lnk_thrussh/lib.rs
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 lnk_thrussh;
35//! extern crate lnk_thrussh_keys;
36//! extern crate futures;
37//! extern crate tokio;
38//! use std::sync::{Mutex, Arc};
39//! use lnk_thrussh::*;
40//! use lnk_thrussh::server::{Auth, Session};
41//! use lnk_thrussh_keys::*;
42//! use std::collections::HashMap;
43//! use futures::Future;
44//!
45//! #[tokio::main]
46//! async fn main() {
47//! let client_key = lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
48//! let client_pubkey = Arc::new(client_key.clone_public_key());
49//! let mut config = lnk_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(lnk_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//! lnk_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<lnk_thrussh_keys::key::PublicKey>,
68//! clients: Arc<Mutex<HashMap<(usize, ChannelId), lnk_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//! ```no_run
153//!extern crate lnk_thrussh;
154//!extern crate lnk_thrussh_keys;
155//!extern crate futures;
156//!extern crate tokio;
157//!extern crate env_logger;
158//!use std::sync::Arc;
159//!use lnk_thrussh::*;
160//!use lnk_thrussh::server::{Auth, Session};
161//!use lnk_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//! use lnk_thrussh_agent::client::ClientStream as _;
197//!
198//! let config = lnk_thrussh::client::Config::default();
199//! let config = Arc::new(config);
200//! let sh = Client{};
201//!
202//! let key = lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
203//! let mut agent = lnk_thrussh_agent::client::tokio::UnixStream::connect_env().await.unwrap();
204//! agent.add_identity(&key, &[]).await.unwrap();
205//! let mut session = lnk_thrussh::client::connect(config, "localhost:22", sh).await.unwrap();
206//! if session.authenticate_future(std::env::var("USER").unwrap(), key.clone_public_key(), agent).await.1.unwrap() {
207//! let mut channel = session.channel_open_session().await.unwrap();
208//! channel.data(&b"Hello, world!"[..]).await.unwrap();
209//! if let Some(msg) = channel.wait().await {
210//! println!("{:?}", msg)
211//! }
212//! }
213//! }
214//! ```
215//! # Using non-socket IO / writing tunnels
216//!
217//! The easy way to implement SSH tunnels, like `ProxyCommand` for
218//! OpenSSH, is to use the `thrussh-config` crate, and use the
219//! `Stream::tcp_connect` or `Stream::proxy_command` methods of that
220//! crate. That crate is a very lightweight layer above Thrussh, only
221//! implementing for external commands the traits used for sockets.
222//!
223//! # The SSH protocol
224//!
225//! If we exclude the key exchange and authentication phases, handled
226//! by Thrussh behind the scenes, the rest of the SSH protocol is
227//! relatively simple: clients and servers open *channels*, which are
228//! just integers used to handle multiple requests in parallel in a
229//! single connection. Once a client has obtained a `ChannelId` by
230//! calling one the many `channel_open_…` methods of
231//! `client::Connection`, the client may send exec requests and data
232//! to the server.
233//!
234//! A simple client just asking the server to run one command will
235//! usually start by calling
236//! `client::Connection::channel_open_session`, then
237//! `client::Connection::exec`, then possibly
238//! `client::Connection::data` a number of times to send data to the
239//! command's standard input, and finally `Connection::channel_eof`
240//! and `Connection::channel_close`.
241//!
242//! # Design principles
243//!
244//! The main goal of this library is conciseness, and reduced size and
245//! readability of the library's code. Moreover, this library is split
246//! between Thrussh, which implements the main logic of SSH clients
247//! and servers, and Thrussh-keys, which implements calls to
248//! cryptographic primitives.
249//!
250//! One non-goal is to implement all possible cryptographic algorithms
251//! published since the initial release of SSH. Technical debt is
252//! easily acquired, and we would need a very strong reason to go
253//! against this principle. If you are designing a system from
254//! scratch, we urge you to consider recent cryptographic primitives
255//! such as Ed25519 for public key cryptography, and Chacha20-Poly1305
256//! for symmetric cryptography and MAC.
257//!
258//! # Internal details of the event loop
259//!
260//! It might seem a little odd that the read/write methods for server
261//! or client sessions often return neither `Result` nor
262//! `Future`. This is because the data sent to the remote side is
263//! buffered, because it needs to be encrypted first, and encryption
264//! works on buffers, and for many algorithms, not in place.
265//!
266//! Hence, the event loop keeps waiting for incoming packets, reacts
267//! to them by calling the provided `Handler`, which fills some
268//! buffers. If the buffers are non-empty, the event loop then sends
269//! them to the socket, flushes the socket, empties the buffers and
270//! starts again. In the special case of the server, unsollicited
271//! messages sent through a `server::Handle` are processed when there
272//! is no incoming packet to read.
273//!
274#[macro_use]
275extern crate bitflags;
276#[macro_use]
277extern crate log;
278extern crate lnk_thrussh_libsodium as sodium;
279#[macro_use]
280extern crate thiserror;
281
282pub use lnk_cryptovec::CryptoVec;
283mod auth;
284mod cipher;
285mod compression;
286mod kex;
287mod key;
288mod msg;
289mod negotiation;
290mod ssh_read;
291mod sshbuffer;
292
293pub use negotiation::{Named, Preferred};
294mod pty;
295pub use pty::Pty;
296
297macro_rules! push_packet {
298 ( $buffer:expr, $x:expr ) => {{
299 use byteorder::{BigEndian, ByteOrder};
300 let i0 = $buffer.len();
301 $buffer.extend(b"\0\0\0\0");
302 let x = $x;
303 let i1 = $buffer.len();
304 use std::ops::DerefMut;
305 let buf = $buffer.deref_mut();
306 BigEndian::write_u32(&mut buf[i0..], (i1 - i0 - 4) as u32);
307 x
308 }};
309}
310
311type Sha256Hash =
312 generic_array::GenericArray<u8, <sha2::Sha256 as digest::FixedOutputDirty>::OutputSize>;
313
314mod session;
315
316/// Server side of this library.
317pub mod server;
318
319/// Client side of this library.
320pub mod client;
321
322#[derive(Debug, Error)]
323pub enum Error {
324 /// The key file could not be parsed.
325 #[error("Could not read key")]
326 CouldNotReadKey,
327
328 /// Unspecified problem with the beginning of key exchange.
329 #[error("Key exchange init failed")]
330 KexInit,
331
332 /// No common key exchange algorithm.
333 #[error("No common key exchange algorithm")]
334 NoCommonKexAlgo,
335
336 /// No common signature algorithm.
337 #[error("No common key algorithm")]
338 NoCommonKeyAlgo,
339
340 /// No common cipher.
341 #[error("No common key cipher")]
342 NoCommonCipher,
343
344 /// No common compression algorithm.
345 #[error("No common compression algorithm")]
346 NoCommonCompression,
347
348 /// Invalid SSH version string.
349 #[error("invalid SSH version string")]
350 Version,
351
352 /// Error during key exchange.
353 #[error("Key exchange failed")]
354 Kex,
355
356 /// Invalid packet authentication code.
357 #[error("Wrong packet authentication code")]
358 PacketAuth,
359
360 /// The protocol is in an inconsistent state.
361 #[error("Inconsistent state of the protocol")]
362 Inconsistent,
363
364 /// The client is not yet authenticated.
365 #[error("Not yet authenticated")]
366 NotAuthenticated,
367
368 /// Index out of bounds.
369 #[error("Index out of bounds")]
370 IndexOutOfBounds,
371
372 /// Unknown server key.
373 #[error("Unknown server key")]
374 UnknownKey,
375
376 /// The server provided a wrong signature.
377 #[error("Wrong server signature")]
378 WrongServerSig,
379
380 /// Message received/sent on unopened channel.
381 #[error("Channel not open")]
382 WrongChannel,
383
384 /// Disconnected
385 #[error("Disconnected")]
386 Disconnect,
387
388 /// No home directory found when trying to learn new host key.
389 #[error("No home directory when saving host key")]
390 NoHomeDir,
391
392 /// Remote key changed, this could mean a man-in-the-middle attack
393 /// is being performed on the connection.
394 #[error("Key changed, line {}", line)]
395 KeyChanged { line: usize },
396
397 /// Connection closed by the remote side.
398 #[error("Connection closed by the remote side")]
399 HUP,
400
401 /// Connection timeout.
402 #[error("Connection timeout")]
403 ConnectionTimeout,
404
405 /// Missing authentication method.
406 #[error("No authentication method")]
407 NoAuthMethod,
408
409 #[error("Channel send error")]
410 SendError,
411
412 #[error("Pending buffer limit reached")]
413 Pending,
414
415 #[error(transparent)]
416 Keys(#[from] lnk_thrussh_keys::Error),
417
418 #[error(transparent)]
419 Encoding(#[from] lnk_thrussh_encoding::Error),
420
421 #[error(transparent)]
422 IO(#[from] std::io::Error),
423
424 #[error(transparent)]
425 Utf8(#[from] std::str::Utf8Error),
426
427 #[error(transparent)]
428 Compress(#[from] flate2::CompressError),
429
430 #[error(transparent)]
431 Decompress(#[from] flate2::DecompressError),
432
433 #[error(transparent)]
434 Join(#[from] tokio::task::JoinError),
435
436 #[error(transparent)]
437 #[cfg(feature = "openssl")]
438 Openssl(#[from] openssl::error::ErrorStack),
439
440 #[error(transparent)]
441 Elapsed(#[from] tokio::time::error::Elapsed),
442}
443
444#[derive(Debug, Error)]
445#[error("Could not reach the event loop")]
446pub struct SendError {}
447
448/// Since handlers are large, their associated future types must implement this trait to provide reasonable default implementations (basically, rejecting all requests).
449pub trait FromFinished<T>: futures::Future<Output = Result<T, Error>> {
450 /// Turns type `T` into `Self`, a future yielding `T`.
451 fn finished(t: T) -> Self;
452}
453
454impl<T> FromFinished<T> for futures::future::Ready<Result<T, Error>> {
455 fn finished(t: T) -> Self {
456 futures::future::ready(Ok(t))
457 }
458}
459
460impl<T: 'static> FromFinished<T> for Box<dyn futures::Future<Output = Result<T, Error>> + Unpin> {
461 fn finished(t: T) -> Self {
462 Box::new(futures::future::ready(Ok(t)))
463 }
464}
465
466// mod mac;
467// use mac::*;
468// mod compression;
469
470/// The number of bytes read/written, and the number of seconds before a key re-exchange is requested.
471#[derive(Debug, Clone)]
472pub struct Limits {
473 pub rekey_write_limit: usize,
474 pub rekey_read_limit: usize,
475 pub rekey_time_limit: std::time::Duration,
476}
477
478impl Limits {
479 /// Create a new `Limits`, checking that the given bounds cannot lead to nonce reuse.
480 pub fn new(write_limit: usize, read_limit: usize, time_limit: std::time::Duration) -> Limits {
481 assert!(write_limit <= 1 << 30 && read_limit <= 1 << 30);
482 Limits {
483 rekey_write_limit: write_limit,
484 rekey_read_limit: read_limit,
485 rekey_time_limit: time_limit,
486 }
487 }
488}
489
490impl Default for Limits {
491 fn default() -> Self {
492 // Following the recommendations of
493 // https://tools.ietf.org/html/rfc4253#section-9
494 Limits {
495 rekey_write_limit: 1 << 30, // 1 Gb
496 rekey_read_limit: 1 << 30, // 1 Gb
497 rekey_time_limit: std::time::Duration::from_secs(3600),
498 }
499 }
500}
501
502pub use auth::{AgentAuthError, MethodSet, Signer};
503
504/// A reason for disconnection.
505#[allow(missing_docs)] // This should be relatively self-explanatory.
506#[derive(Debug)]
507pub enum Disconnect {
508 HostNotAllowedToConnect = 1,
509 ProtocolError = 2,
510 KeyExchangeFailed = 3,
511 #[doc(hidden)]
512 Reserved = 4,
513 MACError = 5,
514 CompressionError = 6,
515 ServiceNotAvailable = 7,
516 ProtocolVersionNotSupported = 8,
517 HostKeyNotVerifiable = 9,
518 ConnectionLost = 10,
519 ByApplication = 11,
520 TooManyConnections = 12,
521 AuthCancelledByUser = 13,
522 NoMoreAuthMethodsAvailable = 14,
523 IllegalUserName = 15,
524}
525
526/// The type of signals that can be sent to a remote process. If you
527/// plan to use custom signals, read [the
528/// RFC](https://tools.ietf.org/html/rfc4254#section-6.10) to
529/// understand the encoding.
530#[allow(missing_docs)]
531// This should be relatively self-explanatory.
532#[derive(Debug, Clone)]
533pub enum Sig {
534 ABRT,
535 ALRM,
536 FPE,
537 HUP,
538 ILL,
539 INT,
540 KILL,
541 PIPE,
542 QUIT,
543 SEGV,
544 TERM,
545 USR1,
546 Custom(String),
547}
548
549impl Sig {
550 fn name(&self) -> &str {
551 match *self {
552 Sig::ABRT => "ABRT",
553 Sig::ALRM => "ALRM",
554 Sig::FPE => "FPE",
555 Sig::HUP => "HUP",
556 Sig::ILL => "ILL",
557 Sig::INT => "INT",
558 Sig::KILL => "KILL",
559 Sig::PIPE => "PIPE",
560 Sig::QUIT => "QUIT",
561 Sig::SEGV => "SEGV",
562 Sig::TERM => "TERM",
563 Sig::USR1 => "USR1",
564 Sig::Custom(ref c) => c,
565 }
566 }
567 fn from_name(name: &[u8]) -> Result<Sig, Error> {
568 match name {
569 b"ABRT" => Ok(Sig::ABRT),
570 b"ALRM" => Ok(Sig::ALRM),
571 b"FPE" => Ok(Sig::FPE),
572 b"HUP" => Ok(Sig::HUP),
573 b"ILL" => Ok(Sig::ILL),
574 b"INT" => Ok(Sig::INT),
575 b"KILL" => Ok(Sig::KILL),
576 b"PIPE" => Ok(Sig::PIPE),
577 b"QUIT" => Ok(Sig::QUIT),
578 b"SEGV" => Ok(Sig::SEGV),
579 b"TERM" => Ok(Sig::TERM),
580 b"USR1" => Ok(Sig::USR1),
581 x => Ok(Sig::Custom(std::str::from_utf8(x)?.to_string())),
582 }
583 }
584}
585
586/// Reason for not being able to open a channel.
587#[derive(Debug, Copy, Clone, PartialEq)]
588#[allow(missing_docs)]
589pub enum ChannelOpenFailure {
590 AdministrativelyProhibited = 1,
591 ConnectFailed = 2,
592 UnknownChannelType = 3,
593 ResourceShortage = 4,
594}
595
596impl ChannelOpenFailure {
597 fn from_u32(x: u32) -> Option<ChannelOpenFailure> {
598 match x {
599 1 => Some(ChannelOpenFailure::AdministrativelyProhibited),
600 2 => Some(ChannelOpenFailure::ConnectFailed),
601 3 => Some(ChannelOpenFailure::UnknownChannelType),
602 4 => Some(ChannelOpenFailure::ResourceShortage),
603 _ => None,
604 }
605 }
606}
607
608#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
609/// The identifier of a channel.
610pub struct ChannelId(u32);
611
612/// The parameters of a channel.
613#[derive(Debug)]
614pub(crate) struct Channel {
615 recipient_channel: u32,
616 sender_channel: ChannelId,
617 recipient_window_size: u32,
618 sender_window_size: u32,
619 recipient_maximum_packet_size: u32,
620 sender_maximum_packet_size: u32,
621 /// Has the other side confirmed the channel?
622 pub confirmed: bool,
623 wants_reply: bool,
624 pending_data: std::collections::VecDeque<(CryptoVec, Option<u32>, usize)>,
625}
626
627#[derive(Debug)]
628pub enum ChannelMsg {
629 Data {
630 data: CryptoVec,
631 },
632 ExtendedData {
633 data: CryptoVec,
634 ext: u32,
635 },
636 Eof,
637 Close,
638 XonXoff {
639 client_can_do: bool,
640 },
641 ExitStatus {
642 exit_status: u32,
643 },
644 ExitSignal {
645 signal_name: Sig,
646 core_dumped: bool,
647 error_message: String,
648 lang_tag: String,
649 },
650 WindowAdjusted {
651 new_size: u32,
652 },
653 Success,
654}
655
656#[cfg(test)]
657mod test_compress {
658 use super::server::{Auth, Server as _, Session};
659 use super::*;
660 use std::collections::HashMap;
661 use std::sync::{Arc, Mutex};
662
663 #[tokio::test]
664 async fn compress_local_test() {
665 let _ = env_logger::try_init();
666
667 let client_key = lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
668 let client_pubkey = Arc::new(client_key.clone_public_key());
669 let mut config = server::Config::default();
670 config.preferred = Preferred::COMPRESSED;
671 config.connection_timeout = None; // Some(std::time::Duration::from_secs(3));
672 config.auth_rejection_time = std::time::Duration::from_secs(3);
673 config
674 .keys
675 .push(lnk_thrussh_keys::key::KeyPair::generate_ed25519().unwrap());
676 let config = Arc::new(config);
677 let mut sh = Server {
678 client_pubkey,
679 clients: Arc::new(Mutex::new(HashMap::new())),
680 id: 0,
681 };
682
683 let socket = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
684 let addr = socket.local_addr().unwrap();
685
686 tokio::spawn(async move {
687 let (socket, _) = socket.accept().await.unwrap();
688 let server = sh.new(socket.peer_addr().ok());
689 server::run_stream(config, socket, server).await.unwrap();
690 });
691
692 let mut config = client::Config::default();
693 config.preferred = Preferred::COMPRESSED;
694 let config = Arc::new(config);
695
696 dbg!(&addr);
697 let mut session = client::connect(config, addr, Client {}).await.unwrap();
698 let authenticated = session
699 .authenticate_publickey(std::env::var("USER").unwrap(), Arc::new(client_key))
700 .await
701 .unwrap();
702 assert!(authenticated);
703 let mut channel = session.channel_open_session().await.unwrap();
704
705 let data = &b"Hello, world!"[..];
706 channel.data(data).await.unwrap();
707 let msg = channel.wait().await.unwrap();
708 match msg {
709 ChannelMsg::Data { data: msg_data } => {
710 assert_eq!(*data, *msg_data)
711 }
712 msg => panic!("Unexpected message {:?}", msg),
713 }
714 }
715
716 #[derive(Clone)]
717 struct Server {
718 client_pubkey: Arc<lnk_thrussh_keys::key::PublicKey>,
719 clients: Arc<Mutex<HashMap<(usize, ChannelId), super::server::Handle>>>,
720 id: usize,
721 }
722
723 impl server::Server for Server {
724 type Handler = Self;
725 fn new(&mut self, _: Option<std::net::SocketAddr>) -> Self {
726 let s = self.clone();
727 self.id += 1;
728 s
729 }
730 }
731
732 impl server::Handler for Server {
733 type Error = super::Error;
734 type FutureAuth = futures::future::Ready<Result<(Self, server::Auth), Self::Error>>;
735 type FutureUnit = futures::future::Ready<Result<(Self, Session), Self::Error>>;
736 type FutureBool = futures::future::Ready<Result<(Self, Session, bool), Self::Error>>;
737
738 fn finished_auth(self, auth: Auth) -> Self::FutureAuth {
739 futures::future::ready(Ok((self, auth)))
740 }
741 fn finished_bool(self, b: bool, s: Session) -> Self::FutureBool {
742 futures::future::ready(Ok((self, s, b)))
743 }
744 fn finished(self, s: Session) -> Self::FutureUnit {
745 futures::future::ready(Ok((self, s)))
746 }
747 fn channel_open_session(self, channel: ChannelId, session: Session) -> Self::FutureUnit {
748 {
749 let mut clients = self.clients.lock().unwrap();
750 clients.insert((self.id, channel), session.handle());
751 }
752 self.finished(session)
753 }
754 fn auth_publickey(self, _: &str, _: &lnk_thrussh_keys::key::PublicKey) -> Self::FutureAuth {
755 debug!("auth_publickey");
756 self.finished_auth(server::Auth::Accept)
757 }
758 fn data(self, channel: ChannelId, data: &[u8], mut session: Session) -> Self::FutureUnit {
759 debug!("server data = {:?}", std::str::from_utf8(data));
760 session.data(channel, CryptoVec::from_slice(data));
761 self.finished(session)
762 }
763 }
764
765 struct Client {}
766
767 impl client::Handler for Client {
768 type Error = super::Error;
769 type FutureUnit = futures::future::Ready<Result<(Self, client::Session), Self::Error>>;
770 type FutureBool = futures::future::Ready<Result<(Self, bool), Self::Error>>;
771
772 fn finished_bool(self, b: bool) -> Self::FutureBool {
773 futures::future::ready(Ok((self, b)))
774 }
775 fn finished(self, session: client::Session) -> Self::FutureUnit {
776 futures::future::ready(Ok((self, session)))
777 }
778 fn check_server_key(
779 self,
780 server_public_key: &lnk_thrussh_keys::key::PublicKey,
781 ) -> Self::FutureBool {
782 println!("check_server_key: {:?}", server_public_key);
783 self.finished_bool(true)
784 }
785 }
786}