use log::error;
use ssh_encoding::Encode;
use tokio::sync::oneshot;
use crate::client::Session;
use crate::session::EncryptedState;
use crate::{map_err, msg, ChannelId, Disconnect, Pty, Sig};
impl Session {
fn channel_open_generic<F>(
&mut self,
kind: &[u8],
write_suffix: F,
) -> Result<ChannelId, crate::Error>
where
F: FnOnce(&mut Vec<u8>) -> Result<(), crate::Error>,
{
let result = if let Some(ref mut enc) = self.common.encrypted {
match enc.state {
EncryptedState::Authenticated => {
let sender_channel = enc.new_channel(
self.common.config.window_size,
self.common.config.maximum_packet_size,
);
push_packet!(enc.write, {
msg::CHANNEL_OPEN.encode(&mut enc.write)?;
kind.encode(&mut enc.write)?;
sender_channel.encode(&mut enc.write)?;
self.common
.config
.as_ref()
.window_size
.encode(&mut enc.write)?;
self.common
.config
.as_ref()
.maximum_packet_size
.encode(&mut enc.write)?;
write_suffix(&mut enc.write)?;
});
sender_channel
}
_ => return Err(crate::Error::NotAuthenticated),
}
} else {
return Err(crate::Error::Inconsistent);
};
Ok(result)
}
pub fn channel_open_session(&mut self) -> Result<ChannelId, crate::Error> {
self.channel_open_generic(b"session", |_| Ok(()))
}
pub fn channel_open_x11(
&mut self,
originator_address: &str,
originator_port: u32,
) -> Result<ChannelId, crate::Error> {
self.channel_open_generic(b"x11", |write| {
map_err!(originator_address.encode(write))?;
map_err!(originator_port.encode(write))?; Ok(())
})
}
pub fn channel_open_direct_tcpip(
&mut self,
host_to_connect: &str,
port_to_connect: u32,
originator_address: &str,
originator_port: u32,
) -> Result<ChannelId, crate::Error> {
self.channel_open_generic(b"direct-tcpip", |write| {
host_to_connect.encode(write)?;
port_to_connect.encode(write)?; originator_address.encode(write)?;
originator_port.encode(write)?; Ok(())
})
}
pub fn channel_open_direct_streamlocal(
&mut self,
socket_path: &str,
) -> Result<ChannelId, crate::Error> {
self.channel_open_generic(b"direct-streamlocal@openssh.com", |write| {
socket_path.encode(write)?;
"".encode(write)?; 0u32.encode(write)?; Ok(())
})
}
#[allow(clippy::too_many_arguments)]
pub fn request_pty(
&mut self,
channel: ChannelId,
want_reply: bool,
term: &str,
col_width: u32,
row_height: u32,
pix_width: u32,
pix_height: u32,
terminal_modes: &[(Pty, u32)],
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
map_err!(msg::CHANNEL_REQUEST.encode(&mut enc.write))?;
channel.recipient_channel.encode(&mut enc.write)?;
"pty-req".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
term.encode(&mut enc.write)?;
col_width.encode(&mut enc.write)?;
row_height.encode(&mut enc.write)?;
pix_width.encode(&mut enc.write)?;
pix_height.encode(&mut enc.write)?;
((1 + 5 * terminal_modes.len()) as u32).encode(&mut enc.write)?;
for &(code, value) in terminal_modes {
if code == Pty::TTY_OP_END {
continue;
}
(code as u8).encode(&mut enc.write)?;
value.encode(&mut enc.write)?;
}
(Pty::TTY_OP_END as u8).encode(&mut enc.write)?;
});
}
}
Ok(())
}
pub fn request_x11(
&mut self,
channel: ChannelId,
want_reply: bool,
single_connection: bool,
x11_authentication_protocol: &str,
x11_authentication_cookie: &str,
x11_screen_number: u32,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
msg::CHANNEL_REQUEST.encode(&mut enc.write)?;
channel.recipient_channel.encode(&mut enc.write)?;
"x11-req".encode(&mut enc.write)?;
enc.write.push(want_reply as u8);
enc.write.push(single_connection as u8);
x11_authentication_protocol.encode(&mut enc.write)?;
x11_authentication_cookie.encode(&mut enc.write)?;
x11_screen_number.encode(&mut enc.write)?;
});
}
}
Ok(())
}
pub fn set_env(
&mut self,
channel: ChannelId,
want_reply: bool,
variable_name: &str,
variable_value: &str,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
msg::CHANNEL_REQUEST.encode(&mut enc.write)?;
channel.recipient_channel.encode(&mut enc.write)?;
"env".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
variable_name.encode(&mut enc.write)?;
variable_value.encode(&mut enc.write)?;
});
}
}
Ok(())
}
pub fn request_shell(
&mut self,
want_reply: bool,
channel: ChannelId,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
msg::CHANNEL_REQUEST.encode(&mut enc.write)?;
channel.recipient_channel.encode(&mut enc.write)?;
"shell".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
});
}
}
Ok(())
}
pub fn exec(
&mut self,
channel: ChannelId,
want_reply: bool,
command: &[u8],
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
msg::CHANNEL_REQUEST.encode(&mut enc.write)?;
channel.recipient_channel.encode(&mut enc.write)?;
"exec".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
command.encode(&mut enc.write)?;
});
return Ok(());
}
}
error!("exec");
Ok(())
}
pub fn signal(&mut self, channel: ChannelId, signal: Sig) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
msg::CHANNEL_REQUEST.encode(&mut enc.write)?;
channel.recipient_channel.encode(&mut enc.write)?;
"signal".encode(&mut enc.write)?;
0u8.encode(&mut enc.write)?;
signal.name().encode(&mut enc.write)?;
});
}
}
Ok(())
}
pub fn request_subsystem(
&mut self,
want_reply: bool,
channel: ChannelId,
name: &str,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
msg::CHANNEL_REQUEST.encode(&mut enc.write)?;
channel.recipient_channel.encode(&mut enc.write)?;
"subsystem".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
name.encode(&mut enc.write)?;
});
}
}
Ok(())
}
pub fn window_change(
&mut self,
channel: ChannelId,
col_width: u32,
row_height: u32,
pix_width: u32,
pix_height: u32,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
msg::CHANNEL_REQUEST.encode(&mut enc.write)?;
channel.recipient_channel.encode(&mut enc.write)?;
"window-change".encode(&mut enc.write)?;
0u8.encode(&mut enc.write)?;
col_width.encode(&mut enc.write)?;
row_height.encode(&mut enc.write)?;
pix_width.encode(&mut enc.write)?;
pix_height.encode(&mut enc.write)?;
});
}
}
Ok(())
}
pub fn tcpip_forward(
&mut self,
reply_channel: Option<oneshot::Sender<Option<u32>>>,
address: &str,
port: u32,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
let want_reply = reply_channel.is_some();
if let Some(reply_channel) = reply_channel {
self.open_global_requests.push_back(
crate::session::GlobalRequestResponse::TcpIpForward(reply_channel),
);
}
push_packet!(enc.write, {
msg::GLOBAL_REQUEST.encode(&mut enc.write)?;
"tcpip-forward".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
address.encode(&mut enc.write)?;
port.encode(&mut enc.write)?;
});
}
Ok(())
}
pub fn cancel_tcpip_forward(
&mut self,
reply_channel: Option<oneshot::Sender<bool>>,
address: &str,
port: u32,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
let want_reply = reply_channel.is_some();
if let Some(reply_channel) = reply_channel {
self.open_global_requests.push_back(
crate::session::GlobalRequestResponse::CancelTcpIpForward(reply_channel),
);
}
push_packet!(enc.write, {
msg::GLOBAL_REQUEST.encode(&mut enc.write)?;
"cancel-tcpip-forward".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
address.encode(&mut enc.write)?;
port.encode(&mut enc.write)?;
});
}
Ok(())
}
pub fn streamlocal_forward(
&mut self,
reply_channel: Option<oneshot::Sender<bool>>,
socket_path: &str,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
let want_reply = reply_channel.is_some();
if let Some(reply_channel) = reply_channel {
self.open_global_requests.push_back(
crate::session::GlobalRequestResponse::StreamLocalForward(reply_channel),
);
}
push_packet!(enc.write, {
msg::GLOBAL_REQUEST.encode(&mut enc.write)?;
"streamlocal-forward@openssh.com".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
socket_path.encode(&mut enc.write)?;
});
}
Ok(())
}
pub fn cancel_streamlocal_forward(
&mut self,
reply_channel: Option<oneshot::Sender<bool>>,
socket_path: &str,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
let want_reply = reply_channel.is_some();
if let Some(reply_channel) = reply_channel {
self.open_global_requests.push_back(
crate::session::GlobalRequestResponse::CancelStreamLocalForward(reply_channel),
);
}
push_packet!(enc.write, {
msg::GLOBAL_REQUEST.encode(&mut enc.write)?;
"cancel-streamlocal-forward@openssh.com".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
socket_path.encode(&mut enc.write)?;
});
}
Ok(())
}
pub fn send_keepalive(&mut self, want_reply: bool) -> Result<(), crate::Error> {
self.open_global_requests
.push_back(crate::session::GlobalRequestResponse::Keepalive);
if let Some(ref mut enc) = self.common.encrypted {
push_packet!(enc.write, {
msg::GLOBAL_REQUEST.encode(&mut enc.write)?;
"keepalive@openssh.com".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
});
}
Ok(())
}
pub fn send_ping(&mut self, reply_channel: oneshot::Sender<()>) -> Result<(), crate::Error> {
self.open_global_requests
.push_back(crate::session::GlobalRequestResponse::Ping(reply_channel));
if let Some(ref mut enc) = self.common.encrypted {
push_packet!(enc.write, {
msg::GLOBAL_REQUEST.encode(&mut enc.write)?;
"keepalive@openssh.com".encode(&mut enc.write)?;
(true as u8).encode(&mut enc.write)?;
});
}
Ok(())
}
pub fn no_more_sessions(&mut self, want_reply: bool) -> Result<(), crate::Error> {
self.open_global_requests
.push_back(crate::session::GlobalRequestResponse::NoMoreSessions);
if let Some(ref mut enc) = self.common.encrypted {
push_packet!(enc.write, {
msg::GLOBAL_REQUEST.encode(&mut enc.write)?;
"no-more-sessions@openssh.com".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
});
}
Ok(())
}
pub fn data(&mut self, channel: ChannelId, data: impl Into<bytes::Bytes>) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
enc.data(channel, data, self.kex.active())
} else {
unreachable!()
}
}
pub fn eof(&mut self, channel: ChannelId) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
enc.eof(channel)
} else {
unreachable!()
}
}
pub fn close(&mut self, channel: ChannelId) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
enc.close(channel)
} else {
unreachable!()
}
}
pub fn extended_data(
&mut self,
channel: ChannelId,
ext: u32,
data: impl Into<bytes::Bytes>,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
enc.extended_data(channel, ext, data, self.kex.active())
} else {
unreachable!()
}
}
pub fn agent_forward(
&mut self,
channel: ChannelId,
want_reply: bool,
) -> Result<(), crate::Error> {
if let Some(ref mut enc) = self.common.encrypted {
if let Some(channel) = enc.channels.get(&channel) {
push_packet!(enc.write, {
msg::CHANNEL_REQUEST.encode(&mut enc.write)?;
channel.recipient_channel.encode(&mut enc.write)?;
"auth-agent-req@openssh.com".encode(&mut enc.write)?;
(want_reply as u8).encode(&mut enc.write)?;
});
}
}
Ok(())
}
pub fn disconnect(
&mut self,
reason: Disconnect,
description: &str,
language_tag: &str,
) -> Result<(), crate::Error> {
self.common.disconnect(reason, description, language_tag)
}
pub fn has_pending_data(&self, channel: ChannelId) -> bool {
if let Some(ref enc) = self.common.encrypted {
enc.has_pending_data(channel)
} else {
false
}
}
pub fn sender_window_size(&self, channel: ChannelId) -> usize {
if let Some(ref enc) = self.common.encrypted {
enc.sender_window_size(channel)
} else {
0
}
}
pub fn remote_sshid(&self) -> &[u8] {
&self.common.remote_sshid
}
}