Skip to content

Commit 490b830

Browse files
committed
Merge Environment variable passing support
From Github #35
2 parents 351e2ef + 8948861 commit 490b830

File tree

7 files changed

+128
-5
lines changed

7 files changed

+128
-5
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ mlkem = ["dep:ml-kem"]
7676
openssh-key = ["ssh-key"]
7777
# implements embedded_io::Error for sunset::Error
7878
embedded-io = ["dep:embedded-io"]
79-
8079
# Arbitrary for fuzzing. std is required for derive(Arbitrary)
8180
arbitrary = ["dep:arbitrary", "std"]
8281

demo/common/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ where
178178
let ad = Ipv4Address::from_bits(ad);
179179
let prefix = SSHDecode::dec(s)?;
180180
if prefix > 32 {
181-
// emabassy panics, so test it here
181+
// embassy panics, so test it here
182182
return Err(WireError::PacketWrong);
183183
}
184184
let gw: Option<u32> = dec_option(s)?;

demo/common/src/server.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ impl DemoCommon {
118118
ServEvent::PubkeyAuth(a) => self.handle_pubkey(a),
119119
ServEvent::OpenSession(a) => self.open_session(a),
120120
ServEvent::SessionPty(a) => a.succeed(),
121+
ServEvent::SessionEnv(a) => a.succeed(),
121122
ServEvent::SessionSubsystem(a) => {
122123
info!("Ignored request for subsystem '{}'", a.command()?);
123124
Ok(())

src/channel.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,27 @@ impl Channels {
569569
_ => Err(Error::bug()),
570570
}
571571
}
572+
573+
pub fn fetch_env_name<'p>(&self, p: &Packet<'p>) -> Result<TextString<'p>> {
574+
match p {
575+
Packet::ChannelRequest(ChannelRequest {
576+
req: ChannelReqType::Environment(packets::Environment { name, .. }),
577+
..
578+
}) => Ok(name.clone()),
579+
_ => Err(Error::bug()),
580+
}
581+
}
582+
583+
pub fn fetch_env_value<'p>(&self, p: &Packet<'p>) -> Result<TextString<'p>> {
584+
match p {
585+
Packet::ChannelRequest(ChannelRequest {
586+
req:
587+
ChannelReqType::Environment(packets::Environment { name: _, value }),
588+
..
589+
}) => Ok(value.clone()),
590+
_ => Err(Error::bug()),
591+
}
592+
}
572593
}
573594

574595
#[derive(Debug, Clone, Copy)]
@@ -900,6 +921,9 @@ impl Channel {
900921
ChannelReqType::Pty(_) => {
901922
Ok(DispatchEvent::ServEvent(ServEventId::SessionPty { num }))
902923
}
924+
ChannelReqType::Environment(_) => {
925+
Ok(DispatchEvent::ServEvent(ServEventId::Environment { num }))
926+
}
903927
_ => {
904928
if let ChannelReqType::Unknown(u) = &p.req {
905929
warn!("Unknown channel req type \"{}\"", u)

src/event.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ pub enum ServEvent<'g, 'a> {
301301
///
302302
/// TODO details
303303
SessionPty(ServPtyRequest<'g, 'a>),
304+
/// Server has received one environment variable.
305+
/// Note: input strings are not sanitised.
306+
SessionEnv(ServEnvironmentRequest<'g, 'a>),
304307

305308
/// The SSH session is no longer running
306309
#[allow(unused)]
@@ -326,6 +329,7 @@ impl Debug for ServEvent<'_, '_> {
326329
Self::SessionExec(_) => "SessionExec",
327330
Self::SessionSubsystem(_) => "SessionSubsystem",
328331
Self::SessionPty(_) => "SessionPty",
332+
Self::SessionEnv(_) => "Environment",
329333
Self::Defunct => "Defunct",
330334
Self::PollAgain => "PollAgain",
331335
};
@@ -745,7 +749,7 @@ impl<'g, 'a> ServExecRequest<'g, 'a> {
745749
self.raw_command()?.as_str()
746750
}
747751

748-
pub fn raw_command(&self) -> Result<TextString<'_>> {
752+
fn raw_command(&self) -> Result<TextString<'_>> {
749753
self.runner.fetch_servcommand()
750754
}
751755

@@ -847,6 +851,69 @@ impl Drop for ServPtyRequest<'_, '_> {
847851
}
848852
}
849853

854+
/// An environment variable request
855+
///
856+
pub struct ServEnvironmentRequest<'g, 'a> {
857+
runner: &'g mut Runner<'a, Server>,
858+
num: ChanNum,
859+
done: bool,
860+
}
861+
862+
impl<'g, 'a> ServEnvironmentRequest<'g, 'a> {
863+
fn new(runner: &'g mut Runner<'a, Server>, num: ChanNum) -> Self {
864+
Self { runner, num, done: false }
865+
}
866+
867+
/// Indicate that the request succeeded.
868+
///
869+
/// Note that if the peer didn't request a reply, this call
870+
/// will not do anything.
871+
pub fn succeed(mut self) -> Result<()> {
872+
self.done = true;
873+
self.runner.resume_chanreq(true)
874+
}
875+
876+
/// Indicate that the request failed.
877+
///
878+
/// Note that if the peer didn't request a reply, this call
879+
/// will not do anything.
880+
/// Does not need to be called explicitly, also occurs on drop without `accept()`
881+
pub fn fail(mut self) -> Result<()> {
882+
self.done = true;
883+
self.runner.resume_chanreq(false)
884+
}
885+
886+
/// Return the associated channel number.
887+
///
888+
/// This will correspond to a `ChanHandle::num()`
889+
/// from a previous [`ServOpenSession`] event.
890+
pub fn channel(&self) -> ChanNum {
891+
self.num
892+
}
893+
894+
/// Retrieve the name of the environment variable (from NAME=VALUE pair).
895+
pub fn name(&self) -> Result<&str> {
896+
self.raw_name()?.as_str()
897+
}
898+
899+
/// Retrieve the raw name of the environment variable.
900+
fn raw_name(&self) -> Result<TextString<'_>> {
901+
self.runner.fetch_env_name()
902+
}
903+
904+
/// Retrieve the value of the environment variable (from NAME=VALUE pair).
905+
pub fn value(&self) -> Result<&str> {
906+
self.raw_value()?.as_str()
907+
}
908+
909+
/// Retrieve the raw value of the environment variable.
910+
fn raw_value(&self) -> Result<TextString<'_>> {
911+
self.runner.fetch_env_value()
912+
}
913+
914+
// TODO: does the app care about wantreply?
915+
}
916+
850917
// Only small values should be stored inline.
851918
// Larger state is retrieved from the current packet via Runner::fetch_*()
852919
#[derive(Debug, Clone)]
@@ -872,6 +939,9 @@ pub(crate) enum ServEventId {
872939
SessionPty {
873940
num: ChanNum,
874941
},
942+
Environment {
943+
num: ChanNum,
944+
},
875945
#[allow(unused)]
876946
Defunct,
877947
// TODO:
@@ -925,6 +995,10 @@ impl ServEventId {
925995
debug_assert!(matches!(p, Some(Packet::ChannelRequest(_))));
926996
Ok(ServEvent::SessionPty(ServPtyRequest::new(runner, num)))
927997
}
998+
Self::Environment { num } => {
999+
debug_assert!(matches!(p, Some(Packet::ChannelRequest(_))));
1000+
Ok(ServEvent::SessionEnv(ServEnvironmentRequest::new(runner, num)))
1001+
}
9281002
Self::Defunct => Ok(ServEvent::Defunct),
9291003
}
9301004
}
@@ -942,6 +1016,7 @@ impl ServEventId {
9421016
| Self::SessionShell { .. }
9431017
| Self::SessionExec { .. }
9441018
| Self::SessionSubsystem { .. }
1019+
| Self::Environment { .. }
9451020
| Self::SessionPty { .. } => true,
9461021
}
9471022
}

