sftp_server.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // sftp_server.go
  2. package sftpd
  3. import (
  4. "context"
  5. "fmt"
  6. "io"
  7. "os"
  8. "time"
  9. "github.com/pkg/sftp"
  10. "github.com/seaweedfs/seaweedfs/weed/glog"
  11. "github.com/seaweedfs/seaweedfs/weed/pb"
  12. filer_pb "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  13. "github.com/seaweedfs/seaweedfs/weed/sftpd/user"
  14. "github.com/seaweedfs/seaweedfs/weed/util"
  15. "google.golang.org/grpc"
  16. )
  17. type SftpServer struct {
  18. filerAddr pb.ServerAddress
  19. grpcDialOption grpc.DialOption
  20. dataCenter string
  21. filerGroup string
  22. user *user.User
  23. }
  24. // NewSftpServer constructs the server.
  25. func NewSftpServer(filerAddr pb.ServerAddress, grpcDialOption grpc.DialOption, dataCenter, filerGroup string, user *user.User) SftpServer {
  26. return SftpServer{
  27. filerAddr: filerAddr,
  28. grpcDialOption: grpcDialOption,
  29. dataCenter: dataCenter,
  30. filerGroup: filerGroup,
  31. user: user,
  32. }
  33. }
  34. // Fileread is invoked for “get” requests.
  35. func (fs *SftpServer) Fileread(req *sftp.Request) (io.ReaderAt, error) {
  36. return fs.readFile(req)
  37. }
  38. // Filewrite is invoked for “put” requests.
  39. func (fs *SftpServer) Filewrite(req *sftp.Request) (io.WriterAt, error) {
  40. return fs.newFileWriter(req)
  41. }
  42. // Filecmd handles Remove, Rename, Mkdir, Rmdir, etc.
  43. func (fs *SftpServer) Filecmd(req *sftp.Request) error {
  44. return fs.dispatchCmd(req)
  45. }
  46. // Filelist handles directory listings.
  47. func (fs *SftpServer) Filelist(req *sftp.Request) (sftp.ListerAt, error) {
  48. return fs.listDir(req)
  49. }
  50. // EnsureHomeDirectory creates the user's home directory if it doesn't exist
  51. func (fs *SftpServer) EnsureHomeDirectory() error {
  52. if fs.user.HomeDir == "" {
  53. return fmt.Errorf("user has no home directory configured")
  54. }
  55. glog.V(0).Infof("Ensuring home directory exists for user %s: %s", fs.user.Username, fs.user.HomeDir)
  56. // Check if home directory already exists
  57. entry, err := fs.getEntry(fs.user.HomeDir)
  58. if err == nil && entry != nil {
  59. // Directory exists, just ensure proper ownership
  60. if entry.Attributes.Uid != fs.user.Uid || entry.Attributes.Gid != fs.user.Gid {
  61. dir, _ := util.FullPath(fs.user.HomeDir).DirAndName()
  62. entry.Attributes.Uid = fs.user.Uid
  63. entry.Attributes.Gid = fs.user.Gid
  64. return fs.updateEntry(dir, entry)
  65. }
  66. return nil
  67. }
  68. // Skip permission check for home directory creation
  69. // This is a special case where we want to create the directory regardless
  70. dir, name := util.FullPath(fs.user.HomeDir).DirAndName()
  71. // Create the directory with proper permissions using filer_pb.Mkdir
  72. err = filer_pb.Mkdir(context.Background(), fs, dir, name, func(entry *filer_pb.Entry) {
  73. mode := uint32(0700 | os.ModeDir) // Default to private permissions for home dirs
  74. entry.Attributes.FileMode = mode
  75. entry.Attributes.Uid = fs.user.Uid
  76. entry.Attributes.Gid = fs.user.Gid
  77. now := time.Now().Unix()
  78. entry.Attributes.Crtime = now
  79. entry.Attributes.Mtime = now
  80. if entry.Extended == nil {
  81. entry.Extended = make(map[string][]byte)
  82. }
  83. entry.Extended["creator"] = []byte(fs.user.Username)
  84. })
  85. if err != nil {
  86. return fmt.Errorf("failed to create home directory: %w", err)
  87. }
  88. glog.V(0).Infof("Successfully created home directory for user %s: %s", fs.user.Username, fs.user.HomeDir)
  89. return nil
  90. }