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)
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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
fn prompt(prompt: &str, echo: bool) -> SshResult<String> {
get_input(prompt, None, echo, false).ok_or_else(|| Error::Fatal("reading password".to_string()))
}
fn prompt_stdin(prompt: &str) -> SshResult<String> {
eprintln!("{}", prompt);
let mut input = String::new();
let _ = std::io::stdin().read_line(&mut input)?;
Ok(input.trim().to_string())
}
fn authenticate(sess: &Session, user_name: Option<&str>) -> SshResult<()> {
match sess.userauth_none(user_name)? {
AuthStatus::Success => return Ok(()),
_ => {}
}
loop {
let auth_methods = sess.userauth_list(user_name)?;
if auth_methods.contains(AuthMethods::PUBLIC_KEY) {
match sess.userauth_public_key_auto(None, None)? {
AuthStatus::Success => return Ok(()),
_ => {}
}
}
if auth_methods.contains(AuthMethods::INTERACTIVE) {
loop {
match sess.userauth_keyboard_interactive(None, None)? {
AuthStatus::Success => return Ok(()),
AuthStatus::Info => {
let info = sess.userauth_keyboard_interactive_info()?;
if !info.instruction.is_empty() {
eprintln!("{}", info.instruction);
}
let mut answers = vec![];
for p in &info.prompts {
answers.push(prompt(&p.prompt, p.echo)?);
}
sess.userauth_keyboard_interactive_set_answers(&answers)?;
continue;
}
AuthStatus::Denied => {
break;
}
status => {
return Err(Error::Fatal(format!(
"interactive auth status: {:?}",
status
)))
}
}
}
}
if auth_methods.contains(AuthMethods::PASSWORD) {
let pw = prompt("Password: ", false)?;
match sess.userauth_password(user_name, Some(&pw))? {
AuthStatus::Success => return Ok(()),
status => return Err(Error::Fatal(format!("password auth status: {:?}", status))),
}
}
return Err(Error::Fatal("unhandled auth case".to_string()));
}
}
fn main() -> SshResult<()> {
let sess = Session::new()?;
sess.set_auth_callback(|prompt, echo, verify, identity| {
let prompt = match identity {
Some(ident) => format!("{} ({}): ", prompt, ident),
None => prompt.to_string(),
};
get_input(&prompt, None, echo, verify)
.ok_or_else(|| Error::Fatal("reading password".to_string()))
});
sess.set_option(SshOption::Hostname("localhost".to_string()))?;
// sess.set_option(SshOption::LogLevel(LogLevel::Packet))?;
sess.options_parse_config(None)?;
sess.connect()?;
eprintln!(
"using {} as user name for authentication",
sess.get_user_name()?
);
verify_known_hosts(&sess)?;
authenticate(&sess, None)?;
let channel = sess.new_channel()?;
channel.open_session()?;
channel.request_exec("whoami")?;
channel.send_eof()?;
let mut stdout = String::new();
channel.stdout().read_to_string(&mut stdout)?;
eprintln!("whoami -> {}", stdout);
let res = channel.get_exit_status();
eprintln!("exit status: {:?}", res);
Ok(())
}