src/packets.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! A [`Packet`] can be encoded/decoded to the
44
//! SSH Binary Packet Protocol using [`sshwire`].
5-
//! SSH packet format is described in [RFC4253](https://tools.ietf.org/html/rfc5643) SSH Transport
5+
//! SSH packet format is described in [RFC4253](https://tools.ietf.org/html/rfc4253#section-6) SSH Transport
66
77
#[allow(unused_imports)]
88
use {
@@ -722,6 +722,8 @@ pub enum ChannelReqType<'a> {
722722
Subsystem(Subsystem<'a>),
723723
#[sshwire(variant = "window-change")]
724724
WinChange(WinChange),
725+
#[sshwire(variant = "env")]
726+
Environment(Environment<'a>),
725727
#[sshwire(variant = "signal")]
726728
Signal(Signal<'a>),
727729
#[sshwire(variant = "exit-status")]
@@ -736,7 +738,6 @@ pub enum ChannelReqType<'a> {
736738
// Other requests that aren't implemented at present:
737739
738740
// x11-req
739-
// env
740741
// xon-xoff
741742
#[sshwire(unknown)]
742743
Unknown(Unknown<'a>),
@@ -777,6 +778,14 @@ pub struct WinChange {
777778
pub height: u32,
778779
}
779780

781+
/// An environment variable
782+
#[derive(Debug, SSHEncode, SSHDecode)]
783+
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
784+
pub struct Environment<'a> {
785+
pub name: TextString<'a>,
786+
pub value: TextString<'a>,
787+
}
788+
780789
/// A unix signal channel request
781790
#[derive(Debug, SSHEncode, SSHDecode)]
782791
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]

src/runner.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ impl<'a, CS: CliServ> Runner<'a, CS> {
778778
| DispatchEvent::ServEvent(ServEventId::SessionExec { .. })
779779
| DispatchEvent::ServEvent(ServEventId::SessionSubsystem { .. })
780780
| DispatchEvent::ServEvent(ServEventId::SessionPty { .. })
781+
| DispatchEvent::ServEvent(ServEventId::Environment { .. })
781782
));
782783
}
783784

@@ -800,6 +801,20 @@ impl<'a, CS: CliServ> Runner<'a, CS> {
800801
let p = self.conn.packet(payload)?;
801802
self.conn.channels.fetch_servcommand(&p)
802803
}
804+
805+
pub(crate) fn fetch_env_name(&self) -> Result<TextString<'_>> {
806+
Self::check_chanreq(&self.resume_event);
807+
let (payload, _seq) = self.traf_in.payload().trap()?;
808+
let p = self.conn.packet(payload)?;
809+
self.conn.channels.fetch_env_name(&p)
810+
}
811+
812+
pub(crate) fn fetch_env_value(&self) -> Result<TextString<'_>> {
813+
Self::check_chanreq(&self.resume_event);
814+
let (payload, _seq) = self.traf_in.payload().trap()?;
815+
let p = self.conn.packet(payload)?;
816+
self.conn.channels.fetch_env_value(&p)
817+
}
803818
}
804819

805820
/// Sets a waker, waking any existing waker

0 commit comments

Comments
 (0)