GithubHelp home page GithubHelp logo

sftpd's Introduction

sftpd - SFTP server library in Go

License: MIT - Docs GoDoc

Recent changes - 2019

  • Attr.FillFrom cannot fail and now does not return an error value. Previously it was always nil.

FAQ

ssh: no common algorithms

The client and the server cannot agree on algorithms. Typically this is caused by an ECDSA host key. If using sshutil add the sshutil.RSA2048 flag.

Enabling debugging output

go build -tags debug -a

Will enable debugging output using package log.

TODO

  • Renames
  • Symlink creation

sftpd's People

Contributors

ilius avatar taruti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sftpd's Issues

Add Examples

Any chance you could add some basic examples for a starting point on how to use this library? Thanks for open sourcing it!

ssh_FXP_EXTENDED problem

hello,i write a example like this:

package main

import (
	"errors"
	"log"
	"net"
	"os"
	"strings"

	"github.com/taruti/sftpd"
	"github.com/taruti/sshutil"
	"golang.org/x/crypto/ssh"
)

func main() {
	RunServerLowLevel(":2022", ReadOnlyDirFs{})
}

type ReadOnlyDirFs struct {
	sftpd.EmptyFS
}

func rfsMangle(path string) (string, error) {
	if strings.Contains(path, "..") {
		return "<invalid>", errors.New("Invalid path")
	}
	if len(path) > 0 && path[0] == '/' {
		path = path[1:]
	}
	path = "./" + path
	return path, nil
}

func (fs ReadOnlyDirFs) Stat(name string, isLstat bool) (*sftpd.Attr, error) {
	p, e := rfsMangle(name)
	if e != nil {
		return nil, e
	}
	var fi os.FileInfo
	if isLstat {
		fi, e = os.Lstat(p)
	} else {
		fi, e = os.Stat(p)
	}
	if e != nil {
		return nil, e
	}
	var a sftpd.Attr
	a.FillFrom(fi)

	return &a, nil
}

// RunServerLowLevel is an example how to use the low level API
func RunServerLowLevel(hostport string, fs sftpd.FileSystem) {
	e := runServer(hostport, fs)
	if e != nil {
		log.Println("running server errored:", e)
	}
}

func runServer(hostport string, fs sftpd.FileSystem) error {
	config := &ssh.ServerConfig{
		PasswordCallback: sshutil.CreatePasswordCheck("root", []byte("123456")),
	}

	// Add the sshutil.RSA2048 and sshutil.Save flags if needed for the server in question...
	hkey, e := sshutil.KeyLoader{Flags: sshutil.Create | sshutil.RSA2048}.Load()
	//	hkey, e := sshutil.KeyLoader{Flags: sshutil.Create}.Load()
	if e != nil {
		return e
	}

	config.AddHostKey(hkey)

	listener, e := net.Listen("tcp", hostport)
	if e != nil {
		return e
	}

	log.Printf("Listening on %s user %s pass %s\n", hostport, "root", "123456")

	for {
		conn, e := listener.Accept()
		if e != nil {
			return e
		}
		go HandleConn(conn, config, fs)
	}
}

func HandleConn(conn net.Conn, config *ssh.ServerConfig, fs sftpd.FileSystem) {
	defer conn.Close()
	e := handleConn(conn, config, fs)
	if e != nil {
		log.Println("sftpd connection errored:", e)
	}
}
func handleConn(conn net.Conn, config *ssh.ServerConfig, fs sftpd.FileSystem) error {
	sc, chans, reqs, e := ssh.NewServerConn(conn, config)
	if e != nil {
		return e
	}
	defer sc.Close()

	// The incoming Request channel must be serviced.
	go PrintDiscardRequests(reqs)

	// Service the incoming Channel channel.
	for newChannel := range chans {
		if newChannel.ChannelType() != "session" {
			newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
			continue
		}
		channel, requests, err := newChannel.Accept()
		if err != nil {
			return err
		}

		go func(in <-chan *ssh.Request) {
			for req := range in {
				ok := false
				switch {
				case sftpd.IsSftpRequest(req):
					ok = true
					go func() {
						e := sftpd.ServeChannel(channel, fs)
						if e != nil {
							log.Println("sftpd servechannel failed:", e)
						}
					}()
				}
				req.Reply(ok, nil)
			}
		}(requests)
	}
	return nil
}

func PrintDiscardRequests(in <-chan *ssh.Request) {
	for req := range in {
		log.Println("Discarding ssh request", req.Type, *req)
		if req.WantReply {
			req.Reply(false, nil)
		}
	}
}

but it did not work

