0

I am implementing SFTP Nodejs server script based on libssh (npm install ssh)

var config = require('config');
var fs = require('fs');
var path = require('path');
var libssh = require('ssh');

var server;
var options = {
    host: 'localhost',
    port: '3022',
    // Get the common name of ssh_keys
    host_key: config.get('logshipper.sftp.host_key'),
    // Root path of SFTP folder on the machine
    root: path.join(__dirname, config.get('logshipper.sftp.root')),
    test_username: 'correct_username',
    test_password: 'correct_password'
};

server = libssh.createServer({
    hostRsaKeyFile: __dirname + '/ssh_keys/' + 'rsa_' + options.host_key,
    hostDsaKeyFile: __dirname + '/ssh_keys/' + 'dsa_' + options.host_key
});

server.on('connection', function (session) {
    session.on('auth', function (message) {
        // Maybe check username/password
        return message.replyAuthSuccess();
    });

    session.on('channel', function (channel) {
        channel.on('subsystem', function (message) {
            if (message.subsystem == 'sftp') {
                message.replySuccess();
                message.sftpAccept();
            }
        });

        channel.on('sftp:realpath', function (message) {
            console.log('server cmd sftp:realpath');
            if (message.filename == '.' || (/\/$/).test(message.filename)) {
                message.replyName(path.join(options.root, message.filename), {
                    permissions: +libssh.Stat('777').dir()
                })
            } else {
                message.replyName(message.filename, {
                    permissions: +libssh.Stat('777').reg()
                })
            }
        });

        channel.on('sftp:stat', statHandle);

        function statHandle(message) {
            console.log('server cmd sftp:stat');

            var attrs = {
                permissions: +libssh.Stat(777).dir()
                , uid: 101
                , gid: 202
                , size: 100
                , atime: Date.now()
                , mtime: Date.now()
            };

            message.replyAttr(attrs)
        }

        // can be handled the same way as 'stat' if you like
        channel.on('sftp:lstat', statHandle);

        channel.on('sftp:opendir', function (message) {
            console.log('server cmd sftp:opendir');
            message.replyHandle(message.filename + '/');
        });

        var lastmsg;
        channel.on('sftpmessage', function (message) {
            lastmsg = message
        });

        channel.on('sftp:readdir', function (message) {
            console.log('server cmd sftp:readdir', message.handle);

            if (lastmsg.type == 'readdir') {
                return message.replyStatus('ok');
            }

            var readPath = message.handle;
            fs.readdir(readPath, function(err, files) {
                if (err) {
                    console.log(err);
                    throw err;

                } else {
                    files = files.map(function(file) {
                        return {
                            filename: file,
                            longname: file,
                            attrs: { permissions: +libssh.Stat(644).reg() }
                        };
                    });
                    return message.replyNames(files);
                }
            });
        });

        channel.on('sftp:close', function (message) {
            console.log('server cmd sftp:close');
            message.replyStatus('ok');
        })
    })
});

server.listen(options.port, options.host);
console.log('Listening on port ' + options.port);

Ubuntu 14.04, nodejs 0.10.25 In the sftp.root directory I have test-file I should be able to download to, check if it is on sftp server, etc.

When I use sftp (ubuntu cmd to connect to server I get):

sftp -P 3022 localhost
Connected to localhost.
sftp> dir
Couldn't read directory: No error
test-file  
sftp> 

Server output:

/usr/bin/node sftpServer.js
Listening on port 3022
server cmd sftp:realpath
server cmd sftp:opendir
server cmd sftp:readdir /home/MyFolder/uploads/
server cmd sftp:readdir /home/MyFolder/uploads/
server cmd sftp:close

Couldn't read directory: No error

But it is actually for a test, I would need to work with this server via lftp

lftp sftp://localhost:3022
lftp localhost:~> dir
ls: ls: Access failed:     
lftp localhost:~> 

I am getting access failed errors. I've tried to make folders chmod 777 or mark as root group and it did not help.

I hope somebody will look into it and help me to figure out why this access error appears, thanks!

Yegor Dia
  • 61
  • 1
  • 8

1 Answers1

1

The last replyNames should include EOF flag and the replyStatus must have the code SSH_FX_EOF. Otherwise the status is considered an error. Maybe this code would do:

        if (lastmsg.type == 'readdir') {
            return message.replyStatus('eof');
        }

It is useful to turn on debug in lftp to see the protocol messages, then compare successful vs unsuccessful sessions.

lav
  • 1,351
  • 9
  • 17