You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							106 lines
						
					
					
						
							3.1 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							106 lines
						
					
					
						
							3.1 KiB
						
					
					
				
								// sftp_server.go
							 | 
						|
								package sftpd
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"context"
							 | 
						|
									"fmt"
							 | 
						|
									"io"
							 | 
						|
									"os"
							 | 
						|
									"time"
							 | 
						|
								
							 | 
						|
									"github.com/pkg/sftp"
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/glog"
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/pb"
							 | 
						|
									filer_pb "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/sftpd/user"
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/util"
							 | 
						|
									"google.golang.org/grpc"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								type SftpServer struct {
							 | 
						|
									filerAddr      pb.ServerAddress
							 | 
						|
									grpcDialOption grpc.DialOption
							 | 
						|
									dataCenter     string
							 | 
						|
									filerGroup     string
							 | 
						|
									user           *user.User
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// NewSftpServer constructs the server.
							 | 
						|
								func NewSftpServer(filerAddr pb.ServerAddress, grpcDialOption grpc.DialOption, dataCenter, filerGroup string, user *user.User) SftpServer {
							 | 
						|
								
							 | 
						|
									return SftpServer{
							 | 
						|
										filerAddr:      filerAddr,
							 | 
						|
										grpcDialOption: grpcDialOption,
							 | 
						|
										dataCenter:     dataCenter,
							 | 
						|
										filerGroup:     filerGroup,
							 | 
						|
										user:           user,
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Fileread is invoked for “get” requests.
							 | 
						|
								func (fs *SftpServer) Fileread(req *sftp.Request) (io.ReaderAt, error) {
							 | 
						|
									return fs.readFile(req)
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Filewrite is invoked for “put” requests.
							 | 
						|
								func (fs *SftpServer) Filewrite(req *sftp.Request) (io.WriterAt, error) {
							 | 
						|
									return fs.newFileWriter(req)
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Filecmd handles Remove, Rename, Mkdir, Rmdir, etc.
							 | 
						|
								func (fs *SftpServer) Filecmd(req *sftp.Request) error {
							 | 
						|
									return fs.dispatchCmd(req)
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Filelist handles directory listings.
							 | 
						|
								func (fs *SftpServer) Filelist(req *sftp.Request) (sftp.ListerAt, error) {
							 | 
						|
									return fs.listDir(req)
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// EnsureHomeDirectory creates the user's home directory if it doesn't exist
							 | 
						|
								func (fs *SftpServer) EnsureHomeDirectory() error {
							 | 
						|
									if fs.user.HomeDir == "" {
							 | 
						|
										return fmt.Errorf("user has no home directory configured")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									glog.V(0).Infof("Ensuring home directory exists for user %s: %s", fs.user.Username, fs.user.HomeDir)
							 | 
						|
								
							 | 
						|
									// Check if home directory already exists
							 | 
						|
									entry, err := fs.getEntry(fs.user.HomeDir)
							 | 
						|
									if err == nil && entry != nil {
							 | 
						|
										// Directory exists, just ensure proper ownership
							 | 
						|
										if entry.Attributes.Uid != fs.user.Uid || entry.Attributes.Gid != fs.user.Gid {
							 | 
						|
											dir, _ := util.FullPath(fs.user.HomeDir).DirAndName()
							 | 
						|
											entry.Attributes.Uid = fs.user.Uid
							 | 
						|
											entry.Attributes.Gid = fs.user.Gid
							 | 
						|
											return fs.updateEntry(dir, entry)
							 | 
						|
										}
							 | 
						|
										return nil
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Skip permission check for home directory creation
							 | 
						|
									// This is a special case where we want to create the directory regardless
							 | 
						|
									dir, name := util.FullPath(fs.user.HomeDir).DirAndName()
							 | 
						|
								
							 | 
						|
									// Create the directory with proper permissions using filer_pb.Mkdir
							 | 
						|
									err = filer_pb.Mkdir(context.Background(), fs, dir, name, func(entry *filer_pb.Entry) {
							 | 
						|
										mode := uint32(0700 | os.ModeDir) // Default to private permissions for home dirs
							 | 
						|
										entry.Attributes.FileMode = mode
							 | 
						|
										entry.Attributes.Uid = fs.user.Uid
							 | 
						|
										entry.Attributes.Gid = fs.user.Gid
							 | 
						|
										now := time.Now().Unix()
							 | 
						|
										entry.Attributes.Crtime = now
							 | 
						|
										entry.Attributes.Mtime = now
							 | 
						|
										if entry.Extended == nil {
							 | 
						|
											entry.Extended = make(map[string][]byte)
							 | 
						|
										}
							 | 
						|
										entry.Extended["creator"] = []byte(fs.user.Username)
							 | 
						|
									})
							 | 
						|
								
							 | 
						|
									if err != nil {
							 | 
						|
										return fmt.Errorf("failed to create home directory: %w", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									glog.V(0).Infof("Successfully created home directory for user %s: %s", fs.user.Username, fs.user.HomeDir)
							 | 
						|
									return nil
							 | 
						|
								}
							 |