Skip to content

Commit 1430a65

Browse files
feat: add control character processing
1 parent e77d58c commit 1430a65

1 file changed

Lines changed: 37 additions & 11 deletions

File tree

packages/pam/handlers/ssh/proxy.go

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ type SSHProxyConfig struct {
2828

2929
// SSHProxy handles proxying SSH connections with credential injection
3030
type SSHProxy struct {
31-
config SSHProxyConfig
32-
mutex sync.Mutex
33-
sessionData []byte // Store session data for logging
34-
inputBuffer []byte // Buffer for input data to batch keystrokes
35-
inputChannelType session.TerminalChannelType // Channel type for buffered input
31+
config SSHProxyConfig
32+
mutex sync.Mutex
33+
sessionData []byte // Store session data for logging
34+
inputBuffer []byte // Buffer for input data to batch keystrokes
35+
inputChannelType session.TerminalChannelType // Channel type for buffered input
3636
}
3737

3838
// channelState holds per-channel state for tracking session type
@@ -510,20 +510,46 @@ func (p *SSHProxy) proxyData(src io.Reader, dst io.Writer, direction string, ses
510510
}
511511
}
512512

513-
// bufferInput accumulates input data and logs only when newline or control chars are encountered
513+
// bufferInput accumulates input data and logs the effective command after processing edits.
514+
// It interprets control characters (backspace, Ctrl+C/U/W) so that the logged command
515+
// reflects what the user actually sent, not the raw keystrokes.
514516
func (p *SSHProxy) bufferInput(data []byte, sessionID string, channelType session.TerminalChannelType) {
515517
p.mutex.Lock()
516518
defer p.mutex.Unlock()
517519

518520
p.inputChannelType = channelType
519521

520522
for _, b := range data {
521-
p.inputBuffer = append(p.inputBuffer, b)
522-
523-
// Check if we should flush the buffer
524-
// CR (0x0D), LF (0x0A), or if buffer gets too large
525-
if b == 0x0D || b == 0x0A || len(p.inputBuffer) >= 1024 {
523+
switch b {
524+
case 0x7F, 0x08: // DEL (backspace on most terminals) or BS
525+
if len(p.inputBuffer) > 0 {
526+
p.inputBuffer = p.inputBuffer[:len(p.inputBuffer)-1]
527+
}
528+
case 0x03: // Ctrl+C - cancel current input
529+
p.inputBuffer = p.inputBuffer[:0]
530+
case 0x15: // Ctrl+U - clear line
531+
p.inputBuffer = p.inputBuffer[:0]
532+
case 0x17: // Ctrl+W - delete previous word
533+
// Skip trailing spaces
534+
for len(p.inputBuffer) > 0 && p.inputBuffer[len(p.inputBuffer)-1] == ' ' {
535+
p.inputBuffer = p.inputBuffer[:len(p.inputBuffer)-1]
536+
}
537+
// Delete until next space or start
538+
for len(p.inputBuffer) > 0 && p.inputBuffer[len(p.inputBuffer)-1] != ' ' {
539+
p.inputBuffer = p.inputBuffer[:len(p.inputBuffer)-1]
540+
}
541+
case 0x0D, 0x0A: // CR or LF - flush the buffer
542+
p.inputBuffer = append(p.inputBuffer, b)
526543
p.flushInputBufferUnsafe(sessionID)
544+
default:
545+
// Only buffer printable characters and tab
546+
if b >= 0x20 || b == 0x09 {
547+
p.inputBuffer = append(p.inputBuffer, b)
548+
}
549+
// Safety: flush if buffer gets too large
550+
if len(p.inputBuffer) >= 1024 {
551+
p.flushInputBufferUnsafe(sessionID)
552+
}
527553
}
528554
}
529555
}

0 commit comments

Comments
 (0)