Struct Session

Source
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 Channels 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

Source

pub fn new() -> SshResult<Self>

Create a new Session.

Examples found in repository?
examples/whoami.rs (line 108)
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}
Source

pub fn set_auth_callback<F>(&self, callback: F)
where F: FnMut(&str, bool, bool, Option<String>) -> SshResult<String> + 'static,

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?
examples/whoami.rs (lines 109-116)
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}
Source

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.

Source

pub fn accept_agent_forward(&self) -> Option<Channel>

Source

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?
examples/whoami.rs (line 130)
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}
Source

pub fn blocking_flush(&self, timeout: Option<Duration>) -> SshResult<()>

Blocking flush of the outgoing buffer.

Source

pub fn disconnect(&self)

Disconnect from a session (client or server). The session can then be reused to open a new session.

Source

pub fn connect(&self) -> SshResult<()>

Connect to the configured remote host

Examples found in repository?
examples/whoami.rs (line 121)
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}
Source

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?
examples/whoami.rs (line 9)
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}
Source

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?
examples/whoami.rs (line 17)
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}
Source

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?
examples/whoami.rs (line 120)
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}
Source

pub fn get_issue_banner(&self) -> SshResult<String>

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.

Source

pub fn get_server_banner(&self) -> SshResult<String>

Gets the server banner. This typically holds the server version information

Source

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?
examples/whoami.rs (line 124)
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}
Source

pub fn get_pubkey(&self) -> SshResult<String>

Returns the public key as string

Source

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?
examples/whoami.rs (line 118)
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}
Source

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?
examples/whoami.rs (line 6)
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}
Source

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.

Source

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.

Source

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.

Source

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?
examples/whoami.rs (line 58)
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}
Source

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?
examples/whoami.rs (line 49)
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}
Source

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?
examples/whoami.rs (line 55)
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}
Source

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?
examples/whoami.rs (line 69)
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}
Source

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?
examples/whoami.rs (line 77)
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}
Source

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?
examples/whoami.rs (line 66)
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}
Source

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?
examples/whoami.rs (line 97)
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}
Source

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.

Source

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.

Source

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.

Source

pub fn is_blocking(&self) -> bool

Returns true if the session is in blocking mode, false otherwise.

Source

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.

Source

pub fn is_connected(&self) -> bool

Returns true if this session is in the connected state, false otherwise.

Source

pub fn sftp(&self) -> SshResult<Sftp>

Source

pub fn send_ignore(&self, data: &[u8]) -> SshResult<()>

Send a message that should be ignored by the peer

Trait Implementations§

Source§

impl AsRawFd for Session

Source§

fn as_raw_fd(&self) -> RawSocket

Extracts the raw file descriptor. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.