Files
netbird/client/ssh/server/sftp.go
Viktor Liu f012fb8592 [client] Add port forwarding to ssh proxy (#5031)
* Implement port forwarding for the ssh proxy

* Allow user switching for port forwarding
2026-01-07 12:18:04 +08:00

90 lines
2.1 KiB
Go

package server
import (
"fmt"
"io"
"github.com/gliderlabs/ssh"
"github.com/pkg/sftp"
log "github.com/sirupsen/logrus"
)
// SetAllowSFTP enables or disables SFTP support
func (s *Server) SetAllowSFTP(allow bool) {
s.mu.Lock()
defer s.mu.Unlock()
s.allowSFTP = allow
}
// sftpSubsystemHandler handles SFTP subsystem requests
func (s *Server) sftpSubsystemHandler(sess ssh.Session) {
sessionKey := s.registerSession(sess, cmdSFTP)
defer s.unregisterSession(sessionKey)
jwtUsername := s.associateJWTUsername(sess, sessionKey)
logger := log.WithField("session", sessionKey)
if jwtUsername != "" {
logger = logger.WithField("jwt_user", jwtUsername)
}
logger.Info("SFTP session started")
defer logger.Info("SFTP session closed")
s.mu.RLock()
allowSFTP := s.allowSFTP
s.mu.RUnlock()
if !allowSFTP {
logger.Debug("SFTP subsystem request denied: SFTP disabled")
if err := sess.Exit(1); err != nil {
logger.Debugf("SFTP session exit: %v", err)
}
return
}
result := s.CheckPrivileges(PrivilegeCheckRequest{
RequestedUsername: sess.User(),
FeatureSupportsUserSwitch: true,
FeatureName: FeatureSFTP,
})
if !result.Allowed {
logger.Warnf("SFTP access denied: %v", result.Error)
if err := sess.Exit(1); err != nil {
logger.Debugf("exit SFTP session: %v", err)
}
return
}
if !result.RequiresUserSwitching {
if err := s.executeSftpDirect(sess); err != nil {
logger.Errorf("SFTP direct execution: %v", err)
}
return
}
if err := s.executeSftpWithPrivilegeDrop(sess, result.User); err != nil {
logger.Errorf("SFTP privilege drop execution: %v", err)
}
}
// executeSftpDirect executes SFTP directly without privilege dropping
func (s *Server) executeSftpDirect(sess ssh.Session) error {
sftpServer, err := sftp.NewServer(sess)
if err != nil {
return fmt.Errorf("SFTP server creation: %w", err)
}
defer func() {
if err := sftpServer.Close(); err != nil {
log.Debugf("failed to close sftp server: %v", err)
}
}()
if err := sftpServer.Serve(); err != nil && err != io.EOF {
return fmt.Errorf("serve: %w", err)
}
return nil
}