pub struct Session { /* private fields */ }
Expand description
A Session represents the state needed to make a connection to a remote host.
You need at least one Session per target host.
A given session can open multiple Channel
s to perform multiple actions
on a given target host.
§Thread Safety
libssh doesn’t allow using anything associated with a given Session
from multiple threads concurrently. These Rust bindings encapsulate
the underlying Session
in an internal mutex, which allows you to
safely operate on the various elements of the session and even move
them to other threads, but you need to be aware that calling methods
on any of those structs will attempt to lock the underlying session,
and this can lead to blocking in surprising situations.
Implementations§
Source§impl Session
impl Session
Sourcepub fn new() -> SshResult<Self>
pub fn new() -> SshResult<Self>
Create a new Session.
Examples found in repository?
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}
Sourcepub fn set_auth_callback<F>(&self, callback: F)
pub fn set_auth_callback<F>(&self, callback: F)
Sets a callback that is used by libssh when it needs to prompt for the passphrase during public key authentication. This is NOT used for password or keyboard interactive authentication. The callback has the signature:
use libssh_rs::SshResult;
fn callback(prompt: &str, echo: bool, verify: bool,
identity: Option<String>) -> SshResult<String> {
unimplemented!()
}
The prompt
parameter is the prompt text to show to the user.
The identity
parameter, if not None, will hold the identity that
is currently being tried by the userauth_public_key_auto
method,
which is helpful to show to the user so that they can input the
correct passphrase.
The echo
parameter, if true
, means that the input entered by
the user should be visible on screen. If false
, it should not be
shown on screen because it is deemed sensitive in some way.
The verify
parameter, if true
, means that the user should be
prompted twice to make sure they entered the same text both times.
The function should return the user’s input as a string, or an
Error
indicating what went wrong.
You can use the get_input
function to satisfy the auth callback:
use libssh_rs::*;
let sess = Session::new().unwrap();
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()))
});
Examples found in repository?
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}
Sourcepub fn enable_accept_agent_forward(&self, enable: bool)
pub fn enable_accept_agent_forward(&self, enable: bool)
Enable or disable creating channels when the remote side requests a new channel for SSH
agent forwarding.
You are supposed to periodically check whether there’s pending channels (already bound to
remote side’s agent client) by using the accept_agent_forward
function.
pub fn accept_agent_forward(&self) -> Option<Channel>
Sourcepub fn new_channel(&self) -> SshResult<Channel>
pub fn new_channel(&self) -> SshResult<Channel>
Create a new channel. Channels are used to handle I/O for commands and forwarded streams.
Examples found in repository?
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}
Sourcepub fn blocking_flush(&self, timeout: Option<Duration>) -> SshResult<()>
pub fn blocking_flush(&self, timeout: Option<Duration>) -> SshResult<()>
Blocking flush of the outgoing buffer.
Sourcepub fn disconnect(&self)
pub fn disconnect(&self)
Disconnect from a session (client or server). The session can then be reused to open a new session.
Sourcepub fn connect(&self) -> SshResult<()>
pub fn connect(&self) -> SshResult<()>
Connect to the configured remote host
Examples found in repository?
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}
Sourcepub fn is_known_server(&self) -> SshResult<KnownHosts>
pub fn is_known_server(&self) -> SshResult<KnownHosts>
Check if the servers public key for the connected session is known. This checks if we already know the public key of the server we want to connect to. This allows to detect if there is a MITM attack going on of if there have been changes on the server we don’t know about.
Examples found in repository?
4fn verify_known_hosts(sess: &Session) -> SshResult<()> {
5 let key = sess
6 .get_server_public_key()?
7 .get_public_key_hash_hexa(PublicKeyHashType::Sha256)?;
8
9 match sess.is_known_server()? {
10 KnownHosts::Ok => Ok(()),
11 KnownHosts::NotFound | KnownHosts::Unknown => {
12 eprintln!("The server is not a known host. Do you trust the host key?");
13 eprintln!("Public key hash: {}", key);
14
15 let input = prompt_stdin("Enter yes to trust the key: ")?;
16 if input == "yes" {
17 sess.update_known_hosts_file()
18 } else {
19 Err(Error::Fatal("untrusted server".to_string()))
20 }
21 }
22 KnownHosts::Changed => {
23 eprintln!("The key for the server has changed. It is now:");
24 eprintln!("{}", key);
25 Err(Error::Fatal("host key changed".to_string()))
26 }
27 KnownHosts::Other => {
28 eprintln!("The host key for this server was not found, but another");
29 eprintln!("type of key exists. An attacker might change the default");
30 eprintln!("server key to confuse your client into thinking the key");
31 eprintln!("does not exist");
32 Err(Error::Fatal("host key has wrong type".to_string()))
33 }
34 }
35}
Sourcepub fn update_known_hosts_file(&self) -> SshResult<()>
pub fn update_known_hosts_file(&self) -> SshResult<()>
Add the current connected server to the user known_hosts file. This adds the currently connected server to the known_hosts file by appending a new line at the end. The global known_hosts file is considered read-only so it is not touched by this function.
Examples found in repository?
4fn verify_known_hosts(sess: &Session) -> SshResult<()> {
5 let key = sess
6 .get_server_public_key()?
7 .get_public_key_hash_hexa(PublicKeyHashType::Sha256)?;
8
9 match sess.is_known_server()? {
10 KnownHosts::Ok => Ok(()),
11 KnownHosts::NotFound | KnownHosts::Unknown => {
12 eprintln!("The server is not a known host. Do you trust the host key?");
13 eprintln!("Public key hash: {}", key);
14
15 let input = prompt_stdin("Enter yes to trust the key: ")?;
16 if input == "yes" {
17 sess.update_known_hosts_file()
18 } else {
19 Err(Error::Fatal("untrusted server".to_string()))
20 }
21 }
22 KnownHosts::Changed => {
23 eprintln!("The key for the server has changed. It is now:");
24 eprintln!("{}", key);
25 Err(Error::Fatal("host key changed".to_string()))
26 }
27 KnownHosts::Other => {
28 eprintln!("The host key for this server was not found, but another");
29 eprintln!("type of key exists. An attacker might change the default");
30 eprintln!("server key to confuse your client into thinking the key");
31 eprintln!("does not exist");
32 Err(Error::Fatal("host key has wrong type".to_string()))
33 }
34 }
35}
Sourcepub fn options_parse_config(&self, file_name: Option<&str>) -> SshResult<()>
pub fn options_parse_config(&self, file_name: Option<&str>) -> SshResult<()>
Parse the ssh config file.
This should be the last call of all options, it may overwrite options
which are already set.
It requires that the SshOption::Hostname
is already set.
if file_name
is None the default ~/.ssh/config
will be used.
Examples found in repository?
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}
Get the issue banner from the server. This is the banner showing a disclaimer to users who log in, typically their right or the fact that they will be monitored.
Gets the server banner. This typically holds the server version information
Sourcepub fn get_user_name(&self) -> SshResult<String>
pub fn get_user_name(&self) -> SshResult<String>
Returns the user name that will be used to authenticate with the remote host
Examples found in repository?
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}
Sourcepub fn get_pubkey(&self) -> SshResult<String>
pub fn get_pubkey(&self) -> SshResult<String>
Returns the public key as string
Sourcepub fn set_option(&self, option: SshOption) -> SshResult<()>
pub fn set_option(&self, option: SshOption) -> SshResult<()>
Configures the session.
You will need to set at least SshOption::Hostname
prior to
connecting, in order for libssh to know where to connect.
Examples found in repository?
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}
Sourcepub fn get_server_public_key(&self) -> SshResult<SshKey>
pub fn get_server_public_key(&self) -> SshResult<SshKey>
This function allows you to get a hash of the public key. You can then print this hash in a human-readable form to the user so that he is able to verify it. It is very important that you verify at some moment that the hash matches a known server. If you don’t do it, cryptography wont help you at making things secure. OpenSSH uses SHA1 to print public key digests.
Examples found in repository?
4fn verify_known_hosts(sess: &Session) -> SshResult<()> {
5 let key = sess
6 .get_server_public_key()?
7 .get_public_key_hash_hexa(PublicKeyHashType::Sha256)?;
8
9 match sess.is_known_server()? {
10 KnownHosts::Ok => Ok(()),
11 KnownHosts::NotFound | KnownHosts::Unknown => {
12 eprintln!("The server is not a known host. Do you trust the host key?");
13 eprintln!("Public key hash: {}", key);
14
15 let input = prompt_stdin("Enter yes to trust the key: ")?;
16 if input == "yes" {
17 sess.update_known_hosts_file()
18 } else {
19 Err(Error::Fatal("untrusted server".to_string()))
20 }
21 }
22 KnownHosts::Changed => {
23 eprintln!("The key for the server has changed. It is now:");
24 eprintln!("{}", key);
25 Err(Error::Fatal("host key changed".to_string()))
26 }
27 KnownHosts::Other => {
28 eprintln!("The host key for this server was not found, but another");
29 eprintln!("type of key exists. An attacker might change the default");
30 eprintln!("server key to confuse your client into thinking the key");
31 eprintln!("does not exist");
32 Err(Error::Fatal("host key has wrong type".to_string()))
33 }
34 }
35}
Sourcepub fn userauth_try_publickey(
&self,
username: Option<&str>,
pubkey: &SshKey,
) -> SshResult<AuthStatus>
pub fn userauth_try_publickey( &self, username: Option<&str>, pubkey: &SshKey, ) -> SshResult<AuthStatus>
Try to authenticate with the given public key.
To avoid unnecessary processing and user interaction, the following
method is provided for querying whether authentication using the
‘pubkey’ would be possible.
On success, you want now to use userauth_publickey.
username
should almost always be None
to use the username as
previously configured via set_option or that
was loaded from the ssh configuration prior to calling
connect, as most ssh server implementations
do not allow changing the username during authentication.
Sourcepub fn userauth_publickey(
&self,
username: Option<&str>,
privkey: &SshKey,
) -> SshResult<AuthStatus>
pub fn userauth_publickey( &self, username: Option<&str>, privkey: &SshKey, ) -> SshResult<AuthStatus>
Authenticate with public/private key or certificate.
username
should almost always be None
to use the username as
previously configured via set_option or that
was loaded from the ssh configuration prior to calling
connect, as most ssh server implementations
do not allow changing the username during authentication.
Sourcepub fn userauth_agent(&self, username: Option<&str>) -> SshResult<AuthStatus>
pub fn userauth_agent(&self, username: Option<&str>) -> SshResult<AuthStatus>
Try to authenticate using an ssh agent.
username
should almost always be None
to use the username as
previously configured via set_option or that
was loaded from the ssh configuration prior to calling
connect, as most ssh server implementations
do not allow changing the username during authentication.
Sourcepub fn userauth_public_key_auto(
&self,
username: Option<&str>,
password: Option<&str>,
) -> SshResult<AuthStatus>
pub fn userauth_public_key_auto( &self, username: Option<&str>, password: Option<&str>, ) -> SshResult<AuthStatus>
Try to automatically authenticate using public key authentication.
This will attempt to use an ssh agent if available, and will then
attempt to use your keys/identities from your ~/.ssh
dir.
username
should almost always be None
to use the username as
previously configured via set_option or that
was loaded from the ssh configuration prior to calling
connect, as most ssh server implementations
do not allow changing the username during authentication.
The password
parameter can be used to pre-fill a password to
unlock the private key(s). Leaving it set to None
will cause
libssh to prompt for the passphrase if you have previously
used set_auth_callback
to configure a callback. If you haven’t set the callback and
a key is password protected, this authentication method will fail.
Examples found in repository?
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}
Sourcepub fn userauth_none(&self, username: Option<&str>) -> SshResult<AuthStatus>
pub fn userauth_none(&self, username: Option<&str>) -> SshResult<AuthStatus>
Try to perform "none"
authentication.
Typically, the server will not allow none
auth to succeed, but it has
the side effect of informing the client which authentication methods
are available, so a full-featured client will call this prior to calling
userauth_list
.
username
should almost always be None
to use the username as
previously configured via set_option or that
was loaded from the ssh configuration prior to calling
connect, as most ssh server implementations
do not allow changing the username during authentication.
Examples found in repository?
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}
Sourcepub fn userauth_list(&self, username: Option<&str>) -> SshResult<AuthMethods>
pub fn userauth_list(&self, username: Option<&str>) -> SshResult<AuthMethods>
Returns the permitted AuthMethods
.
The list is not available until after userauth_none has been called at least once.
The list can change in response to authentication events; for example, after successfully completing pubkey auth, the server may then require keyboard interactive auth to enter a second authentication factor.
username
should almost always be None
to use the username as
previously configured via set_option or that
was loaded from the ssh configuration prior to calling
connect, as most ssh server implementations
do not allow changing the username during authentication.
Examples found in repository?
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}
Sourcepub fn userauth_keyboard_interactive_info(
&self,
) -> SshResult<InteractiveAuthInfo>
pub fn userauth_keyboard_interactive_info( &self, ) -> SshResult<InteractiveAuthInfo>
After userauth_keyboard_interactive
has been called and returned AuthStatus::Info
, this method must be called
to discover the prompts to questions that the server needs answered in order
to authenticate the session.
It is then up to your application to obtain those answers and set them via userauth_keyboard_interactive_set_answers.
Examples found in repository?
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}
Sourcepub fn userauth_keyboard_interactive_set_answers(
&self,
answers: &[String],
) -> SshResult<()>
pub fn userauth_keyboard_interactive_set_answers( &self, answers: &[String], ) -> SshResult<()>
After userauth_keyboard_interactive_info has been called, and your application has produced the answers to the prompts, you must call this method to record those answers.
You will then need to call userauth_keyboard_interactive to present those answers to the server and discover the next stage of authentication.
Examples found in repository?
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}
Sourcepub fn userauth_keyboard_interactive(
&self,
username: Option<&str>,
sub_methods: Option<&str>,
) -> SshResult<AuthStatus>
pub fn userauth_keyboard_interactive( &self, username: Option<&str>, sub_methods: Option<&str>, ) -> SshResult<AuthStatus>
Initiates keyboard-interactive authentication.
This appears similar to, but is not the same as password authentication. You should prefer using keyboard-interactive authentication over password auth.
username
should almost always be None
to use the username as
previously configured via set_option or that
was loaded from the ssh configuration prior to calling
connect, as most ssh server implementations
do not allow changing the username during authentication.
sub_methods
is not documented in the underlying libssh and
should almost always be None
.
If the returned AuthStatus
is Info
, then your application
should use userauth_keyboard_interactive_info
and use the results of that method to prompt the user to answer
the questions sent by the server, then
userauth_keyboard_interactive_set_answers
to record the answers, before again calling this method to
present them to the server and determine the next steps.
Examples found in repository?
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}
Sourcepub fn userauth_password(
&self,
username: Option<&str>,
password: Option<&str>,
) -> SshResult<AuthStatus>
pub fn userauth_password( &self, username: Option<&str>, password: Option<&str>, ) -> SshResult<AuthStatus>
Initiates password based authentication.
This appears similar to, but is not the same as keyboard-interactive authentication. You should prefer using keyboard-interactive authentication over password auth.
username
should almost always be None
to use the username as
previously configured via set_option or that
was loaded from the ssh configuration prior to calling
connect, as most ssh server implementations
do not allow changing the username during authentication.
password
should be a password entered by the user, or otherwise
securely communicated to your application.
Examples found in repository?
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}
Sourcepub fn listen_forward(
&self,
bind_address: Option<&str>,
port: u16,
) -> SshResult<u16>
pub fn listen_forward( &self, bind_address: Option<&str>, port: u16, ) -> SshResult<u16>
Sends the “tcpip-forward” global request to ask the server to begin listening for inbound connections; this is for remote (or reverse) port forwarding.
If bind_address
is None then bind to all interfaces on
the server side. Otherwise, bind only to the specified address.
If port
is 0
then the server will pick a port to bind to,
otherwise, will attempt to use the requested port.
Returns the bound port number.
Later in your program, you will use Session::accept_forward
to
wait for a forwarded connection from the address you specified.
Sourcepub fn accept_forward(&self, timeout: Duration) -> SshResult<(u16, Channel)>
pub fn accept_forward(&self, timeout: Duration) -> SshResult<(u16, Channel)>
Accept a remote forwarded connection.
You must have called Session::listen_forward
previously to set up
remote port forwarding.
Returns a tuple (destination_port, Channel)
.
The destination port is so that you can distinguish between multiple
remote forwards and corresponds to the port returned from listen_forward
.
Sourcepub fn get_poll_state(&self) -> (bool, bool)
pub fn get_poll_state(&self) -> (bool, bool)
Returns a tuple of (read_pending, write_pending)
.
If read_pending
is true, then your OS polling mechanism
should request a wakeup when the socket is readable.
If write_pending
is true, then your OS polling mechanism
should request a wakeup when the socket is writable.
You can use the AsRawFd
or AsRawSocket
trait impl
to obtain the socket descriptor for polling purposes.
Sourcepub fn is_blocking(&self) -> bool
pub fn is_blocking(&self) -> bool
Returns true
if the session is in blocking mode, false
otherwise.
Sourcepub fn set_blocking(&self, blocking: bool)
pub fn set_blocking(&self, blocking: bool)
If blocking == true
then set the session to block mode, otherwise
set it to non-blocking mode.
In non-blocking mode, a number of methods in the objects associated
with the session can return Error::TryAgain
.
Sourcepub fn is_connected(&self) -> bool
pub fn is_connected(&self) -> bool
Returns true
if this session is in the connected state, false
otherwise.
pub fn sftp(&self) -> SshResult<Sftp>
Sourcepub fn send_ignore(&self, data: &[u8]) -> SshResult<()>
pub fn send_ignore(&self, data: &[u8]) -> SshResult<()>
Send a message that should be ignored by the peer