Skip to content

Commit 26aae26

Browse files
committed
added named pipe support for AgentClient and .dynamic()
1 parent ed1fec1 commit 26aae26

File tree

3 files changed

+44
-14
lines changed

3 files changed

+44
-14
lines changed

pageant/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
//!
55
//! This crate only implements the transport, not the actual SSH agent protocol.
66
7-
#[cfg(target_os = "windows")]
7+
#[cfg(windows)]
88
mod pageant_impl;
99

10-
#[cfg(target_os = "windows")]
10+
#[cfg(windows)]
1111
pub use pageant_impl::*;

russh-keys/src/agent/client.rs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,29 @@ use crate::encoding::{Encoding, Reader};
1111
use crate::key::{PublicKey, SignatureHash};
1212
use crate::{key, protocol, Error, PublicKeyBase64};
1313

14+
pub trait AgentStream: AsyncRead + AsyncWrite {}
15+
16+
impl<S: AsyncRead + AsyncWrite> AgentStream for S {}
17+
1418
/// SSH agent client.
15-
pub struct AgentClient<S: AsyncRead + AsyncWrite> {
19+
pub struct AgentClient<S: AgentStream> {
1620
stream: S,
1721
buf: CryptoVec,
1822
}
1923

24+
impl<S: AgentStream + Send + Unpin + 'static> AgentClient<S> {
25+
/// Wraps the internal stream in a Box<dyn _>, allowing different client
26+
/// implementations to have the same type
27+
pub fn dynamic(self) -> AgentClient<Box<dyn AgentStream + Send + Unpin>> {
28+
AgentClient {
29+
stream: Box::new(self.stream),
30+
buf: self.buf,
31+
}
32+
}
33+
}
34+
2035
// https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-4.1
21-
impl<S: AsyncRead + AsyncWrite + Unpin> AgentClient<S> {
36+
impl<S: AgentStream + Unpin> AgentClient<S> {
2237
/// Build a future that connects to an SSH agent via the provided
2338
/// stream (on Unix, usually a Unix-domain socket).
2439
pub fn connect(stream: S) -> Self {
@@ -58,24 +73,39 @@ impl AgentClient<tokio::net::UnixStream> {
5873
}
5974
}
6075

61-
#[cfg(target_os = "windows")]
76+
#[cfg(windows)]
77+
const ERROR_PIPE_BUSY: u32 = 231u32;
78+
79+
#[cfg(windows)]
6280
impl AgentClient<pageant::PageantStream> {
6381
/// Connect to a running Pageant instance
6482
pub async fn connect_pageant() -> Self {
6583
Self::connect(pageant::PageantStream::new())
6684
}
6785
}
6886

69-
#[cfg(not(unix))]
70-
impl AgentClient<tokio::net::TcpStream> {
71-
/// Build a future that connects to an SSH agent via the provided
72-
/// stream (on Unix, usually a Unix-domain socket).
73-
pub async fn connect_env() -> Result<Self, Error> {
74-
Err(Error::AgentFailure)
87+
#[cfg(windows)]
88+
impl AgentClient<tokio::net::windows::named_pipe::NamedPipeClient> {
89+
/// Connect to an SSH agent via a Windows named pipe
90+
pub async fn connect_named_pipe<P: AsRef<std::ffi::OsStr>>(path: P) -> Result<Self, Error> {
91+
let stream = loop {
92+
match tokio::net::windows::named_pipe::ClientOptions::new().open(path.as_ref()) {
93+
Ok(client) => break client,
94+
Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => (),
95+
Err(e) => return Err(e.into()),
96+
}
97+
98+
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
99+
};
100+
101+
Ok(AgentClient {
102+
stream,
103+
buf: CryptoVec::new(),
104+
})
75105
}
76106
}
77107

78-
impl<S: AsyncRead + AsyncWrite + Unpin> AgentClient<S> {
108+
impl<S: AgentStream + Unpin> AgentClient<S> {
79109
async fn read_response(&mut self) -> Result<(), Error> {
80110
// Writing the message
81111
self.stream.write_all(&self.buf).await?;

russh-keys/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ mod backend;
9494
#[path = "backend_rust.rs"]
9595
mod backend;
9696

97-
/// A module to write SSH agent.
97+
/// OpenSSH agent protocol implementation
9898
pub mod agent;
9999

100100
#[derive(Debug, Error)]
@@ -191,7 +191,7 @@ pub enum Error {
191191
#[cfg(feature = "legacy-ed25519-pkcs8-parser")]
192192
LegacyASN1(::yasna::ASN1Error),
193193

194-
#[cfg(target_os = "windows")]
194+
#[cfg(windows)]
195195
#[error("Pageant: {0}")]
196196
Pageant(#[from] pageant::Error),
197197
}

0 commit comments

Comments
 (0)