diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index f7301785fd2..e0e40cf148f 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -3643,6 +3643,7 @@ dependencies = [ "p256", "p384", "p521", + "pin-project", "rsa 0.10.0-rc.8", "sha2 0.10.9", "signature 3.0.0-rc.4", diff --git a/apps/desktop/desktop_native/ssh_agent/Cargo.toml b/apps/desktop/desktop_native/ssh_agent/Cargo.toml index c1a3d07b756..ad3ce1ec630 100644 --- a/apps/desktop/desktop_native/ssh_agent/Cargo.toml +++ b/apps/desktop/desktop_native/ssh_agent/Cargo.toml @@ -24,6 +24,7 @@ inout = { version = "=0.2.0-rc.6" } homedir = { workspace = true } log = { workspace = true } rsa = { version = "=0.10.0-rc.8", features = ["sha2"] } +pin-project = { workspace = true } sha2 = "0.10.9" ssh-encoding = "=0.3.0-rc.2" ssh-key = { version = "=0.7.0-rc.3", features = [ diff --git a/apps/desktop/desktop_native/ssh_agent/src/agent/agent.rs b/apps/desktop/desktop_native/ssh_agent/src/agent/agent.rs index 81d16e333ce..7cafb826d5c 100644 --- a/apps/desktop/desktop_native/ssh_agent/src/agent/agent.rs +++ b/apps/desktop/desktop_native/ssh_agent/src/agent/agent.rs @@ -57,6 +57,10 @@ impl BitwardenDesktopAgent { pub fn is_running(&self) -> bool { !self.cancellation_token.is_cancelled() } + + pub fn cancellation_token(&self) -> CancellationToken { + self.cancellation_token.clone() + } } impl Agent for &BitwardenDesktopAgent { diff --git a/apps/desktop/desktop_native/ssh_agent/src/agent/platform.rs b/apps/desktop/desktop_native/ssh_agent/src/agent/platform.rs index 3ac68841799..cfc6ea9592f 100644 --- a/apps/desktop/desktop_native/ssh_agent/src/agent/platform.rs +++ b/apps/desktop/desktop_native/ssh_agent/src/agent/platform.rs @@ -1,7 +1,4 @@ -use homedir::my_home; -use tracing::info; - -use crate::{agent::BitwardenDesktopAgent, transport::unix_listener_stream::UnixListenerStream}; +use crate::{agent::BitwardenDesktopAgent, transport::named_pipe_listener_stream::NamedPipeServerStream}; pub struct PlatformListener {} @@ -16,6 +13,11 @@ impl PlatformListener { { Self::spawn_macos_listeners(agent); } + + #[cfg(target_os = "windows")] + { + Self::spawn_windows_listeners(agent); + } } #[cfg(target_os = "linux")] @@ -64,4 +66,12 @@ impl PlatformListener { tokio::spawn(UnixListenerStream::listen(path, agent)); } + + #[cfg(target_os = "windows")] + pub fn spawn_windows_listeners(agent: BitwardenDesktopAgent) { + tokio::spawn(async move { + const PIPE_NAME: &str = r"\\.\pipe\openssh-ssh-agent"; + tokio::spawn(NamedPipeServerStream::listen(PIPE_NAME.to_string(), agent)); + }); + } } diff --git a/apps/desktop/desktop_native/ssh_agent/src/transport/mod.rs b/apps/desktop/desktop_native/ssh_agent/src/transport/mod.rs index 74fbc4af514..cdce1ce3be1 100644 --- a/apps/desktop/desktop_native/ssh_agent/src/transport/mod.rs +++ b/apps/desktop/desktop_native/ssh_agent/src/transport/mod.rs @@ -1,4 +1,5 @@ #[cfg(windows)] -mod named_pipe_listener_stream; -pub mod peer_info; +pub mod named_pipe_listener_stream; +#[cfg(not(windows))] pub mod unix_listener_stream; +pub mod peer_info; diff --git a/apps/desktop/desktop_native/ssh_agent/src/transport/named_pipe_listener_stream.rs b/apps/desktop/desktop_native/ssh_agent/src/transport/named_pipe_listener_stream.rs index cb10e873a33..7861fdc49a9 100644 --- a/apps/desktop/desktop_native/ssh_agent/src/transport/named_pipe_listener_stream.rs +++ b/apps/desktop/desktop_native/ssh_agent/src/transport/named_pipe_listener_stream.rs @@ -3,23 +3,17 @@ use std::os::windows::prelude::AsRawHandle as _; use std::{ io, pin::Pin, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, task::{Context, Poll}, }; use tokio::{ net::windows::named_pipe::{NamedPipeServer, ServerOptions}, select, }; -use tokio_util::sync::CancellationToken; use tracing::{error, info}; use windows::Win32::{Foundation::HANDLE, System::Pipes::GetNamedPipeClientProcessId}; -use crate::ssh_agent::peerinfo::{self, models::PeerInfo}; - -const PIPE_NAME: &str = r"\\.\pipe\openssh-ssh-agent"; +use crate::agent::BitwardenDesktopAgent; +use crate::transport::peer_info::PeerInfo; #[pin_project::pin_project] pub struct NamedPipeServerStream { @@ -27,30 +21,32 @@ pub struct NamedPipeServerStream { } impl NamedPipeServerStream { - // FIXME: Remove unwraps! They panic and terminate the whole application. - #[allow(clippy::unwrap_used)] - pub fn new(cancellation_token: CancellationToken, is_running: Arc) -> Self { + pub async fn listen( + pipe_name: String, + agent: BitwardenDesktopAgent, + ) -> Result { + info!("Starting SSH Named Pipe listener"); let (tx, rx) = tokio::sync::mpsc::channel(16); + tokio::spawn(async move { - info!("Creating named pipe server on {}", PIPE_NAME); - let mut listener = match ServerOptions::new().create(PIPE_NAME) { + info!("Creating named pipe server on {}", pipe_name.clone()); + let mut listener = match ServerOptions::new().create(pipe_name.clone()) { Ok(pipe) => pipe, Err(e) => { error!(error = %e, "Encountered an error creating the first pipe. The system's openssh service must likely be disabled"); - cancellation_token.cancel(); - is_running.store(false, Ordering::Relaxed); return; } }; + let cancellation_token = agent.cancellation_token(); loop { info!("Waiting for connection"); select! { _ = cancellation_token.cancelled() => { - info!("[SSH Agent Native Module] Cancellation token triggered, stopping named pipe server"); + info!("Cancellation token triggered, stopping named pipe server"); break; } _ = listener.connect() => { - info!("[SSH Agent Native Module] Incoming connection"); + info!("Incoming connection"); let handle = HANDLE(listener.as_raw_handle()); let mut pid = 0; unsafe { @@ -60,23 +56,14 @@ impl NamedPipeServerStream { } }; - let peer_info = peerinfo::gather::get_peer_info(pid); - let peer_info = match peer_info { - Err(e) => { - error!(error = %e, pid = %pid, "Failed getting process info"); - continue - }, - Ok(info) => info, - }; - + let peer_info = PeerInfo::new(pid as u32, crate::transport::peer_info::PeerType::NamedPipe); tx.send((listener, peer_info)).await.unwrap(); - listener = match ServerOptions::new().create(PIPE_NAME) { + listener = match ServerOptions::new().create(pipe_name.clone()) { Ok(pipe) => pipe, Err(e) => { error!(error = %e, "Encountered an error creating a new pipe"); cancellation_token.cancel(); - is_running.store(false, Ordering::Relaxed); return; } }; @@ -84,7 +71,8 @@ impl NamedPipeServerStream { } } }); - Self { rx } + + Ok(NamedPipeServerStream { rx }) } } diff --git a/apps/desktop/desktop_native/ssh_agent/src/transport/peer_info.rs b/apps/desktop/desktop_native/ssh_agent/src/transport/peer_info.rs index 68ced90da45..bf06b4cf852 100644 --- a/apps/desktop/desktop_native/ssh_agent/src/transport/peer_info.rs +++ b/apps/desktop/desktop_native/ssh_agent/src/transport/peer_info.rs @@ -6,7 +6,6 @@ use sysinfo::{Pid, System}; /// This can be later extended to include more information (icon, app name) for the corresponding application. #[derive(Clone)] pub struct PeerInfo { - uid: u32, pid: u32, process_name: String, peer_type: PeerType, @@ -32,7 +31,6 @@ impl PeerInfo { ); if let Some(process) = system.process(Pid::from_u32(peer_pid)) { Ok(Self { - uid: **process.user_id().ok_or(())?, pid: peer_pid, process_name: process.name().to_str().ok_or(())?.to_string(), peer_type, @@ -44,17 +42,12 @@ impl PeerInfo { pub fn unknown() -> Self { Self { - uid: 0, pid: 0, process_name: "Unknown application".to_string(), peer_type: PeerType::UnixSocket, } } - pub fn uid(&self) -> u32 { - self.uid - } - pub fn pid(&self) -> u32 { self.pid } @@ -67,7 +60,6 @@ impl PeerInfo { impl Debug for PeerInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("PeerInfo") - .field("uid", &self.uid) .field("pid", &self.pid) .field("process_name", &self.process_name) .field("peer_type", &self.peer_type)