Add opt-in, security-gated SSH-agent forwarding
Item 3: SSH-agent forwarding, double-gated (client -A/forward_agent AND server allow_agent_forwarding) and off by default on both ends. Wire: new ForwardingKind::Agent (appended, existing bincode discriminants unchanged). Bumped protocol VERSION 2 -> 3 so a pre-agent peer answers with a clear version-mismatch reject instead of a deserialize error. Client: -A / --forward-agent flag; requires local SSH_AUTH_SOCK. Requests an Agent forwarding during native auth (agent forwarding requires native auth) and, on a server-initiated StreamOpen carrying the reserved @dosh-agent sentinel, splices the stream into the local agent unix socket (separate agent_writers map, TCP forwarding paths untouched). Rejects agent StreamOpens unless it opted in, so a server cannot reach the agent without consent. Server: when the client opted in and allow_agent_forwarding is set, binds a per-session proxy unix socket (dir 0700, socket 0600) before the shell spawns, exports its path as the session's SSH_AUTH_SOCK, and tunnels each connection back to the client over the agent sentinel stream. Applies only to freshly spawned shells (documented). Socket cleaned up on auth/forward failure and when the accept loop ends. SECURITY rationale documented in comments. Tests: 2 end-to-end integration tests (full chain identities round-trip via a PTY-hosted client + looping fake agent; and "no -A => no proxy socket"). Docs updated (README forwarding + disconnect-status note, spec §12.1). fmt + full test suite green (122 tests). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -91,6 +91,12 @@ pub enum ForwardingKind {
|
||||
Local,
|
||||
Remote,
|
||||
Dynamic,
|
||||
/// SSH-agent forwarding: the client opts in and, if the server policy allows
|
||||
/// (`allow_agent_forwarding`), the server exports a proxy unix socket as
|
||||
/// `SSH_AUTH_SOCK` in the remote session and tunnels each connection back to
|
||||
/// the client's local agent over a Dosh stream. Added at the end of the enum
|
||||
/// so bincode discriminants for the existing variants are unchanged.
|
||||
Agent,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -513,6 +519,10 @@ impl AuthorizedKey {
|
||||
"authorized key permitopen= cannot authorize remote or dynamic forwarding"
|
||||
);
|
||||
}
|
||||
// Agent forwarding does not open a host:port, so permitopen
|
||||
// (which restricts which targets may be opened) does not apply;
|
||||
// it is gated separately by the server's allow_agent_forwarding.
|
||||
ForwardingKind::Agent => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user