From 60846ed8a33ec95edea33440c7b2e0c10e8c2c4c Mon Sep 17 00:00:00 2001 From: Matt Johnston <matt@ucc.asn.au> Date: Fri, 19 Aug 2022 18:20:10 +0800 Subject: [PATCH] make serv1 build again with more scopes --- async/examples/con1.rs | 10 +-- async/examples/serv1.rs | 111 ++++++++++++++++++++++++++++---- sshproto/src/async_behaviour.rs | 18 +++--- sshproto/src/behaviour.rs | 16 ++--- sshproto/src/channel.rs | 2 +- sshproto/src/lib.rs | 1 + 6 files changed, 121 insertions(+), 37 deletions(-) diff --git a/async/examples/con1.rs b/async/examples/con1.rs index 3350507..020635f 100644 --- a/async/examples/con1.rs +++ b/async/examples/con1.rs @@ -145,19 +145,15 @@ async fn run(args: &Args) -> Result<()> { // Connect to a peer let mut stream = TcpStream::connect((args.host.as_str(), args.port)).await?; - let work = vec![0; 3000]; - // TODO: better lifetime rather than leaking - let work = Box::leak(Box::new(work)).as_mut_slice(); - let tx = vec![0; 3000]; - let tx = Box::leak(Box::new(tx)).as_mut_slice(); - // app is a Behaviour let mut app = door_async::CmdlineClient::new(args.username.as_ref().unwrap()); for i in &args.identityfile { app.add_authkey(read_key(&i).with_context(|| format!("loading key {i}"))?); } - let mut cli = SSHClient::new(work, tx)?; + let mut rxbuf = vec![0; 3000]; + let mut txbuf = vec![0; 3000]; + let mut cli = SSHClient::new(&mut rxbuf, &mut txbuf)?; let mut s = cli.socket(); diff --git a/async/examples/serv1.rs b/async/examples/serv1.rs index e8b2156..b94553f 100644 --- a/async/examples/serv1.rs +++ b/async/examples/serv1.rs @@ -9,10 +9,13 @@ use pretty_hex::PrettyHex; use tokio::net::{TcpStream, TcpListener}; use std::{net::Ipv6Addr, io::Read}; +use std::path::Path; use door_sshproto::*; use door_async::{SSHServer, raw_pty}; +use async_trait::async_trait; + use simplelog::*; #[derive(argh::FromArgs)] /** con1 @@ -29,10 +32,15 @@ struct Args { #[argh(option, short='p', default="22")] /// port port: u16, + + #[argh(option)] + /// a path to hostkeys. At most one of each key type. + hostkey: Vec<String>, + } fn parse_args() -> Result<Args> { - let mut args: Args = argh::from_env(); + let args: Args = argh::from_env(); Ok(args) } @@ -52,8 +60,7 @@ fn main() -> Result<()> { .map_err(|e| { error!("Exit with error: {e:?}"); e - }); - Ok(()) + }) } fn setup_log(args: &Args) -> Result<()> { @@ -84,17 +91,97 @@ fn setup_log(args: &Args) -> Result<()> { Ok(()) } -fn run_session<'a, R: Send>(scope: &'a moro::Scope<'a, '_, R>, stream: TcpStream) -> Result<()> { - let rxbuf = vec![0; 3000]; - // TODO: better lifetime rather than leaking - let rxbuf = Box::leak(Box::new(rxbuf)).as_mut_slice(); - let txbuf = vec![0; 3000]; - let txbuf = Box::leak(Box::new(txbuf)).as_mut_slice(); +fn read_key(p: &str) -> Result<SignKey> { + let mut v = vec![]; + std::fs::File::open(p)?.read_to_end(&mut v)?; + SignKey::from_openssh(v).context("parsing openssh key") +} + +struct DemoServer { + sess: Option<u32>, + keys: Vec<SignKey> +} - let mut serv = SSHServer::new(rxbuf, txbuf)?; +impl DemoServer { + fn new(keyfiles: &[String]) -> Result<Self> { + let keys = keyfiles.iter().map(|f| { + read_key(f).with_context(|| format!("loading key {f}")) + }).collect::<Result<Vec<SignKey>>>()?; - scope.spawn(async { + Ok(Self { + sess: None, + keys, + }) + } +} +#[async_trait] +impl AsyncServBehaviour for DemoServer { + async fn hostkeys(&mut self) -> BhResult<&[SignKey]> { + Ok(&self.keys) + } + + + fn have_auth_password(&self, user: &str) -> bool { + true + } + + fn have_auth_pubkey(&self, user: &str) -> bool { + false + } + + async fn auth_password(&mut self, user: &str, password: &str) -> bool { + user == "matt" && password == "pw" + } + + fn open_session(&mut self, chan: u32) -> ChanOpened { + if self.sess.is_some() { + ChanOpened::Failure(ChanFail::SSH_OPEN_ADMINISTRATIVELY_PROHIBITED) + } else { + self.sess = Some(chan); + ChanOpened::Success + } + } + + fn sess_req_shell(&mut self, _chan: u32) -> bool { + true + } + + fn sess_pty(&mut self, _chan: u32, _pty: &Pty) -> bool { + true + } +} + +fn run_session<'a, R: Send>(args: &'a Args, scope: &'a moro::Scope<'a, '_, R>, mut stream: TcpStream) -> Result<()> { + // app is a Behaviour + + scope.spawn(async move { + let mut app = DemoServer::new(&args.hostkey)?; + let mut rxbuf = vec![0; 3000]; + let mut txbuf = vec![0; 3000]; + let mut serv = SSHServer::new(&mut rxbuf, &mut txbuf)?; + let mut s = serv.socket(); + + moro::async_scope!(|scope| { + + scope.spawn(tokio::io::copy_bidirectional(&mut stream, &mut s)); + + scope.spawn(async { + loop { + let ev = serv.progress(&mut app, |ev| { + trace!("progress event {ev:?}"); + let e = match ev { + Event::CliAuthed => Some(Event::CliAuthed), + _ => None, + }; + Ok(e) + }).await.context("progress loop")?; + } + #[allow(unreachable_code)] + Ok::<_, anyhow::Error>(()) + }); + Ok::<_, anyhow::Error>(()) + }).await }); Ok(()) @@ -107,7 +194,7 @@ async fn run(args: &Args) -> Result<()> { loop { let (stream, _) = listener.accept().await?; - run_session(scope, stream)? + run_session(args, scope, stream)? } #[allow(unreachable_code)] Ok::<_, anyhow::Error>(()) diff --git a/sshproto/src/async_behaviour.rs b/sshproto/src/async_behaviour.rs index f7e5f8f..fc8395b 100644 --- a/sshproto/src/async_behaviour.rs +++ b/sshproto/src/async_behaviour.rs @@ -117,7 +117,7 @@ pub trait AsyncServBehaviour: Sync+Send { // then later request a single key. // Also could make it take a closure to call with the key, lets it just // be loaded on the stack rather than kept in memory for the whole lifetime. - async fn hostkeys(&self) -> BhResult<&[sign::SignKey]>; + async fn hostkeys(&mut self) -> BhResult<&[sign::SignKey]>; // TODO: or return a slice of enums fn have_auth_password(&self, user: &str) -> bool; @@ -126,42 +126,42 @@ pub trait AsyncServBehaviour: Sync+Send { #[allow(unused)] // TODO: change password - async fn auth_password(&self, user: &str, password: &str) -> bool { + async fn auth_password(&mut self, user: &str, password: &str) -> bool { false } /// Returns true if the pubkey can be used to log in. /// TODO: allow returning pubkey restriction options #[allow(unused)] - async fn auth_pubkey(&self, user: &str, pubkey: &sign::SignKey) -> bool { + async fn auth_pubkey(&mut self, user: &str, pubkey: &sign::SignKey) -> bool { false } /// Returns whether a session can be opened - fn open_session(&self, chan: u32) -> channel::ChanOpened; + fn open_session(&mut self, chan: u32) -> channel::ChanOpened; #[allow(unused)] - fn open_tcp_forwarded(&self, chan: u32, t: &ForwardedTcpip) -> ChanOpened { + fn open_tcp_forwarded(&mut self, chan: u32, t: &ForwardedTcpip) -> ChanOpened { ChanOpened::Failure(ChanFail::SSH_OPEN_UNKNOWN_CHANNEL_TYPE) } #[allow(unused)] - fn open_tcp_direct(&self, chan: u32, t: &DirectTcpip) -> ChanOpened { + fn open_tcp_direct(&mut self, chan: u32, t: &DirectTcpip) -> ChanOpened { ChanOpened::Failure(ChanFail::SSH_OPEN_UNKNOWN_CHANNEL_TYPE) } #[allow(unused)] - fn sess_req_shell(&self, chan: u32) -> bool { + fn sess_req_shell(&mut self, chan: u32) -> bool { false } #[allow(unused)] - fn sess_req_exec(&self, chan: u32, cmd: &str) -> bool { + fn sess_req_exec(&mut self, chan: u32, cmd: &str) -> bool { false } #[allow(unused)] - fn sess_pty(&self, chan: u32, pty: &Pty) -> bool { + fn sess_pty(&mut self, chan: u32, pty: &Pty) -> bool { false } } diff --git a/sshproto/src/behaviour.rs b/sshproto/src/behaviour.rs index de627f9..d9861b1 100644 --- a/sshproto/src/behaviour.rs +++ b/sshproto/src/behaviour.rs @@ -261,7 +261,7 @@ pub struct ServBehaviour<'a> { #[cfg(feature = "std")] impl<'a> ServBehaviour<'a> { - pub(crate) async fn hostkeys(&self) -> BhResult<&[sign::SignKey]> { + pub(crate) async fn hostkeys(&mut self) -> BhResult<&[sign::SignKey]> { self.inner.hostkeys().await } @@ -274,34 +274,34 @@ impl<'a> ServBehaviour<'a> { // fn authmethods(&self) -> [AuthMethod]; - pub(crate) async fn auth_password(&self, user: &str, password: &str) -> bool { + pub(crate) async fn auth_password(&mut self, user: &str, password: &str) -> bool { self.inner.auth_password(user, password).await } /// Returns whether a session channel can be opened - pub(crate) fn open_session(&self, chan: u32) -> channel::ChanOpened { + pub(crate) fn open_session(&mut self, chan: u32) -> channel::ChanOpened { self.inner.open_session(chan) } - pub(crate) fn open_tcp_forwarded(&self, chan: u32, + pub(crate) fn open_tcp_forwarded(&mut self, chan: u32, t: &ForwardedTcpip) -> channel::ChanOpened { self.inner.open_tcp_forwarded(chan, t) } - pub(crate) fn open_tcp_direct(&self, chan: u32, + pub(crate) fn open_tcp_direct(&mut self, chan: u32, t: &DirectTcpip) -> channel::ChanOpened { self.inner.open_tcp_direct(chan, t) } - pub(crate) fn sess_req_shell(&self, chan: u32) -> bool { + pub(crate) fn sess_req_shell(&mut self, chan: u32) -> bool { self.inner.sess_req_shell(chan) } - pub(crate) fn sess_req_exec(&self, chan: u32, cmd: &str) -> bool { + pub(crate) fn sess_req_exec(&mut self, chan: u32, cmd: &str) -> bool { self.inner.sess_req_exec(chan, cmd) } - pub(crate) fn sess_pty(&self, chan: u32, pty: &Pty) -> bool { + pub(crate) fn sess_pty(&mut self, chan: u32, pty: &Pty) -> bool { self.inner.sess_pty(chan, pty) } } diff --git a/sshproto/src/channel.rs b/sshproto/src/channel.rs index eac61b8..f116e12 100644 --- a/sshproto/src/channel.rs +++ b/sshproto/src/channel.rs @@ -245,7 +245,7 @@ impl Channels { let r = match &p.ty { ChannelOpenType::Session => { // unwrap: earlier test ensures b.server() succeeds - let bserv = b.server().unwrap(); + let mut bserv = b.server().unwrap(); bserv.open_session(ch.recv.num) } ChannelOpenType::ForwardedTcpip(t) => { diff --git a/sshproto/src/lib.rs b/sshproto/src/lib.rs index 5bbcaba..df31681 100644 --- a/sshproto/src/lib.rs +++ b/sshproto/src/lib.rs @@ -58,4 +58,5 @@ pub use sign::SignKey; pub use packets::PubKey; pub use error::{Error,Result}; pub use channel::{ChanMsg, ChanMsgDetails, ChanEvent, Pty, ChanOpened}; +pub use sshnames::{ChanFail}; pub use conn::Event; -- GitLab