1

when i debug your code, i found op code is 200(ssh_FXP_EXTENDED), but in switch loop it did not handled.

debug like this

2

why ? can you fix it?

example RunServerHighLevel hangs

It gets stuck in c.readyChan <- e, this fixes it:

diff --git i/example/runserver_highlevel.go w/example/runserver_highlevel.go
index 878d011..8fb7cd8 100644
--- i/example/runserver_highlevel.go
+++ w/example/runserver_highlevel.go
@@ -19,6 +19,7 @@ func RunServerHighLevel(hostport string, fs sftpd.FileSystem) {
                return
        }
        cfg.AddHostKey(hkey)
+       cfg.Init()

        log.Printf("Listening on %s user %s pass %s\n", hostport, testUser, testPass)
        cfg.RunServer()

ReadDir problem with Filezilla and ls -l, support for Long Name?

It started after I realized that with FileZilla, directories are detected as directory only if their name starts with letter "d" (which is very strange).
Also with Linux's sftp client, "ls -l" does not show the files details (just names)

Then I come across this line and saw this FIXME
https://github.com/taruti/sftpd/blob/master/server.go#L216

The format of Long Name is simple, like
https://github.com/pkg/sftp/blob/master/server_unix.go#L129

But the marshaling/encoding syntax (.B32 stuff) looks very strange to me. And I have no idea about the binary format.
Since we need the FileZilla problem be fixed for some of our customers, what can I do to fix this problem?

Attr.FillFrom never fails, remove error return

Hi. I was cleaning old files and stumbled on an edited copy of this package. I think I made this change originally while trying to implement a bridge between sftp and something else, perhaps FUSE. Anyway, I figured better not lose it, so here goes. This is trivial enough that I feel that copyright does not apply, and anyway gift this contribution to you wholly to as you wish:

commit fac378d136eaa2dc7b5cc1e19ffe069ce29aaa0e (HEAD -> master)
Author: Tommi Virtanen <[email protected]>
Date:   2016-04-11 16:40:55 -0700

    Attr.FillFrom never fails, remove error return

diff --git a/example/dir_fs.go b/example/dir_fs.go
index 16919cb..5c4e3d0 100644
--- a/example/dir_fs.go
+++ b/example/dir_fs.go
@@ -96,7 +96,7 @@ func (fs readOnlyDirFs) Stat(name string, islstat bool) (*sftpd.Attr, error) {
                return nil, e
        }
        var a sftpd.Attr
-       e = a.FillFrom(fi)
+       a.FillFrom(fi)
 
-       return &a, e
+       return &a, nil
 }
diff --git a/file.go b/file.go
index 6029471..2cd0346 100644
--- a/file.go
+++ b/file.go
@@ -58,13 +58,12 @@ type FileSystem interface {
 }
 
 // FillFrom fills an Attr from a os.FileInfo
