From 6b93ee19e7b34008e2da9246320de6e1f83ab71a Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Thu, 9 May 2024 07:45:19 -0700 Subject: [PATCH] mux: record client ssh_auth_sock information This commit expands the set of data that we track for each client to include the SSH_AUTH_SOCK. This defaults to the value of that env var on the machine where the ClientId is constructed, which may be remote from the mux server. For the proxy scenario, a remote SSH_AUTH_SOCK path is not addressable, and what we really want is the local SSH_AUTH_SOCK path from that SSH session, so we introduce awareness of whether the current session is a proxy session. Proxy sessions register the mux-local-proxy-id during the setup of the proxy, but we don't apply the identity to the mux. Instead, we wait for the remote client to send their identity and that is annotate to show that it has been routed via a proxy and, crucially, has the SSH_AUTH_SOCK replaced with the mux-local-proxy-id SSH_AUTH_SOCK. ``` ; wezterm cli list-clients USER HOST PID CONNECTED IDLE WORKSPACE FOCUS SSH_AUTH_SOCK wez foo 336500 86.944834352s 944.834352ms default 3 /home/wez/.1password/agent.sock wez foo (via proxy pid 337457) 337314 1.944834352s 944.834352ms 4 /tmp/ssh-XXXXTfGSp7/agent.337456 ``` For the SSH_AUTH_SOCK to be populated, ssh agent forwarding also needs to be enabled for SSH exec() calls; previously it was enabled only for pty channels. Since this commit changes the ABI of the mux protocol, the codec version has been bumped. --- codec/src/lib.rs | 3 +- mux/src/client.rs | 2 + wezterm-client/src/client.rs | 3 +- wezterm-mux-server-impl/src/sessionhandler.rs | 39 +++++++++++++++---- wezterm-ssh/src/sessioninner.rs | 8 ++++ wezterm/src/cli/list_clients.rs | 9 +++++ wezterm/src/cli/proxy.rs | 12 +++++- 7 files changed, 65 insertions(+), 11 deletions(-) diff --git a/codec/src/lib.rs b/codec/src/lib.rs index f8d2f1362..c6337598d 100644 --- a/codec/src/lib.rs +++ b/codec/src/lib.rs @@ -431,7 +431,7 @@ macro_rules! pdu { /// The overall version of the codec. /// This must be bumped when backwards incompatible changes /// are made to the types and protocol. -pub const CODEC_VERSION: usize = 42; +pub const CODEC_VERSION: usize = 43; // Defines the Pdu enum. // Each struct has an explicit identifying number. @@ -823,6 +823,7 @@ pub struct WindowWorkspaceChanged { #[derive(Deserialize, Serialize, PartialEq, Debug)] pub struct SetClientId { pub client_id: ClientId, + pub is_proxy: bool, } #[derive(Deserialize, Serialize, PartialEq, Debug)] diff --git a/mux/src/client.rs b/mux/src/client.rs index 364854915..afd7d5c18 100644 --- a/mux/src/client.rs +++ b/mux/src/client.rs @@ -20,6 +20,7 @@ pub struct ClientId { pub pid: u32, pub epoch: u64, pub id: usize, + pub ssh_auth_sock: Option, } impl ClientId { @@ -33,6 +34,7 @@ impl ClientId { pid: unsafe { libc::getpid() as u32 }, epoch: *EPOCH, id, + ssh_auth_sock: std::env::var("SSH_AUTH_SOCK").ok(), } } } diff --git a/wezterm-client/src/client.rs b/wezterm-client/src/client.rs index eddbabb81..7e6d7c78e 100644 --- a/wezterm-client/src/client.rs +++ b/wezterm-client/src/client.rs @@ -51,7 +51,7 @@ enum ReaderMessage { pub struct Client { sender: Sender, local_domain_id: Option, - client_id: ClientId, + pub client_id: ClientId, client_domain_config: ClientDomainConfig, pub is_reconnectable: bool, pub is_local: bool, @@ -1144,6 +1144,7 @@ impl Client { ); self.set_client_id(SetClientId { client_id: self.client_id.clone(), + is_proxy: false, }) .await?; Ok(info) diff --git a/wezterm-mux-server-impl/src/sessionhandler.rs b/wezterm-mux-server-impl/src/sessionhandler.rs index 405a0166e..0c5725af8 100644 --- a/wezterm-mux-server-impl/src/sessionhandler.rs +++ b/wezterm-mux-server-impl/src/sessionhandler.rs @@ -199,6 +199,7 @@ pub struct SessionHandler { to_write_tx: PduSender, per_pane: HashMap>>, client_id: Option>, + proxy_client_id: Option, } impl Drop for SessionHandler { @@ -216,6 +217,7 @@ impl SessionHandler { to_write_tx, per_pane: HashMap::new(), client_id: None, + proxy_client_id: None, } } @@ -292,14 +294,35 @@ impl SessionHandler { }) .detach(); } - Pdu::SetClientId(SetClientId { client_id }) => { - let client_id = Arc::new(client_id); - self.client_id.replace(client_id.clone()); - spawn_into_main_thread(async move { - let mux = Mux::get(); - mux.register_client(client_id); - }) - .detach(); + Pdu::SetClientId(SetClientId { + mut client_id, + is_proxy, + }) => { + if is_proxy { + if self.proxy_client_id.is_none() { + // Copy proxy identity, but don't assign it to the mux; + // we'll use it to annotate the actual clients own + // identity when they send it + self.proxy_client_id.replace(client_id); + } + } else { + // If this session is a proxy, override the incoming id with + // the proxy information so that it is clear what is going + // on from the `wezterm cli list-clients` information + if let Some(proxy_id) = &self.proxy_client_id { + client_id.ssh_auth_sock = proxy_id.ssh_auth_sock.clone(); + client_id.hostname = + format!("{} (via proxy pid {})", client_id.hostname, proxy_id.pid); + } + + let client_id = Arc::new(client_id); + self.client_id.replace(client_id.clone()); + spawn_into_main_thread(async move { + let mux = Mux::get(); + mux.register_client(client_id); + }) + .detach(); + } send_response(Ok(Pdu::UnitResponse(UnitResponse {}))) } Pdu::SetFocusedPane(SetFocusedPane { pane_id }) => { diff --git a/wezterm-ssh/src/sessioninner.rs b/wezterm-ssh/src/sessioninner.rs index 7e5d50d10..285115909 100644 --- a/wezterm-ssh/src/sessioninner.rs +++ b/wezterm-ssh/src/sessioninner.rs @@ -890,6 +890,14 @@ impl SessionInner { pub fn exec(&mut self, sess: &mut SessionWrap, exec: Exec) -> anyhow::Result { let mut channel = sess.open_session()?; + if let Some("yes") = self.config.get("forwardagent").map(|s| s.as_str()) { + if self.identity_agent().is_some() { + if let Err(err) = channel.request_auth_agent_forwarding() { + log::error!("Failed to request agent forwarding: {:#}", err); + } + } + } + if let Some(env) = &exec.env { for (key, val) in env { if let Err(err) = channel.request_env(key, val) { diff --git a/wezterm/src/cli/list_clients.rs b/wezterm/src/cli/list_clients.rs index 4bf116ec0..d92de5688 100644 --- a/wezterm/src/cli/list_clients.rs +++ b/wezterm/src/cli/list_clients.rs @@ -57,6 +57,10 @@ impl ListClientsCommand { name: "FOCUS".to_string(), alignment: Alignment::Right, }, + Column { + name: "SSH_AUTH_SOCK".to_string(), + alignment: Alignment::Left, + }, ]; let mut data = vec![]; let now: DateTime = Utc::now(); @@ -82,6 +86,11 @@ impl ListClientsCommand { info.focused_pane_id .map(|id| id.to_string()) .unwrap_or_else(String::new), + info.client_id + .ssh_auth_sock + .as_deref() + .unwrap_or("") + .to_string(), ]); } diff --git a/wezterm/src/cli/proxy.rs b/wezterm/src/cli/proxy.rs index 366e965a5..cbdc5c967 100644 --- a/wezterm/src/cli/proxy.rs +++ b/wezterm/src/cli/proxy.rs @@ -1,6 +1,8 @@ use clap::Parser; +use codec::{Pdu, SetClientId}; use config::ConfigHandle; use mux::activity::Activity; +use mux::client::ClientId; use mux::Mux; use std::io::{Read, Write}; use std::sync::Arc; @@ -26,7 +28,15 @@ impl ProxyCommand { Mux::set_mux(&mux); let target = unix_dom.target(); - let stream = unix_connect_with_retry(&target, false, None)?; + let mut stream = unix_connect_with_retry(&target, false, None)?; + + let pdu = Pdu::SetClientId(SetClientId { + client_id: ClientId::new(), + is_proxy: true, + }); + let serial = 1; + pdu.encode(&mut stream, serial)?; + Pdu::decode(&mut stream)?; // Spawn a thread to pull data from the socket and write // it to stdout