Skip to content

Commit

Permalink
Support gating libssh-rs and ssh2 behind features of same name
Browse files Browse the repository at this point in the history
  • Loading branch information
chipsenkbeil authored and wez committed Jan 10, 2022
1 parent b3987be commit 1f17416
Show file tree
Hide file tree
Showing 15 changed files with 328 additions and 126 deletions.
7 changes: 4 additions & 3 deletions wezterm-ssh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ documentation = "https://docs.rs/wezterm-ssh"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = ["libssh-rs", "ssh2"]
vendored-openssl = ["ssh2/vendored-openssl", "libssh-rs/vendored-openssl"]

[dependencies]
Expand All @@ -26,9 +27,9 @@ log = "0.4"
portable-pty = { version="0.7", path = "../pty" }
regex = "1"
smol = "1.2"
ssh2 = {version="0.9.3", features=["openssl-on-win32"]}
libssh-rs = {version="0.1.2", features=["vendored"], git="https://github.com/wez/libssh-rs.git"}
#libssh-rs = {path="../../libssh-rs/libssh-rs", features=["vendored"]}
ssh2 = {version="0.9.3", features=["openssl-on-win32"], optional = true}
libssh-rs = {version="0.1.2", features=["vendored"], git="https://github.com/wez/libssh-rs.git", optional = true}
#libssh-rs = {path="../../libssh-rs/libssh-rs", features=["vendored"], optional = true}
thiserror = "1.0"

# Not used directly, but is used to centralize the openssl vendor feature selection
Expand Down
16 changes: 11 additions & 5 deletions wezterm-ssh/src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use crate::session::SessionEvent;
use anyhow::Context;
use libssh_rs as libssh;
use smol::channel::{bounded, Sender};
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};

