pub fn get_input(
prompt: &str,
default_value: Option<&str>,
echo: bool,
verify: bool,
) -> Option<String>
Expand description
A utility function that will prompt the user for input via the console/tty.
prompt
is the text to show to the user.
default_value
can be used to pre-set the answer, allowing the
user to simply press enter.
echo
, if true
, means to show the user’s answer on the screen
as they type it. If false
, means to conceal it.
verify
, if true
, will ask the user for their input twice in
order to confirm that they provided the same text both times.
This is useful when creating a password and echo == false
.
Examples found in repository?
examples/whoami.rs (line 38)
37fn prompt(prompt: &str, echo: bool) -> SshResult<String> {
38 get_input(prompt, None, echo, false).ok_or_else(|| Error::Fatal("reading password".to_string()))
39}
40
41fn prompt_stdin(prompt: &str) -> SshResult<String> {
42 eprintln!("{}", prompt);
43 let mut input = String::new();
44 let _ = std::io::stdin().read_line(&mut input)?;
45 Ok(input.trim().to_string())
46}
47
48fn authenticate(sess: &Session, user_name: Option<&str>) -> SshResult<()> {
49 match sess.userauth_none(user_name)? {
50 AuthStatus::Success => return Ok(()),
51 _ => {}
52 }
53
54 loop {
55 let auth_methods = sess.userauth_list(user_name)?;
56
57 if auth_methods.contains(AuthMethods::PUBLIC_KEY) {
58 match sess.userauth_public_key_auto(None, None)? {
59 AuthStatus::Success => return Ok(()),
60 _ => {}
61 }
62 }
63
64 if auth_methods.contains(AuthMethods::INTERACTIVE) {
65 loop {
66 match sess.userauth_keyboard_interactive(None, None)? {
67 AuthStatus::Success => return Ok(()),
68 AuthStatus::Info => {
69 let info = sess.userauth_keyboard_interactive_info()?;
70 if !info.instruction.is_empty() {
71 eprintln!("{}", info.instruction);
72 }
73 let mut answers = vec![];
74 for p in &info.prompts {
75 answers.push(prompt(&p.prompt, p.echo)?);
76 }
77 sess.userauth_keyboard_interactive_set_answers(&answers)?;
78
79 continue;
80 }
81 AuthStatus::Denied => {
82 break;
83 }
84 status => {
85 return Err(Error::Fatal(format!(
86 "interactive auth status: {:?}",
87 status
88 )))
89 }
90 }
91 }
92 }
93
94 if auth_methods.contains(AuthMethods::PASSWORD) {
95 let pw = prompt("Password: ", false)?;
96
97 match sess.userauth_password(user_name, Some(&pw))? {
98 AuthStatus::Success => return Ok(()),
99 status => return Err(Error::Fatal(format!("password auth status: {:?}", status))),
100 }
101 }
102
103 return Err(Error::Fatal("unhandled auth case".to_string()));
104 }
105}
106
107fn main() -> SshResult<()> {
108 let sess = Session::new()?;
109 sess.set_auth_callback(|prompt, echo, verify, identity| {
110 let prompt = match identity {
111 Some(ident) => format!("{} ({}): ", prompt, ident),
112 None => prompt.to_string(),
113 };
114 get_input(&prompt, None, echo, verify)
115 .ok_or_else(|| Error::Fatal("reading password".to_string()))
116 });
117
118 sess.set_option(SshOption::Hostname("localhost".to_string()))?;
119 // sess.set_option(SshOption::LogLevel(LogLevel::Packet))?;
120 sess.options_parse_config(None)?;
121 sess.connect()?;
122 eprintln!(
123 "using {} as user name for authentication",
124 sess.get_user_name()?
125 );
126 verify_known_hosts(&sess)?;
127
128 authenticate(&sess, None)?;
129
130 let channel = sess.new_channel()?;
131 channel.open_session()?;
132 channel.request_exec("whoami")?;
133 channel.send_eof()?;
134
135 let mut stdout = String::new();
136 channel.stdout().read_to_string(&mut stdout)?;
137
138 eprintln!("whoami -> {}", stdout);
139
140 let res = channel.get_exit_status();
141 eprintln!("exit status: {:?}", res);
142
143 Ok(())
144}