aboutsummaryrefslogtreecommitdiff
path: root/weed/sftpd/sftp_server.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/sftpd/sftp_server.go')
-rw-r--r--weed/sftpd/sftp_server.go24
1 files changed, 24 insertions, 0 deletions
diff --git a/weed/sftpd/sftp_server.go b/weed/sftpd/sftp_server.go
index f158aeb64..e53098e6b 100644
--- a/weed/sftpd/sftp_server.go
+++ b/weed/sftpd/sftp_server.go
@@ -6,6 +6,8 @@ import (
"fmt"
"io"
"os"
+ "path"
+ "strings"
"time"
"github.com/pkg/sftp"
@@ -37,6 +39,28 @@ func NewSftpServer(filerAddr pb.ServerAddress, grpcDialOption grpc.DialOption, d
}
}
+// toAbsolutePath translates a user-relative path to an absolute filer path.
+// When a user has HomeDir="/sftp/user", their view of "/" maps to "/sftp/user".
+// This implements chroot-like behavior where the user's home directory
+// becomes their root.
+func (fs *SftpServer) toAbsolutePath(userPath string) (string, error) {
+ // If user has root as home directory, no translation needed
+ if fs.user.HomeDir == "" || fs.user.HomeDir == "/" {
+ return path.Clean(userPath), nil
+ }
+
+ // Concatenate home directory with user path, then clean to resolve any ".." components
+ p := path.Join(fs.user.HomeDir, strings.TrimPrefix(userPath, "/"))
+
+ // Security check: ensure the final path is within the home directory.
+ // This prevents path traversal attacks like `../..` that could escape the chroot jail.
+ if !strings.HasPrefix(p, fs.user.HomeDir+"/") && p != fs.user.HomeDir {
+ return "", fmt.Errorf("path traversal attempt: %s resolves to %s which is outside home dir %s", userPath, p, fs.user.HomeDir)
+ }
+
+ return p, nil
+}
+
// Fileread is invoked for “get” requests.
func (fs *SftpServer) Fileread(req *sftp.Request) (io.ReaderAt, error) {
return fs.readFile(req)