-func (a *Attr) FillFrom(fi os.FileInfo) error {
+func (a *Attr) FillFrom(fi os.FileInfo) {
        *a = Attr{}
        a.Flags = ATTR_SIZE | ATTR_MODE
        a.Size = uint64(fi.Size())
        a.Mode = fi.Mode()
        a.MTime = fi.ModTime()
-       return nil
 }
 
 func fileModeToSftp(m os.FileMode) uint32 {
diff --git a/server_test.go b/server_test.go
index 9958321..07cf8c6 100644
--- a/server_test.go
+++ b/server_test.go
@@ -288,7 +288,7 @@ func (fs rfs) Stat(name string, islstat bool) (*Attr, error) {
                return nil, e
        }
        var a Attr
-       e = a.FillFrom(fi)
+       a.FillFrom(fi)
 
-       return &a, e
+       return &a, nil
 }

sftpd connection errored: ssh: no common algorithms

I use you the package that named "githut.com/taruti/sftpd"

my code blow

func main(){
e := RunServer("192.168.1.203:2200",&IMP{})
if e !=nil{
fmt.Printf("run failed,err:%v",e)
}
}
// Run a server serving a given filesystem
func RunServer(hostport string, fs sftpd.FileSystem) error {
config := &ssh.ServerConfig{
PasswordCallback: sshutil.CreatePasswordCheck(testUser, testPass),
}
config.KeyExchanges = append(config.KeyExchanges,ssh.KeyAlgoDSA,ssh.KeyAlgoECDSA256,ssh.KeyAlgoECDSA384,ssh.KeyAlgoECDSA521,ssh.KeyAlgoRSA)

hkey, e := sshutil.KeyLoader{Flags: sshutil.Create}.Load()
if e != nil {
    return e
}

config.AddHostKey(hkey)

listener, e := net.Listen("tcp", hostport)
if e != nil {
    return e
}

log.Printf("Listening on %s user %s pass %s\n", hostport, testUser, testPass)

for {
    conn, e := listener.Accept()
    if e != nil {
        return e
    }
    go HandleConn(conn, config, fs)
}

}

and i has this question blow,linux shell stdout is blow
[root@localhost bin]# ./main
2015/06/18 14:56:54 Listening on 192.168.1.203:2200 user root pass 123

2015/06/18 14:56:57 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:57:39 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:57:48 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:57:57 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:58:07 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:58:16 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:58:25 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:58:35 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:58:44 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:58:53 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:59:02 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:59:12 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:59:21 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:59:30 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:59:40 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:59:49 sftpd connection errored: ssh: no common algorithms
2015/06/18 14:59:58 sftpd connection errored: ssh: no common algorithms
2015/06/18 15:00:07 sftpd connection errored: ssh: no common algorithms
2015/06/18 15:00:17 sftpd connection errored: ssh: no common algorithms
2015/06/18 15:00:26 sftpd connection errored: ssh: no common algorithms
2015/06/18 15:00:35 sftpd connection errored: ssh: no common algorithms
2015/06/18 15:00:44 sftpd connection errored: ssh: no common algorithms
2015/06/18 15:01:57 sftpd connection errored: ssh: no common algorithms

I use winscp as my client tool

I have tried very possibe algorithms in golang offcial package <golang.org/x/crypto/ssh>
I also has this error ,please tell me how i encounterd this problem,and how i can solve this problem

from yuyang
i will thank all the help i can get

Sending errror open: no such file or directory

Hi

[user@pc example]$ cd example
[user@pc example]$ ls -la /tmp/test-sftpd/
drwx------.  2 user  user    40 окт  8 18:49 .
drwxrwxrwt. 26 root root 4400 окт  8 19:22 ..
[user@pc example]$ 

in main.go

package main
func main() {
    // go RunServerHighLevel("127.0.0.1:2023", synthetic{})
    // go RunServerHighLevel("127.0.0.1:2023", rfs{})

    go RunServerLowLevel("127.0.0.1:2024", rfs{})
    // go RunServerLowLevel("10.1.1.64:2024", rfs{})
    <-make(chan int)
}

try put file

echo "put foo foo" | sftp -v -oPort=2024 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null test@localhost
[user@pc example]$ go build  -tags debug
[user@pc example]$ ./example 
2015/10/08 19:14:01 Listening on 127.0.0.1:2024 user test pass xf9XZgR5T3PV63nL
2015/10/08 19:14:22 CR op=INVALID:1 data len=4
2015/10/08 19:14:22 Data 00000003
2015/10/08 19:14:22 CR op=ssh_FXP_REALPATH data len=9
2015/10/08 19:14:22 Data 00000001000000012E
2015/10/08 19:14:22 realpath: mapping . => / <nil>
2015/10/08 19:14:22 CR op=ssh_FXP_STAT data len=12
2015/10/08 19:14:22 Data 00000002000000042F666F6F
2015/10/08 19:14:22 stat/lstat /foo => <nil> stat /tmp/test-sftpd/foo: no such file or directory
2015/10/08 19:14:22 Sending sftp error code ssh_FX_FAILURE
2015/10/08 19:14:22 CR op=ssh_FXP_OPEN data len=24
2015/10/08 19:14:22 Data 00000003000000042F666F6F0000001A00000004000001A4
2015/10/08 19:14:22 Sending errror open /tmp/test-sftpd/foo: no such file or directory
2015/10/08 19:14:22 Sending sftp error code ssh_FX_FAILURE
2015/10/08 19:14:22 sftpd servechannel failed: EOF

Error only put, get is worked.
Tnx

Encryption Protocols?

Which encryption protocols are supported by default, and where can I change them? Thank you!

read dir

read dir can`t show which is directory and not parent directory
my code is blow

func(dir *IMPDIR)Readdir(count int)([]sftpd.NamedAttr,error){
fmt.Printf("readdir:%v\n",dir.dir.Name())
fis, e := dir.dir.Readdir(count)
if e != nil {
return nil, e
}
nas := make([]sftpd.NamedAttr, len(fis))
for i, fi := range fis {
nas[i].Name = fi.Name()
e := nas[i].FillFrom(fi)
if e != nil{
fmt.Printf("fill from os.FIle failed,err:%v\n",e)
}
}
return nas, nil
}

almost the same as the sftp package example

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.