Skip to content

Commit

Permalink
Banner and Break handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mkj committed Jun 3, 2024
1 parent 40b7998 commit 59471c0
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 16 deletions.
3 changes: 3 additions & 0 deletions async/src/cmdline_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,9 @@ impl CmdlineClient {
}
}
}
CliEvent::Banner(b) => {
println!("Banner from server:\n{}", b.banner()?)
}
CliEvent::Defunct => {
trace!("break defunct");
break Ok::<_, Error>(())
Expand Down
8 changes: 0 additions & 8 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,4 @@ impl Client {
parse_ctx.cli_auth_type = None;
self.auth.success()
}

pub(crate) fn banner(
&mut self,
banner: &packets::UserauthBanner<'_>,
) {
// TODO event banner
// b.show_banner(banner.message, banner.lang)
}
}
20 changes: 16 additions & 4 deletions src/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ impl Conn {
self.cliserv.is_client()
}

pub fn is_server(&self) -> bool {
!self.is_client()
}

pub fn server(&self) -> Result<&server::Server> {
match &self.cliserv {
ClientServer::Server(s) => Ok(s),
Expand Down Expand Up @@ -437,13 +441,12 @@ impl Conn {
return error::SSHProto.fail()
}
}
Packet::UserauthBanner(p) => {
if let ClientServer::Client(cli) = &mut self.cliserv {
cli.banner(&p);
} else {
Packet::UserauthBanner(_) => {
if self.is_server() {
debug!("Received banner as a server");
return error::SSHProto.fail()
}
disp.event = DispatchEvent::CliEvent(CliEventId::Banner);
}
Packet::Userauth60(p) => {
// TODO: client only
Expand Down Expand Up @@ -547,6 +550,15 @@ impl Conn {
CliSessionExit::new(&packet)
}

pub(crate) fn fetch_cli_banner<'p>(&mut self, payload: &'p [u8]) -> Result<Banner<'p>> {
self.client()?;
if let Packet::UserauthBanner(b) = self.packet(payload)? {
Ok(Banner(b))
} else {
Err(Error::bug())
}
}

pub(crate) fn resume_servhostkeys(&mut self,
payload: &[u8], s: &mut TrafSend, keys: &[&SignKey]) -> Result<()> {
self.server()?;
Expand Down
21 changes: 20 additions & 1 deletion src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl<'g, 'a> Event<'g, 'a> {
pub enum CliEvent<'g, 'a>
{
Hostkey(CheckHostkey<'g, 'a>),
Banner(Banner<'g>),
Username(RequestUsername<'g, 'a>),
Password(RequestPassword<'g, 'a>),
Pubkey(RequestPubkey<'g, 'a>),
Expand Down Expand Up @@ -78,6 +79,7 @@ impl Debug for CliEvent<'_, '_> {
Self::SessionOpened(_) => "SessionOpened",
Self::SessionExit(_) => "SessionExit",
Self::AgentSign(_) => "AgentSign",
Self::Banner(_) => "Banner",
Self::Defunct => "Defunct",
};
write!(f, "CliEvent({e})")
Expand Down Expand Up @@ -167,6 +169,19 @@ impl CheckHostkey<'_, '_> {
}
}

pub struct Banner<'a>(pub(crate) packets::UserauthBanner<'a>);

impl Banner<'_> {
pub fn banner(&self) -> Result<&str> {
self.0.message.as_str()
}

pub fn raw_banner(&self) -> TextString {
self.0.message
}
}


// impl CliExit<''_, '_> {
// pub fn

Expand All @@ -182,11 +197,11 @@ pub(crate) enum CliEventId {
Authenticated,
SessionOpened(ChanNum),
SessionExit,
Banner,
Defunct

// TODO:
// Disconnected
// Banner,
// OpenTCPForwarded (new session)
// TCPDirectOpened (response)
}
Expand Down Expand Up @@ -222,6 +237,9 @@ impl CliEventId {
Self::SessionExit => {
Ok(CliEvent::SessionExit(runner.fetch_cli_session_exit()?))
}
Self::Banner => {
Ok(CliEvent::Banner(runner.fetch_cli_banner()?))
}
Self::Defunct => error::BadUsage.fail()
}
}
Expand All @@ -233,6 +251,7 @@ impl CliEventId {
| Self::Authenticated
| Self::SessionOpened(_)
| Self::SessionExit
| Self::Banner
| Self::Defunct
=> false,
| Self::Hostkey
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ mod ssh_chapoly;
mod traffic;

use conn::DispatchEvent;
use event::{CliEventId, ServEventId};

// Application API
pub use sshwire::TextString;
Expand Down
7 changes: 7 additions & 0 deletions src/packets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,9 @@ pub struct ChannelRequest<'a> {
pub req: ChannelReqType<'a>,
}

/// Channel Requests
///
/// Most are specified in [RFC4335](https://datatracker.ietf.org/doc/html/rfc4335)
#[derive(Debug, SSHEncode, SSHDecode)]
pub enum ChannelReqType<'a> {
#[sshwire(variant = "shell")]
Expand All @@ -666,6 +669,9 @@ pub enum ChannelReqType<'a> {
ExitStatus(ExitStatus),
#[sshwire(variant = "exit-signal")]
ExitSignal(ExitSignal<'a>),
/// Channel Break Request
///
/// [RFC4335](https://datatracker.ietf.org/doc/html/rfc4335)
#[sshwire(variant = "break")]
Break(Break),
// Other requests that aren't implemented at present:
Expand Down Expand Up @@ -729,6 +735,7 @@ pub struct ExitSignal<'a> {

#[derive(Debug, Clone, SSHEncode, SSHDecode)]
pub struct Break {
/// Break length in milliseconds
pub length: u32,
}

Expand Down
25 changes: 23 additions & 2 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ use pretty_hex::PrettyHex;

use crate::{event::ChanRequest, packets::{Packet, Subsystem}, *};
use packets::{ChannelDataExt, ChannelData};
use crate::channel::{ChanNum, ChanData};
use channel::{ChanNum, ChanData};
use channel::{CliSessionExit, CliSessionOpener};
use encrypt::KeyState;
use traffic::{TrafIn, TrafOut};
use event::{CliEvent, ServEvent, ServEventId, CliEventId};
use event::{Event, CliEvent, ServEvent, ServEventId, CliEventId};

use conn::{Conn, Dispatched, DispatchEvent};

Expand Down Expand Up @@ -445,6 +446,21 @@ impl<'a> Runner<'a> {
}
}

/// Send a break to a session channel
///
/// `length` is in milliseconds, or
/// pass 0 as a default (to be interpreted by the remote implementation).
/// Otherwise length will be clamped to the range [500, 3000] ms.
/// Only call on a client session.
pub fn term_break(&mut self, chan: &ChanHandle, length: u32) -> Result<()> {
if self.is_client() {
let mut s = self.traf_out.sender(&mut self.keys);
self.conn.channels.term_break(chan.0, length, &mut s)
} else {
error::BadChannelData.fail()
}
}

pub(crate) fn cli_session_opener(&mut self, ch: ChanNum) -> Result<CliSessionOpener<'_, 'a>> {
let ch = self.conn.channels.get(ch)?;
let s = self.traf_out.sender(&mut self.keys);
Expand All @@ -460,6 +476,11 @@ impl<'a> Runner<'a> {
self.conn.fetch_cli_session_exit(payload)
}

pub(crate) fn fetch_cli_banner(&mut self) -> Result<event::Banner> {
let (payload, _seq) = self.traf_in.payload().trap()?;
self.conn.fetch_cli_banner(payload)
}

fn wake(&mut self) {
if self.is_input_ready() {
trace!("wake ready_input, waker {:?}", self.input_waker);
Expand Down
3 changes: 2 additions & 1 deletion src/sshnames.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Named SSH algorithms, methods, and extensions.
//!
//! Some identifiers are also listed directly in `packet.rs` derive attributes.
//! Some identifiers are also listed directly in `packet.rs` derive attributes,
//! for example [channel request identifiers](packets::ChannelReqType).
//! Packet numbers are listed in `packets.rs`.
//!
//! This module also serves as an index of SSH specifications.
Expand Down

0 comments on commit 59471c0

Please sign in to comment.