SFTP support for the go.crypto/ssh package

Related tags

go sftp
Overview

sftp

The sftp package provides support for file system operations on remote ssh servers using the SFTP subsystem. It also implements an SFTP server for serving files from the filesystem.

CI Status Go Reference

usage and examples

See https://pkg.go.dev/github.com/pkg/sftp for examples and usage.

The basic operation of the package mirrors the facilities of the os package.

The Walker interface for directory traversal is heavily inspired by Keith Rarick's fs package.

roadmap

  • There is way too much duplication in the Client methods. If there was an unmarshal(interface{}) method this would reduce a heap of the duplication.

contributing

We welcome pull requests, bug fixes and issue reports.

Before proposing a large change, first please discuss your change by raising an issue.

For API/code bugs, please include a small, self contained code example to reproduce the issue. For pull requests, remember test coverage.

We try to handle issues and pull requests with a 0 open philosophy. That means we will try to address the submission as soon as possible and will work toward a resolution. If progress can no longer be made (eg. unreproducible bug) or stops (eg. unresponsive submitter), we will close the bug.

Thanks.

Issues
  • Incoming packet was garbled on decryption w/ winscp

    Incoming packet was garbled on decryption w/ winscp

    I'm using this code. It mostly works, except when copying a large file with WinSCP I get the error "Incoming packet was garbled on decryption" and I have to keep reconnecting.

    According to the WinSCP docs this could be because of miscomputing SSH-2 encryption keys, or ignoring max packet lengths. I tried enabling both workarounds in WinSCP but to no avail.

    Entirely possible my code is doing something wrong (I really have very little idea how SSH works; it's mostly copy-pasta). Buuut it could also be a bug in this code, so .... any ideas?

    opened by Timmmm 48
  • Performance regression from v1.12.0 to v1.13.0 (and master)

    Performance regression from v1.12.0 to v1.13.0 (and master)

    While investigating https://github.com/rclone/rclone/issues/5197 I discovered that doing transfers to rsync.net had gone from 300 KB/s in v1.12.0 to 100KB/s in v1.13.0

    The rsync.net servers run FreeBSD which is one unusual thing about them and the other is that they are a long way away from me (150ms) so have the usual problems with long fat TCP pipes. Rclone uses the ReadFrom interface in the sftp client so that the sftp library can increase the number of outstanding packets to help with this.

    Here are some tests (my upload is capable of 2MB/s).

    make && rclone version && rclone copy -vv --stats 10s /tmp/499.91M rsyncnet: 2>&1 | grep 499.91M:
    

    v1.12.0

     *                                       499.91M:  0% /499.910M, 312.432k/s, 27m8s
     *                                       499.91M:  1% /499.910M, 309.264k/s, 27m15s
     *                                       499.91M:  1% /499.910M, 281.361k/s, 29m49s
     *                                       499.91M:  2% /499.910M, 312.820k/s, 26m37s
     *                                       499.91M:  3% /499.910M, 347.230k/s, 23m48s
    

    v1.13.0

     *                                       499.91M:  0% /499.910M, 81.331k/s, 1h44m44s
     *                                       499.91M:  0% /499.910M, 97.554k/s, 1h27m8s
     *                                       499.91M:  0% /499.910M, 98.655k/s, 1h25m59s
     *                                       499.91M:  0% /499.910M, 122.371k/s, 1h9m7s
     *                                       499.91M:  1% /499.910M, 122.173k/s, 1h9m4s
    

    master

     *                                       499.91M:  0% /499.910M, 109.761k/s, 1h17m33s
     *                                       499.91M:  0% /499.910M, 102.153k/s, 1h23m11s
     *                                       499.91M:  0% /499.910M, 91.254k/s, 1h32m58s
     *                                       499.91M:  0% /499.910M, 85.305k/s, 1h39m18s
     *                                       499.91M:  0% /499.910M, 76.641k/s, 1h50m23s
    

    I bisected this change and discovered this commit is probably the problem. I'm reasonably sure that is the problem commit, and it is certainly touching the code in question. Before this commit at 0be6950c0e91d5cb73a4d690270d3a5010ac9808 the performance is definitely OK and after it is is bad. However there is some variation after the commit so there may be more commits involved.

    commit fc156996912168806d33b55794e2f5436fae2c3d Author: Cassondra Foesch Date: Sun Feb 21 20:32:09 2021 +0000

    fixed concurrent writes, mid-polish
    

    client.go | 614 ++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 373 insertions(+), 241 deletions(-)

    Cc: @puellanivis

    opened by ncw 32
  • More optimization

    More optimization

    • MarshalBinary for packets must now include 4 empty bytes at the start for filling in the length of the packet.
    • Packets may now implement marshalPacket that can return both the packet and payload as separate byte-slices, allowing the payload to be written separately without having to copy it into a separate marshaled packet slice first.
    • rigorously define behavior of chan result in sending packets to the server to guarantee at-most-once delivery on each channel, meaning we can halve the space overhead from allocating a buffered channel (happens nearly every request).
    • fix a write-read race condition in request-server_test.go
    • fix a bunch of edge-cases in client_integration_test.go that were causing integration tests to lock up, be flaky or just not work.
    • implement WriterAt
    • new concurrency model of Map→Worker→Reduce for better high-latency concurrency in: ReadAt, WriteAt, ReadFrom.
    • if a ReadAt or WriteAt can be done in one request, short-circuit concurrency and just do the request straight
    • try and guess if a ReadFrom can be done in one request, and short-circuit to a synchronous loop (this is to be absolutely sure the io.Reader is read to io.EOF, even though it’s strongly likely that it will only ever run one loop.)
    • TODO: currently pondering how best to do WriteTo efficiently with the Map→Worker→Reduce paradigm. For sure though, it won’t end up as similar as the other three are to each other.
    opened by puellanivis 30
  • Incomplete downloads

    Incomplete downloads

    Since upgrading to 1.13 the library will often report EOF before a file opened with Client.Open() is downloaded completely. For example a 634618 byte file has stopped downloading after just 65536 bytes, and a 2367599 byte file after 2031616.

    As a workaround I've added a call to File.Stat().Size(), which returns the correct file size, and compare that with the downloaded size to check for success.

    opened by mrwonko 29
  • ws_ftp and packet order

    ws_ftp and packet order

    Hi,

    using ws ftp pro (trial latest version) library seems to have issues. This can be replicated using the sftp-server example, having for example 20 files with small amount of data, I tested 22 bytes.

    Using command "C:\Program Files (x86)\Ipswitch\WS_FTP 12\wsftppro.exe" -s sftp-lib-conf:/path_to/github.com/pkg/sftp/examples/sftp-server/testfile* -d local:C:\temp\

    Some of the files come as empty. Also sometimes just changing the directory in UI fails.

    I think this is related to packets coming/going in wrong order. Temporary fix that I found was to set SftpServerWorkerCount=1

    I debugged the issue and failing transfers it seems to read with offset greater than filesize, when server responds EOF the next packet with offset zero and correct data seems to be ignored by the client.

    In succesfull transfers offset zero packet seems to come first.

    This issue is not in openssh server, it seems to always receive offset zero first.

    Mikko.

    bug 
    opened by purha 29
  • REALPATH which returns /. causes Cyberduck to error

    REALPATH which returns /. causes Cyberduck to error

    We have noticed that Cyberduck versions 4-6 (as far as we've tested) do not properly handle the following case when the library returns the following path:

    '/.'

    Our use-case is in a jailing SFTP, which we use the request-server to handle processing the requests by the clients differently.

    We found that when the client requests '.', the library returns "/." (which is not a true absolute path) as the return, then Cyberduck pukes, and we have no way to recover.

    Naturally, this used to work before with this library, so something changed within the SFTP library to cause this.

    This is the log we got from Cyberduck, pointing to the use of the Realpath being the cause: https://gist.github.com/LordRalex/61b71bfac43232be8ef89068d2495e00

    I have found the change which introduced this bug: https://github.com/pkg/sftp/commit/4d7bb970c49d8a86d12e2cd34952dc80dbc7cb0d#diff-412115c53c6c5fea203e8253f32d2645

    In particular, this line of code was removed: https://github.com/pkg/sftp/commit/4d7bb970c49d8a86d12e2cd34952dc80dbc7cb0d#diff-412115c53c6c5fea203e8253f32d2645L186-189

    Before: /. is transformed to / After: /. is returned to the client

    This was a breaking change to the Cyberduck client, and so causes our application to therefore break.

    Since /. is not a true absolute path, this code should be re-introduced.

    bug 
    opened by LordRalex 27
  • "File does not exist" when copying remote file - SFTP client

    I really wanted this to be a last resort, but I'm at my wits end trying to figure this out. My code is at the bottom. The main error I keep getting when using the typical configuration is "file does not exist." WinSCP has no issues.

    Things I've tried:

    1. Attempted the same operation using RClone to make sure my code is not the issue (see https://forum.rclone.org/t/sftp-remote-to-local-copy-failed-to-copy-file-does-not-exist/14414/2). RClone fails with the "File does not exist" error.

    2. sftp.NewClient(conn) with sftpClient.Open(srcInvPath) - Received the error: "File does not exist"

    3. sftp.NewClient(conn, sftp.MaxPacket(20480)) with sftpClient.OpenFile(srcInvPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC) - Received the error: "read from 13 for 20480 from 20497 not supported. (SSH_FX_FAILURE)"

    4. sftp.NewClient(conn) with sftpClient.OpenFile(srcInvPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC) - Received the error: "read from 13 for 32768 from 32785 not supported. (SSH_FX_FAILURE)"

    5. sftp.NewClient(conn) with sftpClient.OpenFile(srcInvPath, 0700) - Received the error : "EOF". Have no idea why I tried this.

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"log"
    	"os"
    	"path"
    	"path/filepath"
    	"regexp"
    	"strings"
    
    	"github.com/pkg/sftp"
    	"golang.org/x/crypto/ssh"
    )
    
    var invImpRootPath = "C:\\Invoices\\"
    var invImpErrPath = filepath.Join(invImpRootPath, "Errors")
    var invImpProcPath = filepath.Join(invImpRootPath, "Processed")
    var invRegExp = regexp.MustCompile(`(?m)^(Invoice)\.([0-9]*)\.([0-9]*)\.([0-9]{1,5})\.xml$`)
    var sftpInvPath = "/Invoices/outbound"
    
    func main() {
    	err := os.MkdirAll(invImpRootPath, os.ModeDir)
    	if err != nil {
    		fmt.Printf("Error creating Invoices directory: %s", err.Error())
    		panic(err)
    	}
    
    	err = os.MkdirAll(invImpErrPath, os.ModeDir)
    	if err != nil {
    		fmt.Printf("Error creating Errors directory: %s", err.Error())
    		panic(err)
    	}
    
    	err = os.MkdirAll(invImpProcPath, os.ModeDir)
    	if err != nil {
    		fmt.Printf("Error creating Processed directory: %s", err.Error())
    		panic(err)
    	}
    
    	user := {removed}
    	pass := {removed}
    	host := {removed}
    	port := "22"
    
    	hostKey := getHostKey(host)
    	config := &ssh.ClientConfig{
    		User: user,
    		Auth: []ssh.AuthMethod{
    			ssh.Password(pass),
    		},
    		HostKeyCallback: ssh.FixedHostKey(hostKey),
    	}
    
    	conn, err := ssh.Dial("tcp", host+":"+port, config)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer conn.Close()
    
    	sftpClient, err := sftp.NewClient(conn, sftp.MaxPacket(20480))
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer sftpClient.Close()
    
    	files, err := sftpClient.ReadDir(sftpInvPath)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	for _, file := range files {
    		srcInvPath := path.Join(sftpInvPath, file.Name())
    		dstInvPath := filepath.Join(invImpRootPath, file.Name())
    
    		dstFile, err := os.Create(dstInvPath)
    		if err != nil {
    			log.Fatal(err)
    		}
    		defer dstFile.Close()
    
    		srcFile, err := sftpClient.OpenFile(srcInvPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC)
    		if err != nil {
    			log.Fatal(err) 
    		}
    
    		bytes, err := io.Copy(dstFile, srcFile)
    		if err != nil {
    			log.Fatal(err)
    		}
    		fmt.Printf("%d bytes copied\n", bytes)
    
    		err = dstFile.Sync()
    		if err != nil {
    			log.Fatal(err)
    		}
    	}
    }
    
    func getHostKey(host string) ssh.PublicKey {
    	// parse OpenSSH known_hosts file
    	// ssh or use ssh-keyscan to get initial key
    	file, err := os.Open("known_hosts")
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer file.Close()
    
    	scanner := bufio.NewScanner(file)
    	var hostKey ssh.PublicKey
    	for scanner.Scan() {
    		fields := strings.Split(scanner.Text(), " ")
    		if len(fields) != 3 {
    			continue
    		}
    		if strings.Contains(fields[0], host) {
    			var err error
    			hostKey, _, _, _, err = ssh.ParseAuthorizedKey(scanner.Bytes())
    			if err != nil {
    				log.Fatalf("error parsing %q: %v", fields[2], err)
    			}
    			break
    		}
    	}
    
    	if hostKey == nil {
    		log.Fatalf("no hostkey found for %s", host)
    	}
    
    	return hostKey
    }
    

    Server information from WinSCP:

    Snipaste_2020-02-19_12-34-59

    Snipaste_2020-02-19_12-34-15

    Snipaste_2020-02-19_12-33-41

    Thank you!

    question 
    opened by newdayrising 26
  • Provide some FS API for Server

    Provide some FS API for Server

    In my project I would like to use github.com/pkg/sftp as an embedded SFTP server. Would be nice to make Server more extendable in terms of working with FS or having the following features:

    1. Restrict user to use only specific directory (e.g. chroot)
    2. Provide some kind of notifications when file upload is completed or user session is closed

    In my pull request #94 I've moved all file operations into FileStorageBackend and made it replaceable. Maybe this solution is little bit dirty so let's workshop here the better solution

    opened by an2deg 25
  • "File does not exist" every time when using OpenFile

    As i said in the title, I get "File does not exist" every time when using OpenFile. I can successfully call Open on the same file without any error, and am wondering what is causing this issue.

    Thank you

    question 
    opened by ericcancil 24
  • request-server and long directory list

    request-server and long directory list

    Hi,

    I get errors when listing directory with high amount of files:

    sftp> cd bigdir
    sftp> ls
    Received message too long 4317039
    

    I used simple bash script to create test files:

    #!/bin/bash
    NUM=25000
    
    for i in $(seq 1 $NUM); do
      echo "this is file number $i" > "testfile_xxxxxxxxx-xxxxxxxx-xxxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxx-$i.txt" 
    done
    

    I manually tried to adjust maxTxPacket but with no luck.

    Br, Mikko

    bug enhancement 
    opened by purha 23
  • Bug: wrong error message returned by Client.Remove

    Bug: wrong error message returned by Client.Remove

    Hi, Great job! I really appreciate your effort for maintaining this library! I mainly use your library inside a proprietary Big Data project, that is running in production since 2 years ago, using Linux VMs in the cloud, and moves many TBs of data per day.

    func (c *Client) Remove(path string) error can return an error for many reasons, of course. In most cases, the library just works fine.

    If Remove is called for removing just a file (and not a directory), in some cases I experienced that Remove can return an error containing this message: "Not a directory". In my opinion, it is a bug.

    Looking at the Remove implementation, I see that, in case err.Code is equal to sshFxFailure or if there is a permission error, the returned error is the one got from RemoveDirectory. I think if Remove is called for removing a file, it should never return an error with a message like "Not a directory".

    I would suggest this fixed implementation:

    func (c *Client) Remove(path string) error {
    	err := c.removeFile(path)
    	// some servers, *cough* osx *cough*, return EPERM, not ENODIR.
    	// serv-u returns ssh_FX_FILE_IS_A_DIRECTORY
    	// EPERM is converted to os.ErrPermission so it is not a StatusError
    	if err2, ok := err.(*StatusError); ok {
    		switch err2.Code {
    		case sshFxFailure:
    			if c.RemoveDirectory(path) == nil { return nil }
    			return err
    		case sshFxFileIsADirectory:
    			return c.RemoveDirectory(path)
    		}
    	}
    	if os.IsPermission(err) {
    		if c.RemoveDirectory(path) == nil { return nil }
    	}
    	return err
    }
    

    Thanks for your attention.

    opened by awaken 6
  • StatVFS is flaky

    StatVFS is flaky

    There is a race-condition where we ask for a StatVFS, and then check it against the current results. This has one a number of occasions caused tests to fail, despite being correct code. Usually, the problem is the filesystem changed in between the asking for the StatVFS, and checking the result.

    We should find some kind of way of making this deterministic.

    opened by puellanivis 0
  • RealPathFileLister

    RealPathFileLister

    How do I use this interface to customize the start directory?

    type RealPathFileLister interface {
    	FileLister
    	RealPath(string) string
    }
    

    I do see this in request-example.go:

    // implements RealpathFileLister interface
    func (fs *root) Realpath(p string) string {
    	fs.startDirectory = "/test"
    
    	if fs.startDirectory == "" || fs.startDirectory == "/" {
    		return cleanPath(p)
    	}
    	return cleanPathWithBase(fs.startDirectory, p)
    }
    

    Do I implement the RealPath method and change the dir there? My apologies in advance for asking a basic question.

    opened by d4z3x 0
  • Windows issues with current directory and drive changes

    Windows issues with current directory and drive changes

    Hi,

    I am encountering issues while trying to implement an SFTP connection over my SSH session ( handled by github.com/gliderlabs/ssh).

    Here is the snippet I am using to reproduce the bug:

    package main
    
    import (
    	"fmt"
    	"io"
    	"log"
    	"os"
    
    	"github.com/gliderlabs/ssh"
    	"github.com/pkg/sftp"
    )
    
    const PORT uint16 = 31337
    const PASSWORD string = "Hello!"
    
    var (
    	logger = log.New(os.Stdout, "SFTP: ", 0)
    )
    
    func getPasswordHandler(password string) func(ssh.Context, string) bool {
    	return (func(ctx ssh.Context, user_password string) bool {
    		return user_password == password
    	})
    }
    
    func SftpHandler(sess ssh.Session) {
    
    	logger.Printf("SFTP attempt")
    	debugStream := os.Stdout
    	serverOptions := []sftp.ServerOption{
    		sftp.WithDebug(debugStream),
    	}
    	server, err := sftp.NewServer(
    		sess,
    		serverOptions...,
    	)
    	if err != nil {
    		logger.Printf("sftp server init error: %s", err)
    		return
    	}
    	if err := server.Serve(); err == io.EOF {
    		server.Close()
    		logger.Printf("sftp client exited session.")
    	} else if err != nil {
    		logger.Printf("sftp server completed with error: %s", err)
    	}
    
    }
    
    func main() {
    
    	server := ssh.Server{
    		Addr:            fmt.Sprintf("0.0.0.0:%d", PORT), // IP and PORT to connect on
    		PasswordHandler: ssh.PasswordHandler(getPasswordHandler(PASSWORD)),
    		SubsystemHandlers: map[string]ssh.SubsystemHandler{
    			"sftp": SftpHandler,
    		},
    	}
    
    	logger.Printf("Listening os %d", PORT)
    	err := server.ListenAndServe()
    	if err != nil {
    		logger.Printf("Failed to start the SSH server: %s", err)
    	}
    
    }
    

    I might be doing something wrong .. However it works perfectly on Linux and OSX !

    Screenshot 2021-06-29 at 11 45 51

    opened by SakiiR 6
  • Getting Windows `go test -integration` working

    Getting Windows `go test -integration` working

    I figured, I have everything necessary to give this a shot, what could possibly go wrong? Maybe it would expose the issue with the io.Copy mentioned in #433 ? I’ve jotted down an example of some generic classes of errors below.

    What assumption did we make wrong here?

    client_integration_test.go:752: Getwd: wanted absolute path, got "/C:/Users/snowgirl/Work/sftp"
    

    Intriguing, symlinks aren’t working, we likely need admin rights for symlinks in Windows:

    client_integration_test.go:773: symlink C:\Users\snowgirl\AppData\Local\Temp\sftptest-readlink416952039\file C:\Users\snowgirl\AppData\Local\Temp\sftptest-readlink416952039\symlink: A required privilege is not held by the client.
    

    Not sure how these handles are being left open:

    sftp server file with handle "1" left open: C:\Users\snowgirl\AppData\Local\Temp\sftptest-readdeadlock065051590/writeTest
    ``̀ 
    
    Error message doesn’t even say what file:
    `̀ `
    server_integration_test.go:617: C:\Windows\System32\OpenSSH\sftp.exe: exit status 1: Couldn't stat remote file: Failure
    

    😬

    server_integration_test.go:694: put: local /tmp/sftp.65b523619ba1776cc46bf73a4337dd8d remote /tmp/sftp.ae0dc63945ea2295246a74b92d609d22
    server_integration_test.go:699: open /tmp/sftp.65b523619ba1776cc46bf73a4337dd8d: The system cannot find the path specified.
    $ grep -r tmp
    server_integration_test.go:     tmpDirRemote := "/tmp/" + randName()
    

    Where is this weird , output coming from?

    --- FAIL: TestServerPutRecursive (0.06s)
        server_integration_test.go:869: put recursive: local C:\Users\snowgirl\Work\sftp remote /tmp/sftp.27a44279ebd0fbbb08777194541b8adb
        server_integration_test.go:873: runSftpClient failed: C:\Windows\System32\OpenSSH\sftp.exe: exit status 1: Couldn't stat remote file: Failure
            , output
    
    
    opened by puellanivis 2
  • Refactor: Start using filexfer

    Refactor: Start using filexfer

    So, I’m checking in and pushing a PR very early here, so that others can get a sense of how the client refactor will look like after integrating the filexfer.

    The early attention here should be on the Client.close() function, which felt would be the quickest way to show off how things would change. The changes to Conn and clientConn are to support the changes in the close() function, and allow for a parallel old-way/new-way hand-off from one set of wheels to the other while the car is still running. Before the PR is merged, it will eventually only have the new-way.

    opened by puellanivis 6
  • Proposal: io/fs presents us an opportunity to rework the whole api into a v2

    Proposal: io/fs presents us an opportunity to rework the whole api into a v2

    Most of the proposal is right there in the title. What with io/fs being rolled out in go1.16, we have a big opportunity to remodel, simplify, and rework our API. Current issues, as I see them:

    • The current sftp.Client implements github.com/kr/fs, but we could switch to model more compatible with io/fs.FS
    • The in-memory test filesystem cannot be removed from the main package without a breaking change, ideally if kept, this should be a subpackage.
    • The ErrSshFxXyz errors are still around, because they cannot be removed without a breaking change.
    • The RequestServer and Server implementations are significantly different and almost parallel implementations.
    • The RequestServer could be better implemented via a base interface with additional extension interfaces. (à la io/fs)
    • From an earlier discussion, many of the raw implementation concepts of the protocol itself could be isolated into its own subpackage, providing a better separation of responsibilities.
    • Some features can be reassessed for utility, and either properly folded into functionality without needing feature flags (like the allocator?) or dropped entirely (we could switch WriteTo so that it does not depend upon filesizes, thus saving us the need of an UseFstat() option).
    opened by puellanivis 12
  • Support custom UID/GID

    Support custom UID/GID

    Hi,

    Currently there is no way in windows to provide UID/GID.

    I've implemented my own Filesystem but it seems on windows I can't send the uid and gid with my os.FileInfo as that doesn't seem to be implemented at all.

    https://github.com/pkg/sftp/blob/dcef9e0d4ab634fede2d5e625cadac1bfc91516b/attrs_stubs.go

    Is it possible to provide a way to return that informations from virtual filesystems no matter what OS?

    Maybe provide a custom Sys() result object and check if the interface returned from Sys() is that type instead of using syscall.Stat_t directly?

    enhancement 
    opened by WolfspiritM 2
  • client: Is there any way to create a file on the server with specific permissions?

    client: Is there any way to create a file on the server with specific permissions?

    It looks like neither Client.Create or Clilent.Open provide a way to specify the file mode (e.g. 0640) when creating a file. I see that I can use Chmod once the file exists, but that leaves a window open where the file is accessible using the default permissions. Is there some way around this?

    enhancement question 
    opened by toby-allsopp 7
  • sending exit-status before close

    sending exit-status before close

    I just fixed restic (https://restic.net/) compatibility with sftpgo in this commit

    https://github.com/drakkan/sftpgo/commit/5be1d1be699cd0cbe97218a42d1b011197df900f#diff-4ab88e083a7cb08083127ded5444ac8eR340

    the problem is that pkg/sftp does not send the exit-status.

    Maybe you could be interested to send the exit-status here:

    https://github.com/pkg/sftp/blob/master/request-server.go#L178

    setting the status to 0 if err == io.EOF otherwise 1.

    I'm too busy to send a patch now, sorry

    enhancement 
    opened by drakkan 0
Releases(v1.13.3)
  • v1.13.3(Sep 5, 2021)

    [GH-467] BUGFIX: Statfs was not populating its respond ID, leading to clients receiving unexpected 0 request ids. [GH-455] Cleanup Request mutex usage [GH-456] Regrouping code, linting, and better longname LS formatting [GH-459] Add testing for go1.17, remove testing for go1.15

    Source code(tar.gz)
    Source code(zip)
  • v1.13.2(Jul 10, 2021)

    [GH-441] Use go errors instead of github.com/pkg/errors [GH-443] Sequentially issue read requests in ReadAt [GH-445] The server implementation can now handle Windows paths [GH-452] Fix long output for directory listing response

    Source code(tar.gz)
    Source code(zip)
  • v1.13.1(Jun 12, 2021)

    New features and bugfixes.

    Request Server:

    • [GH-437] Add support for a start directory

    Client:

    • [GH-439] Export a ReadFromWithConcurrency function that permits ensuring concurrency usage
    • [GH-430] Add the internal SSH filexfer module
    • [GH-435] Fix math overflows on 32-bit architectures
    • [GH-436] Sequentially issue read requests, fixes several data loss issues
    • add fuzzer support and fix some potential crashes
    • other minor improvements and bugfixes
    Source code(tar.gz)
    Source code(zip)
  • v1.13.0(Mar 7, 2021)

    New features and bugfixes.

    Request Server:

    • [GH-377] Add OpenFileWriter interface to allow a file to be opened for both reading and writing.
    • [GH-379] Add Lstat support.
    • [GH-392] Return io.EOF only if there is no error.
    • [GH-393] Fix handle leaks in error cases.
    • [GH-406] Add StatVFS support.
    • Add PosixRename support.

    Client:

    • [GH-385] Add Client.Extensiosn method to list supported server extensions.
    • [GH-386] Add support for [email protected].
    • [GH-397] Refactoring and performance improvements, implement WriterAt interface. Concurrent writes are not longer enabled by default for safety reasons. You can use the option UseConcurrentWrites if it's needed for your use case.
    • [GH-401] Use os.ErrPermission to map sshFxPermissionDenied.
    • [GH-408] Add an option to disable concurrent reads. This fix support for read once servers.
    • [GH-410] Expose RealPath method.

    Misc:

    • [GH-380] Fix build on Plan 9.
    • [GH-382] Server: use os.IsNotExist to map sshFxNoSuchFile.
    • [GH-384] Refactor memFile.
    • [GH-387] Tests: clean up temporary files.
    • [GH-389] Fix crash with zero bytes packets.
    • [GH-402] CI: switch from Travis to GitHub Actions.
    • CI: tests against Go versions { 1.15, 1.16 }, instead of { 1.14, 1.15 }
    Source code(tar.gz)
    Source code(zip)
  • v1.12.0(Aug 26, 2020)

    First release in some time. Fixing lots of bugs and adding io.ReaderAt compatibility of files, and various allocation and byte-slice optimizations courtesy of Nicola "@drakkan" Murino. Below are the highlights:

    Features: [GH-285] Implement io.ReaderAt interface on File struct. [GH-338] Remove an unnecessary allocate+copy when unmarshaling data packets. [GH-343] Allocate byte-slices anticipating full capacity to avoid allocate+copies when they are extended. [GH-344] Add an optional caching allocator, to allow reuse of buffers, rather than always allocating anew.

    Bugfixes: [GH-329] S_IFMT overridden for Windows, JS, WASM to the most prevalent POSIX value. [GH-337]: In integration tests, expect /usr/lib/ssh/sftp-server as a possible executable location. [GH-340]: Update golang.org/x/crypto to address vulnerability CVE-2020-9283 [GH-342]: Fix race condition between Connection and Close [GH-355]: cleanPath operates on remote paths, so always use path (POSIX) rather than filepath (local file system rules). [GH-363]: Fix some small unlikely RequestServer.Serve bugs. [GH-372]: Add mutex protection to internal File offset used by Read. [GH-373]: RequestServer incorrectly interpreted SSH_FXP_FSETSTAT as a "Put" request.

    Updates: [GH-365], [GH-376]: Update dependencies In [GH-344], [GH-373]: travis now tests against Go versions { 1.14, 1.15 }, instead of { 1.12, 1.13 }

    Source code(tar.gz)
    Source code(zip)
Owner
Artisanal, hand crafted, barrel aged, Go packages
null
Extended ssh-agent which supports git commit signing over ssh

ssh-agentx ssh-agentx Rationale Requirements Configuration ssh-agentx Configuration ssh-gpg-signer Linux Windows Signing commits after configuration T

Wim 3 May 18, 2021
Một script nho nhỏ viết bằng Go để crawl toàn bộ điểm thi THPTQG-2021

Crawl toàn bộ điểm thi THPTQG-2021 Một script nho nhỏ viết bằng Go để crawl toàn bộ điểm thi THPTQG-2021, mình đã crawl sẵn toàn bộ ở đây: https://dri

null 16 Sep 13, 2021
SFTP support for the go.crypto/ssh package

sftp The sftp package provides support for file system operations on remote ssh servers using the SFTP subsystem. It also implements an SFTP server fo

null 1k Sep 12, 2021
HTTP(S)/WS(S)/TCP Tunnels to localhost using only SSH.

An open source serveo/ngrok alternative.

Antonio Mika 2k Sep 23, 2021
tunnels to localhost and other ssh plumbing

remotemoe is a software daemon for exposing ad-hoc services to the internet without having to deal with the regular network stuff such as configuring VPNs, changing firewalls, or adding port forwards.

Kristian Mide 78 Sep 19, 2021
A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.

frp README | 中文文档 What is frp? frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. As of now, it s

null 48.5k Sep 22, 2021
LazySSH is an SSH server that acts as a jump host only, and dynamically starts temporary virtual machines.

LazySSH is an SSH server that acts as a jump host only, and dynamically starts temporary virtual machines. If you find yourself briefly starti

Stéphan Kochen 459 Jul 2, 2021
Test ssh login key acceptance without having the private key

ssh-key-confirmer This confirms if a SSH public key is listed as a authorized_key on a system Usage $ ssh-key-confirmer -i ./id_rsa.pub [email protected]

Ben Cox 47 Sep 23, 2021
Chisel is a fast TCP/UDP tunnel, transported over HTTP, secured via SSH.

Chisel is a fast TCP/UDP tunnel, transported over HTTP, secured via SSH. Single executable including both client and server. Written in Go (golang). Chisel is mainly useful for passing through firewalls, though it can also be used to provide a secure endpoint into your network.

Jaime Pillora 6.3k Sep 22, 2021
A simple UDP server to make a virtual secure channel with the clients

udpsocket I made this package to make a virtual stateful connection between the client & server using the UDP protocol for a golang game server (as yo

TheRedRad 4 Aug 29, 2021
Access my website from the terminal with SSH!

daniel.is-a.dev (ssh version) What is this? I built a SSH server written in Golang that lets you basically view my website all from the terminal. You

Hackermon 4 Aug 23, 2021
Concurrent ssh-tail sessions and sink option

ssh-tail This project is one of the problems that I generally face while debugging some system. When I am reproducing the issue on the machine i also

Yash Ladha 6 Jun 4, 2021
4chain is a simple、fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet.

4Chain What is 4chain? 4chain is a simple、fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. Using the ssh

null 4 Sep 4, 2021
Assembly-optimized MD4 hash algorithm in Go

md4 MD4 hash algorithm in Go. Assembly-optimized for amd64 platforms. MD4 is cryptographically broken and should should only be used where compatibili

Michael McLoughlin 12 Sep 14, 2021
Command-line tool and library for Windows remote command execution in Go

WinRM for Go Note: if you're looking for the winrm command-line tool, this has been splitted from this project and is available at winrm-cli This is a

Brice Figureau 328 Sep 10, 2021
The devs are over here at devzat, chat over SSH!

Devzat Where are the devs at? Devzat! Devzat is chat over SSH Try it out: ssh sshchat.hackclub.com Add this to ~/.ssh/config: Host chat HostName s

Ishan Goel 320 Sep 17, 2021
WebDAV server for SSH. Similar to sshfs but does not require proprietary MacFUSE on macOS

sshwebdav: WebDAV server for SSH sshwebdav provides a WebDAV server for a remote SSH host. sshwebdav is similar to sshfs but does not require propriet

Linux Machines 9 Sep 13, 2021
Fast Telegram client fully in go.

Telegram client, in Go. (MTProto API)

gotd 277 Sep 25, 2021