Skip to content

Commit 8a4bc2e

Browse files
authored
Merge pull request #46 from stacklok/fix/agent-forwarding-channel-request
Fix SSH agent forwarding handled in wrong request handler
2 parents 490e9b7 + db3efd1 commit 8a4bc2e

File tree

3 files changed

+47
-37
lines changed

3 files changed

+47
-37
lines changed

guest/sshd/server.go

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -274,32 +274,12 @@ func (s *Server) handleConnection(netConn net.Conn) {
274274
}
275275

276276
// handleGlobalRequests processes connection-level SSH requests.
277-
// It handles agent forwarding requests when enabled and discards
278-
// all other global requests.
279-
func (s *Server) handleGlobalRequests(reqs <-chan *ssh.Request, conn *ssh.ServerConn) {
277+
// It rejects all global requests; session-specific requests like
278+
// agent forwarding are handled in handleSession.
279+
func (s *Server) handleGlobalRequests(reqs <-chan *ssh.Request, _ *ssh.ServerConn) {
280280
for req := range reqs {
281-
switch req.Type {
282-
case "auth-agent-req@openssh.com":
283-
if s.cfg.AgentForwarding {
284-
s.setAgentForwarding(conn, true)
285-
s.logger.Info("agent forwarding enabled",
286-
"remote", conn.RemoteAddr(),
287-
)
288-
if req.WantReply {
289-
_ = req.Reply(true, nil)
290-
}
291-
} else {
292-
s.logger.Debug("agent forwarding rejected (disabled)",
293-
"remote", conn.RemoteAddr(),
294-
)
295-
if req.WantReply {
296-
_ = req.Reply(false, nil)
297-
}
298-
}
299-
default:
300-
if req.WantReply {
301-
_ = req.Reply(false, nil)
302-
}
281+
if req.WantReply {
282+
_ = req.Reply(false, nil)
303283
}
304284
}
305285
}

guest/sshd/server_test.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/stretchr/testify/assert"
2121
"github.com/stretchr/testify/require"
2222
"golang.org/x/crypto/ssh"
23+
"golang.org/x/crypto/ssh/agent"
2324
)
2425

2526
// generateTestKeyPair creates an ECDSA P-256 key pair for testing and
@@ -327,10 +328,13 @@ func TestAgentForwardingDisabled(t *testing.T) {
327328

328329
client := dialSSH(t, addr, signer)
329330

330-
// Request agent forwarding — should be rejected.
331-
ok, _, err := client.SendRequest("auth-agent-req@openssh.com", true, nil)
331+
session, err := client.NewSession()
332332
require.NoError(t, err)
333-
assert.False(t, ok, "agent forwarding should be rejected when disabled")
333+
defer func() { _ = session.Close() }()
334+
335+
// Request agent forwarding via the real API — should be rejected.
336+
err = agent.RequestAgentForwarding(session)
337+
assert.Error(t, err, "agent forwarding should be rejected when disabled")
334338
}
335339

336340
func TestAgentForwardingEnabled(t *testing.T) {
@@ -352,10 +356,23 @@ func TestAgentForwardingEnabled(t *testing.T) {
352356

353357
client := dialSSH(t, addr, signer)
354358

355-
// Request agent forwarding — should be accepted.
356-
ok, _, err := client.SendRequest("auth-agent-req@openssh.com", true, nil)
359+
session, err := client.NewSession()
360+
require.NoError(t, err)
361+
defer func() { _ = session.Close() }()
362+
363+
// Request agent forwarding via the real API — should be accepted.
364+
err = agent.RequestAgentForwarding(session)
365+
require.NoError(t, err, "agent forwarding should be accepted when enabled")
366+
367+
// Verify the flag was set by running a command on a second session.
368+
session2, err := client.NewSession()
357369
require.NoError(t, err)
358-
assert.True(t, ok, "agent forwarding should be accepted when enabled")
370+
defer func() { _ = session2.Close() }()
371+
372+
output, err := session2.CombinedOutput("echo ${SSH_AUTH_SOCK:-unset}")
373+
require.NoError(t, err)
374+
result := strings.TrimSpace(string(output))
375+
assert.Contains(t, result, "/tmp/ssh-", "agent socket should be set on connection after forwarding request")
359376
}
360377

361378
func TestAgentSocketCreated(t *testing.T) {
@@ -377,16 +394,15 @@ func TestAgentSocketCreated(t *testing.T) {
377394

378395
client := dialSSH(t, addr, signer)
379396

380-
// Request agent forwarding.
381-
ok, _, err := client.SendRequest("auth-agent-req@openssh.com", true, nil)
382-
require.NoError(t, err)
383-
require.True(t, ok)
384-
385-
// Run a command that checks if SSH_AUTH_SOCK is set.
397+
// Request agent forwarding and run a command on the same session,
398+
// which is the real client flow: auth-agent-req arrives before exec.
386399
session, err := client.NewSession()
387400
require.NoError(t, err)
388401
defer func() { _ = session.Close() }()
389402

403+
err = agent.RequestAgentForwarding(session)
404+
require.NoError(t, err)
405+
390406
output, err := session.CombinedOutput("echo $SSH_AUTH_SOCK")
391407
require.NoError(t, err)
392408

guest/sshd/session.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,20 @@ func (s *Server) handleSession(ch ssh.Channel, requests <-chan *ssh.Request, con
119119
replyRequest(req, false)
120120
}
121121

122+
case "auth-agent-req@openssh.com":
123+
if s.cfg.AgentForwarding {
124+
s.setAgentForwarding(conn, true)
125+
s.logger.Info("agent forwarding enabled",
126+
"remote", conn.RemoteAddr(),
127+
)
128+
replyRequest(req, true)
129+
} else {
130+
s.logger.Debug("agent forwarding rejected (disabled)",
131+
"remote", conn.RemoteAddr(),
132+
)
133+
replyRequest(req, false)
134+
}
135+
122136
case "exec":
123137
var payload struct {
124138
Command string

0 commit comments

Comments
 (0)