Skip to content
This repository was archived by the owner on Feb 25, 2021. It is now read-only.

Ensure correct server data path is used #4

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@

# Misc files and folders
.idea/
sftp-server
sftp-server
sftp-server\.log
73 changes: 61 additions & 12 deletions src/server/handler.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
package server

import (
"github.com/buger/jsonparser"
"github.com/patrickmn/go-cache"
"github.com/pkg/errors"
"github.com/pkg/sftp"
"github.com/pterodactyl/sftp-server/src/logger"
"go.uber.org/zap"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"sync"

"github.com/buger/jsonparser"
cache "github.com/patrickmn/go-cache"
"github.com/pkg/errors"
"github.com/pkg/sftp"
"github.com/pterodactyl/sftp-server/src/logger"
"go.uber.org/zap"
)

type FileSystem struct {
Expand All @@ -28,7 +29,7 @@ type FileSystem struct {
lock sync.Mutex
}

// Creates a reader for a file on the system and returns the reader back.
// Fileread creates a reader for a file on the system and returns the reader back.
func (fs FileSystem) Fileread(request *sftp.Request) (io.ReaderAt, error) {
// Check first if the user can actually open and view a file. This permission is named
// really poorly, but it is checking if they can read. There is an addition permission,
Expand All @@ -42,6 +43,17 @@ func (fs FileSystem) Fileread(request *sftp.Request) (io.ReaderAt, error) {
return nil, sftp.ErrSshFxNoSuchFile
}

symfile, err := filepath.EvalSymlinks(p)
if err != nil {
return nil, sftp.ErrSshFxOpUnsupported
}

dir, _ := path.Split(p)

if !strings.Contains(symfile, dir) {
return nil, sftp.ErrSshFxPermissionDenied
}

fs.lock.Lock()
defer fs.lock.Unlock()

Expand All @@ -58,7 +70,7 @@ func (fs FileSystem) Fileread(request *sftp.Request) (io.ReaderAt, error) {
return file, nil
}

// Handle a write action for a file on the system.
// Filewrite handles the write actions for a file on the system.
func (fs FileSystem) Filewrite(request *sftp.Request) (io.WriterAt, error) {
if fs.ReadOnly {
return nil, sftp.ErrSshFxOpUnsupported
Expand All @@ -69,6 +81,17 @@ func (fs FileSystem) Filewrite(request *sftp.Request) (io.WriterAt, error) {
return nil, sftp.ErrSshFxNoSuchFile
}

symfile, err := filepath.EvalSymlinks(p)
if err != nil {
return nil, sftp.ErrSshFxOpUnsupported
}

dir, _ := path.Split(p)

if !strings.Contains(symfile, dir) {
return nil, sftp.ErrSshFxPermissionDenied
}

// If the user doesn't have enough space left on the server it should respond with an
// error since we won't be letting them write this file to the disk.
if !fs.hasSpace() {
Expand Down Expand Up @@ -155,7 +178,7 @@ func (fs FileSystem) Filewrite(request *sftp.Request) (io.WriterAt, error) {
return file, nil
}

// Hander for basic SFTP system calls related to files, but not anything to do with reading
// Filecmd hander for basic SFTP system calls related to files, but not anything to do with reading
// or writing to those files.
func (fs FileSystem) Filecmd(request *sftp.Request) error {
if fs.ReadOnly {
Expand All @@ -167,6 +190,17 @@ func (fs FileSystem) Filecmd(request *sftp.Request) error {
return sftp.ErrSshFxNoSuchFile
}

symfile, err := filepath.EvalSymlinks(p)
if err != nil {
return sftp.ErrSshFxOpUnsupported
}

dir, _ := path.Split(p)

if !strings.Contains(symfile, dir) {
return sftp.ErrSshFxPermissionDenied
}

var target string
// If a target is provided in this request validate that it is going to the correct
// location for the server. If it is not, return an operation unsupported error. This
Expand All @@ -180,7 +214,7 @@ func (fs FileSystem) Filecmd(request *sftp.Request) error {

switch request.Method {
case "Setstat":
var mode os.FileMode = 0644
var mode os.FileMode = request.Attributes().FileMode().Perm()
if request.Attributes().FileMode().IsDir() {
mode = 0755
}
Expand Down Expand Up @@ -272,7 +306,7 @@ func (fs FileSystem) Filecmd(request *sftp.Request) error {
return sftp.ErrSshFxOk
}

// Handler for SFTP filesystem list calls. This will handle calls to list the contents of
// Filelist is the andler for SFTP filesystem list calls. This will handle calls to list the contents of
// a directory as well as perform file/folder stat calls.
func (fs FileSystem) Filelist(request *sftp.Request) (sftp.ListerAt, error) {
p, err := fs.buildPath(request.Filepath)
Expand All @@ -292,6 +326,21 @@ func (fs FileSystem) Filelist(request *sftp.Request) (sftp.ListerAt, error) {
return nil, sftp.ErrSshFxFailure
}

for i, file := range files {
if file.Mode()&os.ModeType == os.ModeSymlink {

symfile, err := filepath.EvalSymlinks(p + "/" + file.Name())
if err != nil {
return nil, sftp.ErrSshFxOpUnsupported
}

if !strings.Contains(symfile, p) {
logger.Get().Debugw("File "+file.Name()+"is a symlink. Dropping file from filelist", zap.String("file", file.Name()))
files = append(files[:i], files[i+1:]...)
}
}
}

return ListerAt(files), nil
case "Stat":
if !fs.can("list-files") {
Expand Down Expand Up @@ -452,4 +501,4 @@ func (fs FileSystem) directorySize(dir string) int64 {
wg.Wait()

return size
}
}