1 // Copyright 2016 Pierre-Étienne Meunier 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 16 //! Server and client SSH asynchronous library, based on tokio/futures. 17 //! 18 //! The normal way to use this library, both for clients and for 19 //! servers, is by creating *handlers*, i.e. types that implement 20 //! `client::Handler` for clients and `server::Handler` for 21 //! servers. 22 //! 23 //! # Writing servers 24 //! 25 //! In the specific case of servers, a server must implement 26 //! `server::Server`, a trait for creating new `server::Handler`. The 27 //! main type to look at in the `server` module is `Session` (and 28 //! `Config`, of course). 29 //! 30 //! Here is an example server, which forwards input from each client 31 //! to all other clients: 32 //! 33 //! ``` 34 //! extern crate thrussh; 35 //! extern crate thrussh_keys; 36 //! extern crate futures; 37 //! extern crate tokio; 38 //! use std::sync::{Mutex, Arc}; 39 //! use thrussh::*; 40 //! use thrussh::server::{Auth, Session}; 41 //! use thrussh_keys::*; 42 //! use std::collections::HashMap; 43 //! use futures::Future; 44 //! 45 //! #[tokio::main] 46 //! async fn main() { 47 //! let client_key = thrussh_keys::key::KeyPair::generate_ed25519().unwrap(); 48 //! let client_pubkey = Arc::new(client_key.clone_public_key()); 49 //! let mut config = thrussh::server::Config::default(); 50 //! config.connection_timeout = Some(std::time::Duration::from_secs(3)); 51 //! config.auth_rejection_time = std::time::Duration::from_secs(3); 52 //! config.keys.push(thrussh_keys::key::KeyPair::generate_ed25519().unwrap()); 53 //! let config = Arc::new(config); 54 //! let sh = Server{ 55 //! client_pubkey, 56 //! clients: Arc::new(Mutex::new(HashMap::new())), 57 //! id: 0 58 //! }; 59 //! tokio::time::timeout( 60 //! std::time::Duration::from_secs(1), 61 //! thrussh::server::run(config, "0.0.0.0:2222", sh) 62 //! ).await.unwrap_or(Ok(())); 63 //! } 64 //! 65 //! #[derive(Clone)] 66 //! struct Server { 67 //! client_pubkey: Arc<thrussh_keys::key::PublicKey>, 68 //! clients: Arc<Mutex<HashMap<(usize, ChannelId), thrussh::server::Handle>>>, 69 //! id: usize, 70 //! } 71 //! 72 //! impl server::Server for Server { 73 //! type Handler = Self; 74 //! fn new(&mut self, _: Option<std::net::SocketAddr>) -> Self { 75 //! let s = self.clone(); 76 //! self.id += 1; 77 //! s 78 //! } 79 //! } 80 //! 81 //! impl server::Handler for Server { 82 //! type Error = anyhow::Error; 83 //! type FutureAuth = futures::future::Ready<Result<(Self, server::Auth), anyhow::Error>>; 84 //! type FutureUnit = futures::future::Ready<Result<(Self, Session), anyhow::Error>>; 85 //! type FutureBool = futures::future::Ready<Result<(Self, Session, bool), anyhow::Error>>; 86 //! 87 //! fn finished_auth(mut self, auth: Auth) -> Self::FutureAuth { 88 //! futures::future::ready(Ok((self, auth))) 89 //! } 90 //! fn finished_bool(self, b: bool, s: Session) -> Self::FutureBool { 91 //! futures::future::ready(Ok((self, s, b))) 92 //! } 93 //! fn finished(self, s: Session) -> Self::FutureUnit { 94 //! futures::future::ready(Ok((self, s))) 95 //! } 96 //! fn channel_open_session(self, channel: ChannelId, session: Session) -> Self::FutureUnit { 97 //! { 98 //! let mut clients = self.clients.lock().unwrap(); 99 //! clients.insert((self.id, channel), session.handle()); 100 //! } 101 //! self.finished(session) 102 //! } 103 //! fn auth_publickey(self, _: &str, _: &key::PublicKey) -> Self::FutureAuth { 104 //! self.finished_auth(server::Auth::Accept) 105 //! } 106 //! fn data(self, channel: ChannelId, data: &[u8], mut session: Session) -> Self::FutureUnit { 107 //! { 108 //! let mut clients = self.clients.lock().unwrap(); 109 //! for ((id, channel), ref mut s) in clients.iter_mut() { 110 //! if *id != self.id { 111 //! s.data(*channel, CryptoVec::from_slice(data)); 112 //! } 113 //! } 114 //! } 115 //! session.data(channel, CryptoVec::from_slice(data)); 116 //! self.finished(session) 117 //! } 118 //! } 119 //! ``` 120 //! 121 //! Note the call to `session.handle()`, which allows to keep a handle 122 //! to a client outside the event loop. This feature is internally 123 //! implemented using `futures::sync::mpsc` channels. 124 //! 125 //! Note that this is just a toy server. In particular: 126 //! 127 //! - It doesn't handle errors when `s.data` returns an error, 128 //! i.e. when the client has disappeared 129 //! 130 //! - Each new connection increments the `id` field. Even though we 131 //! would need a lot of connections per second for a very long time to 132 //! saturate it, there are probably better ways to handle this to 133 //! avoid collisions. 134 //! 135 //! 136 //! # Implementing clients 137 //! 138 //! Maybe surprisingly, the data types used by Thrussh to implement 139 //! clients are relatively more complicated than for servers. This is 140 //! mostly related to the fact that clients are generally used both in 141 //! a synchronous way (in the case of SSH, we can think of sending a 142 //! shell command), and asynchronously (because the server may send 143 //! unsollicited messages), and hence need to handle multiple 144 //! interfaces. 145 //! 146 //! The important types in the `client` module are `Session` and 147 //! `Connection`. A `Connection` is typically used to send commands to 148 //! the server and wait for responses, and contains a `Session`. The 149 //! `Session` is passed to the `Handler` when the client receives 150 //! data. 151 //! 152 //! ``` 153 //!extern crate thrussh; 154 //!extern crate thrussh_keys; 155 //!extern crate futures; 156 //!extern crate tokio; 157 //!extern crate env_logger; 158 //!use std::sync::Arc; 159 //!use thrussh::*; 160 //!use thrussh::server::{Auth, Session}; 161 //!use thrussh_keys::*; 162 //!use futures::Future; 163 //!use std::io::Read; 164 //! 165 //! 166 //!struct Client { 167 //!} 168 //! 169 //!impl client::Handler for Client { 170 //! type Error = anyhow::Error; 171 //! type FutureUnit = futures::future::Ready<Result<(Self, client::Session), anyhow::Error>>; 172 //! type FutureBool = futures::future::Ready<Result<(Self, bool), anyhow::Error>>; 173 //! 174 //! fn finished_bool(self, b: bool) -> Self::FutureBool { 175 //! futures::future::ready(Ok((self, b))) 176 //! } 177 //! fn finished(self, session: client::Session) -> Self::FutureUnit { 178 //! futures::future::ready(Ok((self, session))) 179 //! } 180 //! fn check_server_key(self, server_public_key: &key::PublicKey) -> Self::FutureBool { 181 //! println!("check_server_key: {:?}", server_public_key); 182 //! self.finished_bool(true) 183 //! } 184 //! fn channel_open_confirmation(self, channel: ChannelId, max_packet_size: u32, window_size: u32, session: client::Session) -> Self::FutureUnit { 185 //! println!("channel_open_confirmation: {:?}", channel); 186 //! self.finished(session) 187 //! } 188 //! fn data(self, channel: ChannelId, data: &[u8], session: client::Session) -> Self::FutureUnit { 189 //! println!("data on channel {:?}: {:?}", channel, std::str::from_utf8(data)); 190 //! self.finished(session) 191 //! } 192 //!} 193 //! 194 //! #[tokio::main] 195 //! async fn main() { 196 //! let config = thrussh::client::Config::default(); 197 //! let config = Arc::new(config); 198 //! let sh = Client{}; 199 //! 200 //! let key = thrussh_keys::key::KeyPair::generate_ed25519().unwrap(); 201 //! let mut agent = thrussh_keys::agent::client::AgentClient::connect_env().await.unwrap(); 202 //! agent.add_identity(&key, &[]).await.unwrap(); 203 //! let mut session = thrussh::client::connect(config, "localhost:22", sh).await.unwrap(); 204 //! if session.authenticate_future(std::env::var("USER").unwrap(), key.clone_public_key(), agent).await.1.unwrap() { 205 //! let mut channel = session.channel_open_session().await.unwrap(); 206 //! channel.data(&b"Hello, world!"[..]).await.unwrap(); 207 //! if let Some(msg) = channel.wait().await { 208 //! println!("{:?}", msg) 209 //! } 210 //! } 211 //! } 212 //! ``` 213 //! # Using non-socket IO / writing tunnels 214 //! 215 //! The easy way to implement SSH tunnels, like `ProxyCommand` for 216 //! OpenSSH, is to use the `thrussh-config` crate, and use the 217 //! `Stream::tcp_connect` or `Stream::proxy_command` methods of that 218 //! crate. That crate is a very lightweight layer above Thrussh, only 219 //! implementing for external commands the traits used for sockets. 220 //! 221 //! # The SSH protocol 222 //! 223 //! If we exclude the key exchange and authentication phases, handled 224 //! by Thrussh behind the scenes, the rest of the SSH protocol is 225 //! relatively simple: clients and servers open *channels*, which are 226 //! just integers used to handle multiple requests in parallel in a 227 //! single connection. Once a client has obtained a `ChannelId` by 228 //! calling one the many `channel_open_…` methods of 229 //! `client::Connection`, the client may send exec requests and data 230 //! to the server. 231 //! 232 //! A simple client just asking the server to run one command will 233 //! usually start by calling 234 //! `client::Connection::channel_open_session`, then 235 //! `client::Connection::exec`, then possibly 236 //! `client::Connection::data` a number of times to send data to the 237 //! command's standard input, and finally `Connection::channel_eof` 238 //! and `Connection::channel_close`. 239 //! 240 //! # Design principles 241 //! 242 //! The main goal of this library is conciseness, and reduced size and 243 //! readability of the library's code. Moreover, this library is split 244 //! between Thrussh, which implements the main logic of SSH clients 245 //! and servers, and Thrussh-keys, which implements calls to 246 //! cryptographic primitives. 247 //! 248 //! One non-goal is to implement all possible cryptographic algorithms 249 //! published since the initial release of SSH. Technical debt is 250 //! easily acquired, and we would need a very strong reason to go 251 //! against this principle. If you are designing a system from 252 //! scratch, we urge you to consider recent cryptographic primitives 253 //! such as Ed25519 for public key cryptography, and Chacha20-Poly1305 254 //! for symmetric cryptography and MAC. 255 //! 256 //! # Internal details of the event loop 257 //! 258 //! It might seem a little odd that the read/write methods for server 259 //! or client sessions often return neither `Result` nor 260 //! `Future`. This is because the data sent to the remote side is 261 //! buffered, because it needs to be encrypted first, and encryption 262 //! works on buffers, and for many algorithms, not in place. 263 //! 264 //! Hence, the event loop keeps waiting for incoming packets, reacts 265 //! to them by calling the provided `Handler`, which fills some 266 //! buffers. If the buffers are non-empty, the event loop then sends 267 //! them to the socket, flushes the socket, empties the buffers and 268 //! starts again. In the special case of the server, unsollicited 269 //! messages sent through a `server::Handle` are processed when there 270 //! is no incoming packet to read. 271 //! 272 #[macro_use] 273 extern crate bitflags; 274 #[macro_use] 275 extern crate log; 276 extern crate thrussh_libsodium as sodium; 277 #[macro_use] 278 extern crate thiserror; 279 280 pub use cryptovec::CryptoVec; 281 mod auth; 282 mod cipher; 283 mod compression; 284 mod kex; 285 mod key; 286 mod msg; 287 mod negotiation; 288 mod ssh_read; 289 mod sshbuffer; 290 291 pub use negotiation::{Named, Preferred}; 292 mod pty; 293 pub use pty::Pty; 294 295 macro_rules! push_packet { 296 ( $buffer:expr, $x:expr ) => {{ 297 use byteorder::{BigEndian, ByteOrder}; 298 let i0 = $buffer.len(); 299 $buffer.extend(b"\0\0\0\0"); 300 let x = $x; 301 let i1 = $buffer.len(); 302 use std::ops::DerefMut; 303 let buf = $buffer.deref_mut(); 304 BigEndian::write_u32(&mut buf[i0..], (i1 - i0 - 4) as u32); 305 x 306 }}; 307 } 308 309 type Sha256Hash = generic_array::GenericArray<u8, <sha2::Sha256 as digest::FixedOutputDirty>::OutputSize>; 310 311 mod session; 312 313 /// Server side of this library. 314 pub mod server; 315 316 /// Client side of this library. 317 pub mod client; 318 319 #[derive(Debug, Error)] 320 pub enum Error { 321 /// The key file could not be parsed. 322 #[error("Could not read key")] 323 CouldNotReadKey, 324 325 /// Unspecified problem with the beginning of key exchange. 326 #[error("Key exchange init failed")] 327 KexInit, 328 329 /// No common key exchange algorithm. 330 #[error("No common key exchange algorithm")] 331 NoCommonKexAlgo, 332 333 /// No common signature algorithm. 334 #[error("No common key algorithm")] 335 NoCommonKeyAlgo, 336 337 /// No common cipher. 338 #[error("No common key cipher")] 339 NoCommonCipher, 340 341 /// No common compression algorithm. 342 #[error("No common compression algorithm")] 343 NoCommonCompression, 344 345 /// Invalid SSH version string. 346 #[error("invalid SSH version string")] 347 Version, 348 349 /// Error during key exchange. 350 #[error("Key exchange failed")] 351 Kex, 352 353 /// Invalid packet authentication code. 354 #[error("Wrong packet authentication code")] 355 PacketAuth, 356 357 /// The protocol is in an inconsistent state. 358 #[error("Inconsistent state of the protocol")] 359 Inconsistent, 360 361 /// The client is not yet authenticated. 362 #[error("Not yet authenticated")] 363 NotAuthenticated, 364 365 /// Index out of bounds. 366 #[error("Index out of bounds")] 367 IndexOutOfBounds, 368 369 /// Unknown server key. 370 #[error("Unknown server key")] 371 UnknownKey, 372 373 /// The server provided a wrong signature. 374 #[error("Wrong server signature")] 375 WrongServerSig, 376 377 /// Message received/sent on unopened channel. 378 #[error("Channel not open")] 379 WrongChannel, 380 381 /// Disconnected 382 #[error("Disconnected")] 383 Disconnect, 384 385 /// No home directory found when trying to learn new host key. 386 #[error("No home directory when saving host key")] 387 NoHomeDir, 388 389 /// Remote key changed, this could mean a man-in-the-middle attack 390 /// is being performed on the connection. 391 #[error("Key changed, line {}", line)] 392 KeyChanged { line: usize }, 393 394 /// Connection closed by the remote side. 395 #[error("Connection closed by the remote side")] 396 HUP, 397 398 /// Connection timeout. 399 #[error("Connection timeout")] 400 ConnectionTimeout, 401 402 /// Missing authentication method. 403 #[error("No authentication method")] 404 NoAuthMethod, 405 406 #[error("Channel send error")] 407 SendError, 408 409 #[error("Pending buffer limit reached")] 410 Pending, 411 412 #[error(transparent)] 413 Keys(#[from] thrussh_keys::Error), 414 415 #[error(transparent)] 416 IO(#[from] std::io::Error), 417 418 #[error(transparent)] 419 Utf8(#[from] std::str::Utf8Error), 420 421 #[error(transparent)] 422 Compress(#[from] flate2::CompressError), 423 424 #[error(transparent)] 425 Decompress(#[from] flate2::DecompressError), 426 427 #[error(transparent)] 428 Join(#[from] tokio::task::JoinError), 429 430 #[error(transparent)] 431 #[cfg(feature = "openssl")] 432 Openssl(#[from] openssl::error::ErrorStack), 433 434 #[error(transparent)] 435 Elapsed(#[from] tokio::time::error::Elapsed), 436 } 437 438 #[derive(Debug, Error)] 439 #[error("Could not reach the event loop")] 440 pub struct SendError {} 441 442 /// Since handlers are large, their associated future types must implement this trait to provide reasonable default implementations (basically, rejecting all requests). 443 pub trait FromFinished<T>: futures::Future<Output = Result<T, Error>> { 444 /// Turns type `T` into `Self`, a future yielding `T`. finished(t: T) -> Self445 fn finished(t: T) -> Self; 446 } 447 448 impl<T> FromFinished<T> for futures::future::Ready<Result<T, Error>> { finished(t: T) -> Self449 fn finished(t: T) -> Self { 450 futures::future::ready(Ok(t)) 451 } 452 } 453 454 impl<T: 'static> FromFinished<T> for Box<dyn futures::Future<Output = Result<T, Error>> + Unpin> { finished(t: T) -> Self455 fn finished(t: T) -> Self { 456 Box::new(futures::future::ready(Ok(t))) 457 } 458 } 459 460 // mod mac; 461 // use mac::*; 462 // mod compression; 463 464 /// The number of bytes read/written, and the number of seconds before a key re-exchange is requested. 465 #[derive(Debug, Clone)] 466 pub struct Limits { 467 pub rekey_write_limit: usize, 468 pub rekey_read_limit: usize, 469 pub rekey_time_limit: std::time::Duration, 470 } 471 472 impl Limits { 473 /// Create a new `Limits`, checking that the given bounds cannot lead to nonce reuse. new(write_limit: usize, read_limit: usize, time_limit: std::time::Duration) -> Limits474 pub fn new(write_limit: usize, read_limit: usize, time_limit: std::time::Duration) -> Limits { 475 assert!(write_limit <= 1 << 30 && read_limit <= 1 << 30); 476 Limits { 477 rekey_write_limit: write_limit, 478 rekey_read_limit: read_limit, 479 rekey_time_limit: time_limit, 480 } 481 } 482 } 483 484 impl Default for Limits { default() -> Self485 fn default() -> Self { 486 // Following the recommendations of 487 // https://tools.ietf.org/html/rfc4253#section-9 488 Limits { 489 rekey_write_limit: 1 << 30, // 1 Gb 490 rekey_read_limit: 1 << 30, // 1 Gb 491 rekey_time_limit: std::time::Duration::from_secs(3600), 492 } 493 } 494 } 495 496 pub use auth::{AgentAuthError, MethodSet, Signer}; 497 498 /// A reason for disconnection. 499 #[allow(missing_docs)] // This should be relatively self-explanatory. 500 #[derive(Debug)] 501 pub enum Disconnect { 502 HostNotAllowedToConnect = 1, 503 ProtocolError = 2, 504 KeyExchangeFailed = 3, 505 #[doc(hidden)] 506 Reserved = 4, 507 MACError = 5, 508 CompressionError = 6, 509 ServiceNotAvailable = 7, 510 ProtocolVersionNotSupported = 8, 511 HostKeyNotVerifiable = 9, 512 ConnectionLost = 10, 513 ByApplication = 11, 514 TooManyConnections = 12, 515 AuthCancelledByUser = 13, 516 NoMoreAuthMethodsAvailable = 14, 517 IllegalUserName = 15, 518 } 519 520 /// The type of signals that can be sent to a remote process. If you 521 /// plan to use custom signals, read [the 522 /// RFC](https://tools.ietf.org/html/rfc4254#section-6.10) to 523 /// understand the encoding. 524 #[allow(missing_docs)] 525 // This should be relatively self-explanatory. 526 #[derive(Debug, Clone)] 527 pub enum Sig { 528 ABRT, 529 ALRM, 530 FPE, 531 HUP, 532 ILL, 533 INT, 534 KILL, 535 PIPE, 536 QUIT, 537 SEGV, 538 TERM, 539 USR1, 540 Custom(String), 541 } 542 543 impl Sig { name(&self) -> &str544 fn name(&self) -> &str { 545 match *self { 546 Sig::ABRT => "ABRT", 547 Sig::ALRM => "ALRM", 548 Sig::FPE => "FPE", 549 Sig::HUP => "HUP", 550 Sig::ILL => "ILL", 551 Sig::INT => "INT", 552 Sig::KILL => "KILL", 553 Sig::PIPE => "PIPE", 554 Sig::QUIT => "QUIT", 555 Sig::SEGV => "SEGV", 556 Sig::TERM => "TERM", 557 Sig::USR1 => "USR1", 558 Sig::Custom(ref c) => c, 559 } 560 } from_name(name: &[u8]) -> Result<Sig, Error>561 fn from_name(name: &[u8]) -> Result<Sig, Error> { 562 match name { 563 b"ABRT" => Ok(Sig::ABRT), 564 b"ALRM" => Ok(Sig::ALRM), 565 b"FPE" => Ok(Sig::FPE), 566 b"HUP" => Ok(Sig::HUP), 567 b"ILL" => Ok(Sig::ILL), 568 b"INT" => Ok(Sig::INT), 569 b"KILL" => Ok(Sig::KILL), 570 b"PIPE" => Ok(Sig::PIPE), 571 b"QUIT" => Ok(Sig::QUIT), 572 b"SEGV" => Ok(Sig::SEGV), 573 b"TERM" => Ok(Sig::TERM), 574 b"USR1" => Ok(Sig::USR1), 575 x => Ok(Sig::Custom(std::str::from_utf8(x)?.to_string())), 576 } 577 } 578 } 579 580 /// Reason for not being able to open a channel. 581 #[derive(Debug, Copy, Clone, PartialEq)] 582 #[allow(missing_docs)] 583 pub enum ChannelOpenFailure { 584 AdministrativelyProhibited = 1, 585 ConnectFailed = 2, 586 UnknownChannelType = 3, 587 ResourceShortage = 4, 588 } 589 590 impl ChannelOpenFailure { from_u32(x: u32) -> Option<ChannelOpenFailure>591 fn from_u32(x: u32) -> Option<ChannelOpenFailure> { 592 match x { 593 1 => Some(ChannelOpenFailure::AdministrativelyProhibited), 594 2 => Some(ChannelOpenFailure::ConnectFailed), 595 3 => Some(ChannelOpenFailure::UnknownChannelType), 596 4 => Some(ChannelOpenFailure::ResourceShortage), 597 _ => None, 598 } 599 } 600 } 601 602 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 603 /// The identifier of a channel. 604 pub struct ChannelId(u32); 605 606 /// The parameters of a channel. 607 #[derive(Debug)] 608 pub(crate) struct Channel { 609 recipient_channel: u32, 610 sender_channel: ChannelId, 611 recipient_window_size: u32, 612 sender_window_size: u32, 613 recipient_maximum_packet_size: u32, 614 sender_maximum_packet_size: u32, 615 /// Has the other side confirmed the channel? 616 pub confirmed: bool, 617 wants_reply: bool, 618 pending_data: std::collections::VecDeque<(CryptoVec, Option<u32>, usize)>, 619 } 620 621 #[derive(Debug)] 622 pub enum ChannelMsg { 623 Data { 624 data: CryptoVec, 625 }, 626 ExtendedData { 627 data: CryptoVec, 628 ext: u32, 629 }, 630 Eof, 631 Close, 632 XonXoff { 633 client_can_do: bool, 634 }, 635 ExitStatus { 636 exit_status: u32, 637 }, 638 ExitSignal { 639 signal_name: Sig, 640 core_dumped: bool, 641 error_message: String, 642 lang_tag: String, 643 }, 644 WindowAdjusted { 645 new_size: u32, 646 }, 647 Success, 648 } 649 650 #[cfg(test)] 651 mod test_compress { 652 use super::server::{Auth, Server as _, Session}; 653 use super::*; 654 use std::collections::HashMap; 655 use std::sync::{Arc, Mutex}; 656 657 #[tokio::test] compress_local_test()658 async fn compress_local_test() { 659 let _ = env_logger::try_init(); 660 661 let client_key = thrussh_keys::key::KeyPair::generate_ed25519().unwrap(); 662 let client_pubkey = Arc::new(client_key.clone_public_key()); 663 let mut config = server::Config::default(); 664 config.preferred = Preferred::COMPRESSED; 665 config.connection_timeout = None; // Some(std::time::Duration::from_secs(3)); 666 config.auth_rejection_time = std::time::Duration::from_secs(3); 667 config 668 .keys 669 .push(thrussh_keys::key::KeyPair::generate_ed25519().unwrap()); 670 let config = Arc::new(config); 671 let mut sh = Server { 672 client_pubkey, 673 clients: Arc::new(Mutex::new(HashMap::new())), 674 id: 0, 675 }; 676 677 let socket = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); 678 let addr = socket.local_addr().unwrap(); 679 680 tokio::spawn(async move { 681 let (socket, _) = socket.accept().await.unwrap(); 682 let server = sh.new(socket.peer_addr().ok()); 683 server::run_stream(config, socket, server).await.unwrap(); 684 }); 685 686 let mut config = client::Config::default(); 687 config.preferred = Preferred::COMPRESSED; 688 let config = Arc::new(config); 689 690 dbg!(&addr); 691 let mut session = client::connect(config, addr, Client {}).await.unwrap(); 692 let authenticated = session 693 .authenticate_publickey(std::env::var("USER").unwrap(), Arc::new(client_key)) 694 .await 695 .unwrap(); 696 assert!(authenticated); 697 let mut channel = session.channel_open_session().await.unwrap(); 698 699 let data = &b"Hello, world!"[..]; 700 channel.data(data).await.unwrap(); 701 let msg = channel.wait().await.unwrap(); 702 match msg { 703 ChannelMsg::Data { data: msg_data } => { 704 assert_eq!(*data, *msg_data) 705 } 706 msg => panic!("Unexpected message {:?}", msg), 707 } 708 } 709 710 #[derive(Clone)] 711 struct Server { 712 client_pubkey: Arc<thrussh_keys::key::PublicKey>, 713 clients: Arc<Mutex<HashMap<(usize, ChannelId), super::server::Handle>>>, 714 id: usize, 715 } 716 717 impl server::Server for Server { 718 type Handler = Self; new(&mut self, _: Option<std::net::SocketAddr>) -> Self719 fn new(&mut self, _: Option<std::net::SocketAddr>) -> Self { 720 let s = self.clone(); 721 self.id += 1; 722 s 723 } 724 } 725 726 impl server::Handler for Server { 727 type Error = super::Error; 728 type FutureAuth = futures::future::Ready<Result<(Self, server::Auth), Self::Error>>; 729 type FutureUnit = futures::future::Ready<Result<(Self, Session), Self::Error>>; 730 type FutureBool = futures::future::Ready<Result<(Self, Session, bool), Self::Error>>; 731 finished_auth(self, auth: Auth) -> Self::FutureAuth732 fn finished_auth(self, auth: Auth) -> Self::FutureAuth { 733 futures::future::ready(Ok((self, auth))) 734 } finished_bool(self, b: bool, s: Session) -> Self::FutureBool735 fn finished_bool(self, b: bool, s: Session) -> Self::FutureBool { 736 futures::future::ready(Ok((self, s, b))) 737 } finished(self, s: Session) -> Self::FutureUnit738 fn finished(self, s: Session) -> Self::FutureUnit { 739 futures::future::ready(Ok((self, s))) 740 } channel_open_session(self, channel: ChannelId, session: Session) -> Self::FutureUnit741 fn channel_open_session(self, channel: ChannelId, session: Session) -> Self::FutureUnit { 742 { 743 let mut clients = self.clients.lock().unwrap(); 744 clients.insert((self.id, channel), session.handle()); 745 } 746 self.finished(session) 747 } auth_publickey(self, _: &str, _: &thrussh_keys::key::PublicKey) -> Self::FutureAuth748 fn auth_publickey(self, _: &str, _: &thrussh_keys::key::PublicKey) -> Self::FutureAuth { 749 debug!("auth_publickey"); 750 self.finished_auth(server::Auth::Accept) 751 } data(self, channel: ChannelId, data: &[u8], mut session: Session) -> Self::FutureUnit752 fn data(self, channel: ChannelId, data: &[u8], mut session: Session) -> Self::FutureUnit { 753 debug!("server data = {:?}", std::str::from_utf8(data)); 754 session.data(channel, CryptoVec::from_slice(data)); 755 self.finished(session) 756 } 757 } 758 759 struct Client {} 760 761 impl client::Handler for Client { 762 type Error = super::Error; 763 type FutureUnit = futures::future::Ready<Result<(Self, client::Session), Self::Error>>; 764 type FutureBool = futures::future::Ready<Result<(Self, bool), Self::Error>>; 765 finished_bool(self, b: bool) -> Self::FutureBool766 fn finished_bool(self, b: bool) -> Self::FutureBool { 767 futures::future::ready(Ok((self, b))) 768 } finished(self, session: client::Session) -> Self::FutureUnit769 fn finished(self, session: client::Session) -> Self::FutureUnit { 770 futures::future::ready(Ok((self, session))) 771 } check_server_key( self, server_public_key: &thrussh_keys::key::PublicKey, ) -> Self::FutureBool772 fn check_server_key( 773 self, 774 server_public_key: &thrussh_keys::key::PublicKey, 775 ) -> Self::FutureBool { 776 println!("check_server_key: {:?}", server_public_key); 777 self.finished_bool(true) 778 } 779 } 780 } 781