diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1ea93bf9..f98d0d4c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -93,6 +93,5 @@ jobs: - name: Check with minimal dependency versions run: | - rustup toolchain add 1.73.0 - # minimal-versions cannot correctly resolve the ssh-key dep on Rust <1.73 - cargo +1.73.0 minimal-versions check --all-features --no-dev-deps + rustup toolchain add 1.75.0 + cargo +1.75.0 minimal-versions check --all-features --no-dev-deps diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..2c63c085 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} diff --git a/Cargo.toml b/Cargo.toml index b5889f69..624e0cdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ digest = "0.10" delegate = "0.13" env_logger = "0.6" futures = "0.3" -home = "=0.5.5" # 0.5.6 changes MSRV +home = "0.5" hmac = "0.12" log = "0.4.11" rand = "0.8" diff --git a/cryptovec/Cargo.toml b/cryptovec/Cargo.toml index 5d919665..5ee6f509 100644 --- a/cryptovec/Cargo.toml +++ b/cryptovec/Cargo.toml @@ -7,7 +7,7 @@ license = "Apache-2.0" name = "russh-cryptovec" repository = "https://github.com/warp-tech/russh" version = "0.48.0" -rust-version = "1.60" +rust-version = "1.75" [dependencies] libc = "0.2" diff --git a/pageant/Cargo.toml b/pageant/Cargo.toml index 12c2510e..2eab0565 100644 --- a/pageant/Cargo.toml +++ b/pageant/Cargo.toml @@ -7,7 +7,7 @@ license = "Apache-2.0" name = "pageant" repository = "https://github.com/warp-tech/russh" version = "0.0.2" -rust-version = "1.65" +rust-version = "1.75" [dependencies] futures.workspace = true diff --git a/russh-config/Cargo.toml b/russh-config/Cargo.toml index 04aa2eb6..e68a3722 100644 --- a/russh-config/Cargo.toml +++ b/russh-config/Cargo.toml @@ -8,7 +8,7 @@ license = "Apache-2.0" name = "russh-config" repository = "https://github.com/warp-tech/russh" version = "0.48.0" -rust-version = "1.65" +rust-version = "1.75" [dependencies] home.workspace = true diff --git a/russh-util/Cargo.toml b/russh-util/Cargo.toml index f746fc41..757606a2 100644 --- a/russh-util/Cargo.toml +++ b/russh-util/Cargo.toml @@ -2,7 +2,7 @@ name = "russh-util" version = "0.48.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.75" description = "Runtime abstraction utilities for russh." documentation = "https://docs.rs/russh-util" homepage = "https://github.com/warp-tech/russh" diff --git a/russh/Cargo.toml b/russh/Cargo.toml index 72d31bd6..70c11033 100644 --- a/russh/Cargo.toml +++ b/russh/Cargo.toml @@ -10,10 +10,11 @@ name = "russh" readme = "../README.md" repository = "https://github.com/warp-tech/russh" version = "0.50.0-beta.11" -rust-version = "1.65" +rust-version = "1.75" [features] default = ["flate2"] +async-trait = ["dep:async-trait"] legacy-ed25519-pkcs8-parser = ["yasna"] # Danger: 3DES cipher is insecure. des = ["dep:des"] @@ -21,7 +22,7 @@ des = ["dep:des"] [dependencies] aes-gcm = "0.10" aes.workspace = true -async-trait.workspace = true +async-trait = { workspace = true, optional = true } bitflags = "2.0" block-padding = { version = "0.3", features = ["std"] } byteorder.workspace = true @@ -119,3 +120,11 @@ tempfile = "3.14.0" [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] russh-sftp = "2.0.5" tokio.workspace = true + +[[example]] +name = "sftp_server" +path = "examples/sftp_server.rs" +required-features = ["async-trait"] + +[package.metadata.docs.rs] +all-features = true diff --git a/russh/examples/client_exec_interactive.rs b/russh/examples/client_exec_interactive.rs index c7477989..2c088bc8 100644 --- a/russh/examples/client_exec_interactive.rs +++ b/russh/examples/client_exec_interactive.rs @@ -9,7 +9,6 @@ use std::sync::Arc; use std::time::Duration; use anyhow::Result; -use async_trait::async_trait; use clap::Parser; use log::info; use russh::keys::*; @@ -65,7 +64,6 @@ struct Client {} // More SSH event handlers // can be defined in this trait // In this example, we're only using Channel, so these aren't needed. -#[async_trait] impl client::Handler for Client { type Error = russh::Error; diff --git a/russh/examples/client_exec_simple.rs b/russh/examples/client_exec_simple.rs index 5405893c..c43f3b2e 100644 --- a/russh/examples/client_exec_simple.rs +++ b/russh/examples/client_exec_simple.rs @@ -8,7 +8,6 @@ use std::sync::Arc; use std::time::Duration; use anyhow::Result; -use async_trait::async_trait; use clap::Parser; use log::info; use russh::keys::*; @@ -57,7 +56,6 @@ struct Client {} // More SSH event handlers // can be defined in this trait // In this example, we're only using Channel, so these aren't needed. -#[async_trait] impl client::Handler for Client { type Error = russh::Error; diff --git a/russh/examples/echoserver.rs b/russh/examples/echoserver.rs index 183d30cf..6123297b 100644 --- a/russh/examples/echoserver.rs +++ b/russh/examples/echoserver.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use std::sync::Arc; -use async_trait::async_trait; use rand_core::OsRng; use russh::keys::{Certificate, *}; use russh::server::{Msg, Server as _, Session}; @@ -64,7 +63,6 @@ impl server::Server for Server { } } -#[async_trait] impl server::Handler for Server { type Error = russh::Error; diff --git a/russh/examples/ratatui_app.rs b/russh/examples/ratatui_app.rs index 5f6ab152..757c976e 100644 --- a/russh/examples/ratatui_app.rs +++ b/russh/examples/ratatui_app.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use std::sync::Arc; -use async_trait::async_trait; use rand_core::OsRng; use ratatui::backend::CrosstermBackend; use ratatui::layout::Rect; @@ -142,7 +141,6 @@ impl Server for AppServer { } } -#[async_trait] impl Handler for AppServer { type Error = anyhow::Error; diff --git a/russh/examples/ratatui_shared_app.rs b/russh/examples/ratatui_shared_app.rs index dffa6fbd..d221c382 100644 --- a/russh/examples/ratatui_shared_app.rs +++ b/russh/examples/ratatui_shared_app.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use std::sync::Arc; -use async_trait::async_trait; use rand_core::OsRng; use ratatui::backend::CrosstermBackend; use ratatui::layout::Rect; @@ -144,7 +143,6 @@ impl Server for AppServer { } } -#[async_trait] impl Handler for AppServer { type Error = anyhow::Error; diff --git a/russh/examples/sftp_client.rs b/russh/examples/sftp_client.rs index 5e29fb79..d10f0dd6 100644 --- a/russh/examples/sftp_client.rs +++ b/russh/examples/sftp_client.rs @@ -1,6 +1,5 @@ use std::sync::Arc; -use async_trait::async_trait; use log::{error, info, LevelFilter}; use russh::keys::*; use russh::*; @@ -10,7 +9,6 @@ use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; struct Client; -#[async_trait] impl client::Handler for Client { type Error = anyhow::Error; diff --git a/russh/examples/sftp_server.rs b/russh/examples/sftp_server.rs index f0076949..0f7d7847 100644 --- a/russh/examples/sftp_server.rs +++ b/russh/examples/sftp_server.rs @@ -3,7 +3,6 @@ use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; -use async_trait::async_trait; use log::{error, info, LevelFilter}; use rand_core::OsRng; use russh::server::{Auth, Msg, Server as _, Session}; @@ -41,7 +40,6 @@ impl SshSession { } } -#[async_trait] impl russh::server::Handler for SshSession { type Error = anyhow::Error; @@ -109,7 +107,7 @@ struct SftpSession { root_dir_read_done: bool, } -#[async_trait] +#[async_trait::async_trait] impl russh_sftp::server::Handler for SftpSession { type Error = StatusCode; diff --git a/russh/examples/test.rs b/russh/examples/test.rs index 9694c9a1..be139da0 100644 --- a/russh/examples/test.rs +++ b/russh/examples/test.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use std::sync::{Arc, Mutex}; -use async_trait::async_trait; use log::debug; use rand_core::OsRng; use russh::keys::*; @@ -47,7 +46,6 @@ impl server::Server for Server { } } -#[async_trait] impl server::Handler for Server { type Error = anyhow::Error; diff --git a/russh/src/auth.rs b/russh/src/auth.rs index 0c1607b1..9636b1e9 100644 --- a/russh/src/auth.rs +++ b/russh/src/auth.rs @@ -13,11 +13,11 @@ // limitations under the License. // +use std::future::Future; use std::ops::Deref; use std::str::FromStr; use std::sync::Arc; -use async_trait::async_trait; use ssh_key::{Certificate, HashAlg, PrivateKey}; use thiserror::Error; use tokio::io::{AsyncRead, AsyncWrite}; @@ -147,16 +147,16 @@ impl AuthResult { } } -#[async_trait] +#[cfg_attr(feature = "async-trait", async_trait::async_trait)] pub trait Signer: Sized { type Error: From; - async fn auth_publickey_sign( + fn auth_publickey_sign( &mut self, key: &ssh_key::PublicKey, hash_alg: Option, to_sign: CryptoVec, - ) -> Result; + ) -> impl Future> + Send; } #[derive(Debug, Error)] @@ -167,21 +167,24 @@ pub enum AgentAuthError { Key(#[from] crate::keys::Error), } -#[async_trait] +#[cfg_attr(feature = "async-trait", async_trait::async_trait)] impl Signer for crate::keys::agent::client::AgentClient { type Error = AgentAuthError; - async fn auth_publickey_sign( + #[allow(clippy::manual_async_fn)] + fn auth_publickey_sign( &mut self, key: &ssh_key::PublicKey, hash_alg: Option, to_sign: CryptoVec, - ) -> Result { - self.sign_request(key, hash_alg, to_sign) - .await - .map_err(Into::into) + ) -> impl Future> { + async move { + self.sign_request(key, hash_alg, to_sign) + .await + .map_err(Into::into) + } } } diff --git a/russh/src/client/mod.rs b/russh/src/client/mod.rs index 9728a82a..8e6945d5 100644 --- a/russh/src/client/mod.rs +++ b/russh/src/client/mod.rs @@ -40,7 +40,6 @@ use std::num::Wrapping; use std::pin::Pin; use std::sync::Arc; -use async_trait::async_trait; use futures::task::{Context, Poll}; use futures::Future; use kex::ClientKex; @@ -1564,8 +1563,9 @@ impl Default for Config { /// You must at the very least implement the `check_server_key` fn. /// The default implementation rejects all keys. /// -/// Note: this is an `async_trait`. Click `[source]` on the right to see actual async function definitions. -#[async_trait] +/// Note: this is an async trait. The trait functions return `impl Future`, +/// and you can simply define them as `async fn` instead. +#[cfg_attr(feature = "async-trait", async_trait::async_trait)] pub trait Handler: Sized + Send { type Error: From + Send + core::fmt::Debug; @@ -1574,95 +1574,95 @@ pub trait Handler: Sized + Send { /// [RFC4252](https://tools.ietf.org/html/rfc4252#section-5.4) for /// more details. #[allow(unused_variables)] - async fn auth_banner( + fn auth_banner( &mut self, banner: &str, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called to check the server's public key. This is a very important /// step to help prevent man-in-the-middle attacks. The default /// implementation rejects all keys. #[allow(unused_variables)] - async fn check_server_key( + fn check_server_key( &mut self, server_public_key: &ssh_key::PublicKey, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } /// Called when the server confirmed our request to open a /// channel. A channel can only be written to after receiving this /// message (this library panics otherwise). #[allow(unused_variables)] - async fn channel_open_confirmation( + fn channel_open_confirmation( &mut self, id: ChannelId, max_packet_size: u32, window_size: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server signals success. #[allow(unused_variables)] - async fn channel_success( + fn channel_success( &mut self, channel: ChannelId, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server signals failure. #[allow(unused_variables)] - async fn channel_failure( + fn channel_failure( &mut self, channel: ChannelId, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server closes a channel. #[allow(unused_variables)] - async fn channel_close( + fn channel_close( &mut self, channel: ChannelId, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server sends EOF to a channel. #[allow(unused_variables)] - async fn channel_eof( + fn channel_eof( &mut self, channel: ChannelId, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server rejected our request to open a channel. #[allow(unused_variables)] - async fn channel_open_failure( + fn channel_open_failure( &mut self, channel: ChannelId, reason: ChannelOpenFailure, description: &str, language: &str, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server opens a channel for a new remote port forwarding connection #[allow(unused_variables)] - async fn server_channel_open_forwarded_tcpip( + fn server_channel_open_forwarded_tcpip( &mut self, channel: Channel, connected_address: &str, @@ -1670,29 +1670,29 @@ pub trait Handler: Sized + Send { originator_address: &str, originator_port: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } // Called when the server opens a channel for a new remote UDS forwarding connection #[allow(unused_variables)] - async fn server_channel_open_forwarded_streamlocal( + fn server_channel_open_forwarded_streamlocal( &mut self, channel: Channel, socket_path: &str, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server opens an agent forwarding channel #[allow(unused_variables)] - async fn server_channel_open_agent_forward( + fn server_channel_open_agent_forward( &mut self, channel: Channel, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server attempts to open a channel of unknown type. It may return `true`, @@ -1700,37 +1700,37 @@ pub trait Handler: Sized + Send { /// [Handler::server_channel_open_unknown] will be called soon after. If it returns `false`, /// the channel will not be created and a rejection message will be sent to the server. #[allow(unused_variables)] - async fn should_accept_unknown_server_channel( + fn should_accept_unknown_server_channel( &mut self, id: ChannelId, channel_type: &str, - ) -> bool { - false + ) -> impl Future + Send { + async { false } } /// Called when the server opens an unknown channel. #[allow(unused_variables)] - async fn server_channel_open_unknown( + fn server_channel_open_unknown( &mut self, channel: Channel, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server opens a session channel. #[allow(unused_variables)] - async fn server_channel_open_session( + fn server_channel_open_session( &mut self, channel: Channel, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server opens a direct tcp/ip channel. #[allow(unused_variables)] - async fn server_channel_open_direct_tcpip( + fn server_channel_open_direct_tcpip( &mut self, channel: Channel, host_to_connect: &str, @@ -1738,20 +1738,20 @@ pub trait Handler: Sized + Send { originator_address: &str, originator_port: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server opens an X11 channel. #[allow(unused_variables)] - async fn server_channel_open_x11( + fn server_channel_open_x11( &mut self, channel: Channel, originator_address: &str, originator_port: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server sends us data. The `extended_code` @@ -1759,13 +1759,13 @@ pub trait Handler: Sized + Send { /// standard output, and `Some(1)` is the standard error. See /// [RFC4254](https://tools.ietf.org/html/rfc4254#section-5.2). #[allow(unused_variables)] - async fn data( + fn data( &mut self, channel: ChannelId, data: &[u8], session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the server sends us data. The `extended_code` @@ -1773,43 +1773,43 @@ pub trait Handler: Sized + Send { /// standard output, and `Some(1)` is the standard error. See /// [RFC4254](https://tools.ietf.org/html/rfc4254#section-5.2). #[allow(unused_variables)] - async fn extended_data( + fn extended_data( &mut self, channel: ChannelId, ext: u32, data: &[u8], session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The server informs this client of whether the client may /// perform control-S/control-Q flow control. See /// [RFC4254](https://tools.ietf.org/html/rfc4254#section-6.8). #[allow(unused_variables)] - async fn xon_xoff( + fn xon_xoff( &mut self, channel: ChannelId, client_can_do: bool, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The remote process has exited, with the given exit status. #[allow(unused_variables)] - async fn exit_status( + fn exit_status( &mut self, channel: ChannelId, exit_status: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The remote process exited upon receiving a signal. #[allow(unused_variables)] - async fn exit_signal( + fn exit_signal( &mut self, channel: ChannelId, signal_name: Sig, @@ -1817,8 +1817,8 @@ pub trait Handler: Sized + Send { error_message: &str, lang_tag: &str, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the network window is adjusted, meaning that we @@ -1827,13 +1827,13 @@ pub trait Handler: Sized + Send { /// `Session::data` before, and it returned less than the /// full amount of data. #[allow(unused_variables)] - async fn window_adjusted( + fn window_adjusted( &mut self, channel: ChannelId, new_size: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when this client adjusts the network window. Return the @@ -1845,27 +1845,31 @@ pub trait Handler: Sized + Send { /// Called when the server signals success. #[allow(unused_variables)] - async fn openssh_ext_host_keys_announced( + fn openssh_ext_host_keys_announced( &mut self, keys: Vec, session: &mut Session, - ) -> Result<(), Self::Error> { - debug!("openssh_ext_hostkeys_announced: {:?}", keys); - Ok(()) + ) -> impl Future> + Send { + async move { + debug!("openssh_ext_hostkeys_announced: {:?}", keys); + Ok(()) + } } /// Called when the server sent a disconnect message /// /// If reason is an Error, this function should re-return the error so the join can also evaluate it #[allow(unused_variables)] - async fn disconnected( + fn disconnected( &mut self, reason: DisconnectReason, - ) -> Result<(), Self::Error> { - debug!("disconnected: {:?}", reason); - match reason { - DisconnectReason::ReceivedDisconnect(_) => Ok(()), - DisconnectReason::Error(e) => Err(e), + ) -> impl Future> + Send { + async { + debug!("disconnected: {:?}", reason); + match reason { + DisconnectReason::ReceivedDisconnect(_) => Ok(()), + DisconnectReason::Error(e) => Err(e), + } } } } diff --git a/russh/src/keys/agent/server.rs b/russh/src/keys/agent/server.rs index bdcedbb1..a3833c51 100644 --- a/russh/src/keys/agent/server.rs +++ b/russh/src/keys/agent/server.rs @@ -3,7 +3,6 @@ use std::marker::Sync; use std::sync::{Arc, RwLock}; use std::time::{Duration, SystemTime}; -use async_trait::async_trait; use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; use futures::future::Future; @@ -44,7 +43,7 @@ pub enum MessageType { Unlock, } -#[async_trait] +#[cfg_attr(feature = "async-trait", async_trait::async_trait)] pub trait Agent: Clone + Send + 'static { fn confirm( self, @@ -53,8 +52,8 @@ pub trait Agent: Clone + Send + 'static { Box::new(futures::future::ready((self, true))) } - async fn confirm_request(&self, _msg: MessageType) -> bool { - true + fn confirm_request(&self, _msg: MessageType) -> impl Future + Send { + async { true } } } @@ -330,7 +329,11 @@ impl + Send; @@ -203,10 +203,12 @@ pub trait Handler: Sized { /// sure rejection happens in time `config.auth_rejection_time`, /// except if this method takes more than that. #[allow(unused_variables)] - async fn auth_none(&mut self, user: &str) -> Result { - Ok(Auth::Reject { - proceed_with_methods: None, - }) + fn auth_none(&mut self, user: &str) -> impl Future> + Send { + async { + Ok(Auth::Reject { + proceed_with_methods: None, + }) + } } /// Check authentication using the "password" method. Russh @@ -214,10 +216,16 @@ pub trait Handler: Sized { /// `config.auth_rejection_time`, except if this method takes more /// than that. #[allow(unused_variables)] - async fn auth_password(&mut self, user: &str, password: &str) -> Result { - Ok(Auth::Reject { - proceed_with_methods: None, - }) + fn auth_password( + &mut self, + user: &str, + password: &str, + ) -> impl Future> + Send { + async { + Ok(Auth::Reject { + proceed_with_methods: None, + }) + } } /// Check authentication using the "publickey" method. This method @@ -228,12 +236,12 @@ pub trait Handler: Sized { /// `config.auth_rejection_time`, except if this method takes more /// time than that. #[allow(unused_variables)] - async fn auth_publickey_offered( + fn auth_publickey_offered( &mut self, user: &str, public_key: &ssh_key::PublicKey, - ) -> Result { - Ok(Auth::Accept) + ) -> impl Future> + Send { + async { Ok(Auth::Accept) } } /// Check authentication using the "publickey" method. This method @@ -243,14 +251,16 @@ pub trait Handler: Sized { /// `config.auth_rejection_time`, except if this method takes more /// time than that. #[allow(unused_variables)] - async fn auth_publickey( + fn auth_publickey( &mut self, user: &str, public_key: &ssh_key::PublicKey, - ) -> Result { - Ok(Auth::Reject { - proceed_with_methods: None, - }) + ) -> impl Future> + Send { + async { + Ok(Auth::Reject { + proceed_with_methods: None, + }) + } } /// Check authentication using an OpenSSH certificate. This method @@ -260,14 +270,16 @@ pub trait Handler: Sized { /// `config.auth_rejection_time`, except if this method takes more /// time than that. #[allow(unused_variables)] - async fn auth_openssh_certificate( + fn auth_openssh_certificate( &mut self, user: &str, certificate: &Certificate, - ) -> Result { - Ok(Auth::Reject { - proceed_with_methods: None, - }) + ) -> impl Future> + Send { + async { + Ok(Auth::Reject { + proceed_with_methods: None, + }) + } } /// Check authentication using the "keyboard-interactive" @@ -275,78 +287,85 @@ pub trait Handler: Sized { /// `config.auth_rejection_time`, except if this method takes more /// than that. #[allow(unused_variables)] - async fn auth_keyboard_interactive( - &mut self, + fn auth_keyboard_interactive<'a>( + &'a mut self, user: &str, submethods: &str, - response: Option>, - ) -> Result { - Ok(Auth::Reject { - proceed_with_methods: None, - }) + response: Option>, + ) -> impl Future> + Send { + async { + Ok(Auth::Reject { + proceed_with_methods: None, + }) + } } /// Called when authentication succeeds for a session. #[allow(unused_variables)] - async fn auth_succeeded(&mut self, session: &mut Session) -> Result<(), Self::Error> { - Ok(()) + fn auth_succeeded( + &mut self, + session: &mut Session, + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when authentication starts but before it is successful. /// Return value is an authentication banner, usually a warning message shown to the client. #[allow(unused_variables)] - async fn authentication_banner(&mut self) -> Result, Self::Error> { - Ok(None) + fn authentication_banner( + &mut self, + ) -> impl Future, Self::Error>> + Send { + async { Ok(None) } } /// Called when the client closes a channel. #[allow(unused_variables)] - async fn channel_close( + fn channel_close( &mut self, channel: ChannelId, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the client sends EOF to a channel. #[allow(unused_variables)] - async fn channel_eof( + fn channel_eof( &mut self, channel: ChannelId, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when a new session channel is created. /// Return value indicates whether the channel request should be granted. #[allow(unused_variables)] - async fn channel_open_session( + fn channel_open_session( &mut self, channel: Channel, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } /// Called when a new X11 channel is created. /// Return value indicates whether the channel request should be granted. #[allow(unused_variables)] - async fn channel_open_x11( + fn channel_open_x11( &mut self, channel: Channel, originator_address: &str, originator_port: u32, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } /// Called when a new TCP/IP is created. /// Return value indicates whether the channel request should be granted. #[allow(unused_variables)] - async fn channel_open_direct_tcpip( + fn channel_open_direct_tcpip( &mut self, channel: Channel, host_to_connect: &str, @@ -354,14 +373,14 @@ pub trait Handler: Sized { originator_address: &str, originator_port: u32, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } /// Called when a new forwarded connection comes in. /// #[allow(unused_variables)] - async fn channel_open_forwarded_tcpip( + fn channel_open_forwarded_tcpip( &mut self, channel: Channel, host_to_connect: &str, @@ -369,34 +388,34 @@ pub trait Handler: Sized { originator_address: &str, originator_port: u32, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } /// Called when the client confirmed our request to open a /// channel. A channel can only be written to after receiving this /// message (this library panics otherwise). #[allow(unused_variables)] - async fn channel_open_confirmation( + fn channel_open_confirmation( &mut self, id: ChannelId, max_packet_size: u32, window_size: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when a data packet is received. A response can be /// written to the `response` argument. #[allow(unused_variables)] - async fn data( + fn data( &mut self, channel: ChannelId, data: &[u8], session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when an extended data packet is received. Code 1 means @@ -404,26 +423,26 @@ pub trait Handler: Sized { /// defined (see /// [RFC4254](https://tools.ietf.org/html/rfc4254#section-5.2)). #[allow(unused_variables)] - async fn extended_data( + fn extended_data( &mut self, channel: ChannelId, code: u32, data: &[u8], session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when the network window is adjusted, meaning that we /// can send more bytes. #[allow(unused_variables)] - async fn window_adjusted( + fn window_adjusted( &mut self, channel: ChannelId, new_size: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Called when this server adjusts the network window. Return the @@ -457,7 +476,7 @@ pub trait Handler: Sized { /// } /// ``` #[allow(unused_variables, clippy::too_many_arguments)] - async fn pty_request( + fn pty_request( &mut self, channel: ChannelId, term: &str, @@ -467,8 +486,8 @@ pub trait Handler: Sized { pix_height: u32, modes: &[(Pty, u32)], session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The client requests an X11 connection. @@ -492,7 +511,7 @@ pub trait Handler: Sized { /// } /// ``` #[allow(unused_variables)] - async fn x11_request( + fn x11_request( &mut self, channel: ChannelId, single_connection: bool, @@ -500,8 +519,8 @@ pub trait Handler: Sized { x11_auth_cookie: &str, x11_screen_number: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The client wants to set the given environment variable. Check @@ -525,14 +544,14 @@ pub trait Handler: Sized { /// } /// ``` #[allow(unused_variables)] - async fn env_request( + fn env_request( &mut self, channel: ChannelId, variable_name: &str, variable_value: &str, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The client requests a shell. @@ -552,12 +571,12 @@ pub trait Handler: Sized { /// } /// ``` #[allow(unused_variables)] - async fn shell_request( + fn shell_request( &mut self, channel: ChannelId, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The client sends a command to execute, to be passed to a @@ -579,13 +598,13 @@ pub trait Handler: Sized { /// } /// ``` #[allow(unused_variables)] - async fn exec_request( + fn exec_request( &mut self, channel: ChannelId, data: &[u8], session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The client asks to start the subsystem with the given name @@ -607,13 +626,13 @@ pub trait Handler: Sized { /// } /// ``` #[allow(unused_variables)] - async fn subsystem_request( + fn subsystem_request( &mut self, channel: ChannelId, name: &str, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The client's pseudo-terminal window size has changed. @@ -637,7 +656,7 @@ pub trait Handler: Sized { /// } /// ``` #[allow(unused_variables)] - async fn window_change_request( + fn window_change_request( &mut self, channel: ChannelId, col_width: u32, @@ -645,8 +664,8 @@ pub trait Handler: Sized { pix_width: u32, pix_height: u32, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// The client requests OpenSSH agent forwarding @@ -666,67 +685,67 @@ pub trait Handler: Sized { /// } /// ``` #[allow(unused_variables)] - async fn agent_request( + fn agent_request( &mut self, channel: ChannelId, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } /// The client is sending a signal (usually to pass to the /// currently running process). #[allow(unused_variables)] - async fn signal( + fn signal( &mut self, channel: ChannelId, signal: Sig, session: &mut Session, - ) -> Result<(), Self::Error> { - Ok(()) + ) -> impl Future> + Send { + async { Ok(()) } } /// Used for reverse-forwarding ports, see /// [RFC4254](https://tools.ietf.org/html/rfc4254#section-7). /// If `port` is 0, you should set it to the allocated port number. #[allow(unused_variables)] - async fn tcpip_forward( + fn tcpip_forward( &mut self, address: &str, port: &mut u32, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } /// Used to stop the reverse-forwarding of a port, see /// [RFC4254](https://tools.ietf.org/html/rfc4254#section-7). #[allow(unused_variables)] - async fn cancel_tcpip_forward( + fn cancel_tcpip_forward( &mut self, address: &str, port: u32, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } #[allow(unused_variables)] - async fn streamlocal_forward( + fn streamlocal_forward( &mut self, socket_path: &str, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } #[allow(unused_variables)] - async fn cancel_streamlocal_forward( + fn cancel_streamlocal_forward( &mut self, socket_path: &str, session: &mut Session, - ) -> Result { - Ok(false) + ) -> impl Future> + Send { + async { Ok(false) } } /// Override when enabling the `diffie-hellman-group-exchange-*` key exchange methods. @@ -742,35 +761,37 @@ pub trait Handler: Sized { /// /// See https://datatracker.ietf.org/doc/html/rfc4419#section-3 #[allow(unused_variables)] - async fn lookup_dh_gex_group( + fn lookup_dh_gex_group( &mut self, gex_params: &GexParams, - ) -> Result, Self::Error> { - let mut best_group = &DH_GROUP14; - - // Find _some_ matching group - for group in BUILTIN_SAFE_DH_GROUPS.iter() { - if group.bit_size() >= gex_params.min_group_size() - && group.bit_size() <= gex_params.max_group_size() - { - best_group = *group; - break; + ) -> impl Future, Self::Error>> + Send { + async { + let mut best_group = &DH_GROUP14; + + // Find _some_ matching group + for group in BUILTIN_SAFE_DH_GROUPS.iter() { + if group.bit_size() >= gex_params.min_group_size() + && group.bit_size() <= gex_params.max_group_size() + { + best_group = *group; + break; + } } - } - // Find _closest_ matching group - for group in BUILTIN_SAFE_DH_GROUPS.iter() { - if group.bit_size() > gex_params.preferred_group_size() { - best_group = *group; - break; + // Find _closest_ matching group + for group in BUILTIN_SAFE_DH_GROUPS.iter() { + if group.bit_size() > gex_params.preferred_group_size() { + best_group = *group; + break; + } } - } - Ok(Some(best_group.clone())) + Ok(Some(best_group.clone())) + } } } -#[async_trait] +#[cfg_attr(feature = "async-trait", async_trait::async_trait)] /// Trait used to create new handlers when clients connect. pub trait Server { /// The type of handlers. @@ -782,78 +803,88 @@ pub trait Server { /// Run a server on a specified `tokio::net::TcpListener`. Useful when dropping /// privileges immediately after socket binding, for example. - async fn run_on_socket( + fn run_on_socket( &mut self, config: Arc, socket: &TcpListener, - ) -> Result<(), std::io::Error> { - if config.maximum_packet_size > 65535 { - error!( - "Maximum packet size ({:?}) should not larger than a TCP packet (65535)", - config.maximum_packet_size - ); - } + ) -> impl Future> + Send + where + Self: Send, + { + async move { + if config.maximum_packet_size > 65535 { + error!( + "Maximum packet size ({:?}) should not larger than a TCP packet (65535)", + config.maximum_packet_size + ); + } - let (error_tx, mut error_rx) = tokio::sync::mpsc::unbounded_channel(); - - loop { - tokio::select! { - accept_result = socket.accept() => { - match accept_result { - Ok((socket, _)) => { - let config = config.clone(); - let handler = self.new_client(socket.peer_addr().ok()); - let error_tx = error_tx.clone(); - - russh_util::runtime::spawn(async move { - if config.nodelay { - if let Err(e) = socket.set_nodelay(true) { - warn!("set_nodelay() failed: {e:?}"); + let (error_tx, mut error_rx) = tokio::sync::mpsc::unbounded_channel(); + + loop { + tokio::select! { + accept_result = socket.accept() => { + match accept_result { + Ok((socket, _)) => { + let config = config.clone(); + let handler = self.new_client(socket.peer_addr().ok()); + let error_tx = error_tx.clone(); + + russh_util::runtime::spawn(async move { + if config.nodelay { + if let Err(e) = socket.set_nodelay(true) { + warn!("set_nodelay() failed: {e:?}"); + } } - } - - let session = match run_stream(config, socket, handler).await { - Ok(s) => s, - Err(e) => { - debug!("Connection setup failed"); - let _ = error_tx.send(e); - return - } - }; - match session.await { - Ok(_) => debug!("Connection closed"), - Err(e) => { - debug!("Connection closed with error"); - let _ = error_tx.send(e); + let session = match run_stream(config, socket, handler).await { + Ok(s) => s, + Err(e) => { + debug!("Connection setup failed"); + let _ = error_tx.send(e); + return + } + }; + + match session.await { + Ok(_) => debug!("Connection closed"), + Err(e) => { + debug!("Connection closed with error"); + let _ = error_tx.send(e); + } } - } - }); + }); + } + + _ => break, } + }, - _ => break, + Some(error) = error_rx.recv() => { + self.handle_session_error(error); } - }, - - Some(error) = error_rx.recv() => { - self.handle_session_error(error); } } - } - Ok(()) + Ok(()) + } } /// Run a server. /// Create a new `Connection` from the server's configuration, a /// stream and a [`Handler`](trait.Handler.html). - async fn run_on_address( + fn run_on_address( &mut self, config: Arc, addrs: A, - ) -> Result<(), std::io::Error> { - let socket = TcpListener::bind(addrs).await?; - self.run_on_socket(config, &socket).await + ) -> impl Future> + Send + where + Self: Send, + { + async move { + let socket = TcpListener::bind(addrs).await?; + self.run_on_socket(config, &socket).await + } } } diff --git a/russh/src/tests.rs b/russh/src/tests.rs index dbe6bbb2..afe08d1d 100644 --- a/russh/src/tests.rs +++ b/russh/src/tests.rs @@ -8,7 +8,6 @@ mod compress { use std::collections::HashMap; use std::sync::{Arc, Mutex}; - use async_trait::async_trait; use keys::PrivateKeyWithHashAlg; use log::debug; use rand_core::OsRng; @@ -90,7 +89,6 @@ mod compress { } } - #[async_trait] impl server::Handler for Server { type Error = super::Error; @@ -127,7 +125,6 @@ mod compress { struct Client {} - #[async_trait] impl client::Handler for Client { type Error = super::Error; @@ -142,7 +139,6 @@ mod compress { } mod channels { - use async_trait::async_trait; use keys::PrivateKeyWithHashAlg; use rand_core::OsRng; use server::Session; @@ -224,7 +220,6 @@ mod channels { #[derive(Debug)] struct Client {} - #[async_trait] impl client::Handler for Client { type Error = crate::Error; @@ -259,7 +254,6 @@ mod channels { } } - #[async_trait] impl server::Handler for ServerHandle { type Error = crate::Error; @@ -306,7 +300,6 @@ mod channels { #[derive(Debug)] struct Client {} - #[async_trait] impl client::Handler for Client { type Error = crate::Error; @@ -332,7 +325,6 @@ mod channels { } } - #[async_trait] impl server::Handler for ServerHandle { type Error = crate::Error; @@ -402,7 +394,6 @@ mod channels { #[derive(Debug)] struct Client {} - #[async_trait] impl client::Handler for Client { type Error = crate::Error; @@ -418,7 +409,6 @@ mod channels { impl ServerHandle {} - #[async_trait] impl server::Handler for ServerHandle { type Error = crate::Error; @@ -479,7 +469,6 @@ mod channels { #[derive(Debug)] struct Client {} - #[async_trait] impl client::Handler for Client { type Error = crate::Error; @@ -505,7 +494,6 @@ mod channels { } } - #[async_trait] impl server::Handler for ServerHandle { type Error = crate::Error; diff --git a/russh/tests/test_backpressure.rs b/russh/tests/test_backpressure.rs index 5c48e1b7..960d53d0 100644 --- a/russh/tests/test_backpressure.rs +++ b/russh/tests/test_backpressure.rs @@ -116,7 +116,6 @@ impl russh::server::Server for Server { } } -#[async_trait::async_trait] impl russh::server::Handler for Server { type Error = anyhow::Error; @@ -149,7 +148,6 @@ impl russh::server::Handler for Server { struct Client; -#[async_trait::async_trait] impl russh::client::Handler for Client { type Error = anyhow::Error; diff --git a/russh/tests/test_data_stream.rs b/russh/tests/test_data_stream.rs index 45fe5c23..f1a75dfc 100644 --- a/russh/tests/test_data_stream.rs +++ b/russh/tests/test_data_stream.rs @@ -114,7 +114,6 @@ impl russh::server::Server for Server { } } -#[async_trait::async_trait] impl russh::server::Handler for Server { type Error = anyhow::Error; @@ -148,7 +147,6 @@ impl russh::server::Handler for Server { struct Client; -#[async_trait::async_trait] impl russh::client::Handler for Client { type Error = anyhow::Error;