#[derive(Debug)]
pub struct AuthenticationPrompt {
Expand All @@ -30,6 +27,7 @@ impl AuthenticationEvent {
}

impl crate::sessioninner::SessionInner {
#[cfg(feature = "ssh2")]
fn agent_auth(&mut self, sess: &ssh2::Session, user: &str) -> anyhow::Result<bool> {
if let Some(only) = self.config.get("identitiesonly") {
if only == "yes" {
Expand All @@ -55,12 +53,15 @@ impl crate::sessioninner::SessionInner {
Ok(false)
}

#[cfg(feature = "ssh2")]
fn pubkey_auth(
&mut self,
sess: &ssh2::Session,
user: &str,
host: &str,
) -> anyhow::Result<bool> {
use std::path::{Path, PathBuf};

if let Some(files) = self.config.get("identityfile") {
for file in files.split_whitespace() {
let pubkey: PathBuf = format!("{}.pub", file).into();
Expand Down Expand Up @@ -127,7 +128,9 @@ impl crate::sessioninner::SessionInner {
Ok(false)
}

pub fn authenticate_libssh(&mut self, sess: &libssh::Session) -> anyhow::Result<()> {
#[cfg(feature = "libssh-rs")]
pub fn authenticate_libssh(&mut self, sess: &libssh_rs::Session) -> anyhow::Result<()> {
use std::collections::HashMap;
let tx = self.tx_event.clone();

// Set the callback for pubkey auth
Expand All @@ -153,7 +156,7 @@ impl crate::sessioninner::SessionInner {
Ok(answers.remove(0))
});

use libssh::{AuthMethods, AuthStatus};
use libssh_rs::{AuthMethods, AuthStatus};
match sess.userauth_none(None)? {
AuthStatus::Success => return Ok(()),
_ => {}
Expand Down Expand Up @@ -249,12 +252,15 @@ impl crate::sessioninner::SessionInner {
}
}

#[cfg(feature = "ssh2")]
pub fn authenticate(
&mut self,
sess: &ssh2::Session,
user: &str,
host: &str,
) -> anyhow::Result<()> {
use std::collections::HashSet;

loop {
if sess.authenticated() {
return Ok(());
Expand Down
42 changes: 39 additions & 3 deletions wezterm-ssh/src/channelwrap.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use crate::pty::{NewPty, ResizePty};
use libssh_rs as libssh;
use portable_pty::ExitStatus;

pub(crate) enum ChannelWrap {
#[cfg(feature = "ssh2")]
Ssh2(ssh2::Channel),
LibSsh(libssh::Channel),

#[cfg(feature = "libssh-rs")]
LibSsh(libssh_rs::Channel),
}

#[cfg(feature = "ssh2")]
fn has_signal(chan: &ssh2::Channel) -> Option<ssh2::ExitSignal> {
if let Ok(sig) = chan.exit_signal() {
if sig.exit_signal.is_some() {
Expand All @@ -19,6 +22,7 @@ fn has_signal(chan: &ssh2::Channel) -> Option<ssh2::ExitSignal> {
impl ChannelWrap {
pub fn exit_status(&mut self) -> Option<ExitStatus> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => {
if chan.eof() && chan.wait_close().is_ok() {
if let Some(_sig) = has_signal(chan) {
Expand All @@ -32,6 +36,8 @@ impl ChannelWrap {
None
}
}

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => {
if chan.is_eof() {
if let Some(status) = chan.get_exit_status() {
Expand All @@ -45,7 +51,10 @@ impl ChannelWrap {

pub fn reader(&mut self, idx: usize) -> Box<dyn std::io::Read + '_> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => Box::new(chan.stream(idx as i32)),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => match idx {
0 => Box::new(chan.stdout()),
1 => Box::new(chan.stderr()),
Expand All @@ -56,16 +65,22 @@ impl ChannelWrap {

pub fn writer(&mut self) -> Box<dyn std::io::Write + '_> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => Box::new(chan),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => Box::new(chan.stdin()),
}
}

pub fn close(&mut self) {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => {
let _ = chan.close();
}

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => {
let _ = chan.close();
}
Expand All @@ -74,6 +89,7 @@ impl ChannelWrap {

pub fn request_pty(&mut self, newpty: &NewPty) -> anyhow::Result<()> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => Ok(chan.request_pty(
&newpty.term,
None,
Expand All @@ -84,6 +100,8 @@ impl ChannelWrap {
newpty.size.pixel_height.into(),
)),
)?),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => Ok(chan.request_pty(
&newpty.term,
newpty.size.cols.into(),
Expand All @@ -94,42 +112,60 @@ impl ChannelWrap {

pub fn request_env(&mut self, name: &str, value: &str) -> anyhow::Result<()> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => Ok(chan.setenv(name, value)?),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => Ok(chan.request_env(name, value)?),
}
}

pub fn request_exec(&mut self, command_line: &str) -> anyhow::Result<()> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => Ok(chan.exec(command_line)?),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => Ok(chan.request_exec(command_line)?),
}
}

pub fn request_shell(&mut self) -> anyhow::Result<()> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => Ok(chan.shell()?),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => Ok(chan.request_shell()?),
}
}

pub fn resize_pty(&mut self, resize: &ResizePty) -> anyhow::Result<()> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(chan) => Ok(chan.request_pty_size(
resize.size.cols.into(),
resize.size.rows.into(),
Some(resize.size.pixel_width.into()),
Some(resize.size.pixel_height.into()),
)?),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => {
Ok(chan.change_pty_size(resize.size.cols.into(), resize.size.rows.into())?)
}
}
}

pub fn send_signal(&mut self, signame: &str) -> anyhow::Result<()> {
pub fn send_signal(
&mut self,
#[cfg_attr(not(feature = "libssh-rs"), allow(unused_variables))] signame: &str,
) -> anyhow::Result<()> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(_) => Ok(()),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(chan) => Ok(chan.request_send_signal(signame)?),
}
}
Expand Down
11 changes: 8 additions & 3 deletions wezterm-ssh/src/dirwrap.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
use crate::sftp::types::Metadata;
use crate::sftp::{SftpChannelError, SftpChannelResult};
use camino::Utf8PathBuf;
use libssh_rs as libssh;
use std::convert::TryFrom;

pub(crate) enum DirWrap {
#[cfg(feature = "ssh2")]
Ssh2(ssh2::File),
LibSsh(libssh::SftpDir),

#[cfg(feature = "libssh-rs")]
LibSsh(libssh_rs::SftpDir),
}

impl DirWrap {
pub fn read_dir(&mut self) -> SftpChannelResult<(Utf8PathBuf, Metadata)> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(file) => {
use std::convert::TryFrom;
file.readdir()
.map_err(SftpChannelError::from)
.and_then(|(path, stat)| match Utf8PathBuf::try_from(path) {
Expand All @@ -23,6 +26,8 @@ impl DirWrap {
))),
})
}

#[cfg(feature = "libssh-rs")]
Self::LibSsh(dir) => match dir.read_dir() {
None => Err(SftpChannelError::from(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
Expand Down
34 changes: 28 additions & 6 deletions wezterm-ssh/src/filewrap.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,45 @@
use crate::sftp::types::Metadata;
use crate::sftp::{SftpChannelError, SftpChannelResult};
use libssh_rs as libssh;
use std::io::Write;

pub(crate) enum FileWrap {
#[cfg(feature = "ssh2")]
Ssh2(ssh2::File),
LibSsh(libssh::SftpFile),

#[cfg(feature = "libssh-rs")]
LibSsh(libssh_rs::SftpFile),
}

impl FileWrap {
pub fn reader(&mut self) -> Box<dyn std::io::Read + '_> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(file) => Box::new(file),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(file) => Box::new(file),
}
}

pub fn writer(&mut self) -> Box<dyn std::io::Write + '_> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(file) => Box::new(file),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(file) => Box::new(file),
}
}

pub fn set_metadata(&mut self, metadata: Metadata) -> SftpChannelResult<()> {
pub fn set_metadata(
&mut self,
#[cfg_attr(not(feature = "ssh2"), allow(unused_variables))] metadata: Metadata,
) -> SftpChannelResult<()> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(file) => Ok(file.setstat(metadata.into())?),
Self::LibSsh(_file) => Err(libssh::Error::fatal(

#[cfg(feature = "libssh-rs")]
Self::LibSsh(_file) => Err(libssh_rs::Error::fatal(
"FileWrap::set_metadata not implemented for libssh::SftpFile",
)
.into()),
Expand All @@ -35,7 +48,10 @@ impl FileWrap {

pub fn metadata(&mut self) -> SftpChannelResult<Metadata> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(file) => Ok(file.stat().map(Metadata::from)?),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(file) => file
.metadata()
.map(Metadata::from)
Expand All @@ -45,8 +61,14 @@ impl FileWrap {

pub fn fsync(&mut self) -> SftpChannelResult<()> {
match self {
#[cfg(feature = "ssh2")]
Self::Ssh2(file) => file.fsync().map_err(SftpChannelError::from),
Self::LibSsh(file) => Ok(file.flush()?),

#[cfg(feature = "libssh-rs")]
Self::LibSsh(file) => {
use std::io::Write;
Ok(file.flush()?)
}
}
}
}
Loading

0 comments on commit 1f17416

Please sign in to comment.