2015-03-17 04:41:14 +00:00
|
|
|
/* jslint node: true */
|
|
|
|
'use strict';
|
2014-10-17 02:21:06 +00:00
|
|
|
|
2015-03-17 04:41:14 +00:00
|
|
|
// ENiGMA½
|
2015-03-23 04:52:04 +00:00
|
|
|
var conf = require('../config.js');
|
|
|
|
var baseClient = require('../client.js');
|
2015-10-19 23:21:47 +00:00
|
|
|
var Log = require('../logger.js').log;
|
2015-03-23 04:52:04 +00:00
|
|
|
var ServerModule = require('../server_module.js').ServerModule;
|
2015-10-19 23:21:47 +00:00
|
|
|
var userLogin = require('../user_login.js').userLogin;
|
2015-10-20 21:39:33 +00:00
|
|
|
var enigVersion = require('../../package.json').version;
|
2015-10-20 04:33:11 +00:00
|
|
|
|
2015-03-17 04:41:14 +00:00
|
|
|
var ssh2 = require('ssh2');
|
|
|
|
var fs = require('fs');
|
2015-03-23 04:52:04 +00:00
|
|
|
var util = require('util');
|
2015-10-19 23:21:47 +00:00
|
|
|
var _ = require('lodash');
|
2014-10-17 02:21:06 +00:00
|
|
|
|
|
|
|
exports.moduleInfo = {
|
|
|
|
name : 'SSH',
|
|
|
|
desc : 'SSH Server',
|
2015-03-17 04:41:14 +00:00
|
|
|
author : 'NuSkooler'
|
2014-10-17 02:21:06 +00:00
|
|
|
};
|
|
|
|
|
2015-03-23 04:52:04 +00:00
|
|
|
exports.getModule = SSHServerModule;
|
2015-03-17 04:41:14 +00:00
|
|
|
|
2015-10-20 21:39:33 +00:00
|
|
|
/*
|
|
|
|
Hello,
|
|
|
|
|
|
|
|
If you follow the first server example in the `ssh2` readme and substitute the `session.once('exec', ...)` with `session.once('shell', ...)`
|
|
|
|
you should be fine. Just about all ssh clients default to an interactive shell session so that is what you will want to look for. As the
|
|
|
|
documentation notes, the `shell` event handler is just passed `accept, reject` with `accept()` returning a duplex stream representing
|
|
|
|
stdin/stdout. You can write to stderr by using the `stderr` property of the duplex stream object.
|
|
|
|
|
|
|
|
You will probably also want to handle the `pty` event on the session, since most clients (by default) will request a pseudo-TTY before
|
|
|
|
requesting an interactive shell. I believe this event may be especially useful in your case because the ssh client can send certain terminal
|
|
|
|
modes which can have relevance with your telnet usage. The event info also contains window dimensions which may help in determining layout
|
|
|
|
of your display (there is also a `window-change` event that contains these same dimensions whenever the client's screen/window dimensions
|
|
|
|
change).
|
|
|
|
|
|
|
|
If you are still having problems after making these changes, post your code somewhere and I will see if there is anything out of place.
|
|
|
|
Additionally, you can set `debug: console.log` in the server config object to show debug output which may be useful to see what is or isn't
|
|
|
|
being sent/received ssh protocol-wise.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2015-10-19 23:21:47 +00:00
|
|
|
function SSHClient(clientConn) {
|
2015-03-17 04:41:14 +00:00
|
|
|
baseClient.Client.apply(this, arguments);
|
|
|
|
|
2015-10-19 23:21:47 +00:00
|
|
|
//
|
|
|
|
// WARNING: Until we have emit 'ready', self.input, and self.output and
|
|
|
|
// not yet defined!
|
|
|
|
//
|
2015-03-17 04:41:14 +00:00
|
|
|
|
2015-10-19 23:21:47 +00:00
|
|
|
var self = this;
|
2015-03-17 04:41:14 +00:00
|
|
|
|
2015-10-19 23:21:47 +00:00
|
|
|
clientConn.on('authentication', function authentication(ctx) {
|
2015-10-20 04:33:11 +00:00
|
|
|
self.log.trace(
|
|
|
|
{
|
|
|
|
domain : ctx.domain,
|
|
|
|
username : ctx.username,
|
|
|
|
method : ctx.method,
|
|
|
|
}, 'SSH authentication');
|
2015-10-19 23:21:47 +00:00
|
|
|
|
|
|
|
// :TODO: check Config max failed logon attempts/etc.
|
|
|
|
|
|
|
|
switch(ctx.method) {
|
|
|
|
case 'password' :
|
|
|
|
// :TODO: Proper userLogin() here
|
|
|
|
self.user.authenticate(ctx.username, ctx.password, self, function authResult(err) {
|
|
|
|
if(err) {
|
|
|
|
ctx.reject();
|
|
|
|
} else {
|
|
|
|
ctx.accept();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'publickey' :
|
|
|
|
// :TODO:
|
|
|
|
ctx.reject();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'keyboard-interactive' :
|
|
|
|
if(!_.isString(ctx.username)) {
|
|
|
|
// :TODO: Let client know a username is required!
|
|
|
|
ctx.reject()
|
2015-03-17 04:41:14 +00:00
|
|
|
}
|
2015-10-19 23:21:47 +00:00
|
|
|
|
|
|
|
var PASS_PROMPT = { prompt : 'Password: ', echo : false };
|
|
|
|
|
|
|
|
ctx.prompt(PASS_PROMPT, function promptResponse(responses) {
|
|
|
|
if(0 === responses.length) {
|
|
|
|
return ctx.reject( ['keyboard-interactive'] );
|
|
|
|
}
|
|
|
|
|
|
|
|
userLogin(self, ctx.username, responses[0], function authResult(err) {
|
|
|
|
if(err) {
|
|
|
|
if(err.existingConn) {
|
|
|
|
// :TODO: Already logged in - how to let the SSH client know?
|
|
|
|
//self.term.write('User already logged in');
|
|
|
|
ctx.reject();
|
|
|
|
} else {
|
|
|
|
PASS_PROMPT.prompt = 'Invalid username or password\nPassword: ';
|
|
|
|
ctx.prompt(PASS_PROMPT, promptResponse);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ctx.accept();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
|
|
|
|
default :
|
2015-10-20 04:33:11 +00:00
|
|
|
self.log.info( { method : ctx.method }, 'Unsupported SSH authentication method');
|
2015-10-19 23:21:47 +00:00
|
|
|
ctx.reject();
|
2015-03-17 04:41:14 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-10-19 23:21:47 +00:00
|
|
|
clientConn.on('ready', function clientReady() {
|
|
|
|
self.log.info('SSH authentication success');
|
2015-03-19 05:08:23 +00:00
|
|
|
|
2015-10-19 23:21:47 +00:00
|
|
|
clientConn.on('session', function sess(accept, reject) {
|
2015-10-20 04:33:11 +00:00
|
|
|
|
|
|
|
var session = accept();
|
|
|
|
|
2015-10-20 21:39:33 +00:00
|
|
|
session.on('pty', function pty(accept, reject, info) {
|
2015-10-20 04:33:11 +00:00
|
|
|
console.log(info);
|
|
|
|
var channel = accept();
|
|
|
|
console.log(channel)
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
session.on('shell', function shell(accept, reject) {
|
|
|
|
var channel = accept();
|
|
|
|
|
2015-10-20 21:39:33 +00:00
|
|
|
self.setInputOutput(channel.stdin, channel.stdout);
|
2015-10-20 04:33:11 +00:00
|
|
|
|
|
|
|
self.emit('ready')
|
|
|
|
});
|
|
|
|
|
2015-03-19 05:08:23 +00:00
|
|
|
});
|
2015-03-17 04:41:14 +00:00
|
|
|
});
|
|
|
|
|
2015-10-19 23:21:47 +00:00
|
|
|
clientConn.on('end', function clientEnd() {
|
2015-10-20 04:33:11 +00:00
|
|
|
//self.emit('end');
|
2015-03-17 04:41:14 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-03-23 04:52:04 +00:00
|
|
|
util.inherits(SSHClient, baseClient.Client);
|
|
|
|
|
|
|
|
function SSHServerModule() {
|
|
|
|
ServerModule.call(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
util.inherits(SSHServerModule, ServerModule);
|
|
|
|
|
|
|
|
SSHServerModule.prototype.createServer = function() {
|
|
|
|
SSHServerModule.super_.prototype.createServer.call(this);
|
2015-03-17 04:41:14 +00:00
|
|
|
|
|
|
|
var serverConf = {
|
2015-10-19 23:21:47 +00:00
|
|
|
privateKey : fs.readFileSync(conf.config.servers.ssh.rsaPrivateKey),
|
2015-10-20 21:39:33 +00:00
|
|
|
banner : 'ENiGMA½ BBS ' + enigVersion + ' SSH Server',
|
|
|
|
ident : 'enigma-bbs-' + enigVersion + '-srv',
|
2015-10-19 23:21:47 +00:00
|
|
|
debug : function debugSsh(dbgLine) {
|
|
|
|
if(true === conf.config.servers.ssh.debugConnections) {
|
2015-10-20 21:39:33 +00:00
|
|
|
Log.trace('SSH: ' + dbgLine);
|
2015-10-19 23:21:47 +00:00
|
|
|
}
|
2015-10-20 04:33:11 +00:00
|
|
|
},
|
2015-03-17 04:41:14 +00:00
|
|
|
};
|
2014-10-17 02:21:06 +00:00
|
|
|
|
2015-03-17 04:41:14 +00:00
|
|
|
var server = ssh2.Server(serverConf);
|
2015-03-19 05:08:23 +00:00
|
|
|
server.on('connection', function onConnection(conn, info) {
|
2015-10-19 23:21:47 +00:00
|
|
|
Log.info(info, 'New SSH connection');
|
|
|
|
|
|
|
|
var client = new SSHClient(conn);
|
2015-10-20 21:39:33 +00:00
|
|
|
|
|
|
|
this.emit('client', client, conn._sock);
|
2014-10-17 02:21:06 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return server;
|
2015-03-23 04:52:04 +00:00
|
|
|
};
|