Created
February 22, 2011 08:58
-
-
Save paraboul/838390 to your computer and use it in GitHub Desktop.
APE SSH
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***************** Client-side ********************/ | |
APE.ssh = new Class({ | |
Extends: APE.Client, | |
initialize: function(container){ | |
this.term = null; | |
this.addEvent('load', this.start); | |
this.addEvent('ready', this.ready); | |
this.onRaw('ssh', this.shell); | |
}, | |
start: function() { | |
this.core.start(); | |
}, | |
ready: function() { | |
$('creds_form').addEvent('submit', function(ev) { | |
ev.stop(); | |
var form = $('creds_form'); | |
this.core.request.send('ssh', { | |
'cmd' :'connect', | |
'ip' :form.ip.get('value'), | |
'login' :form.login.get('value'), | |
'pass' :form.password.get('value') | |
}); | |
}.bind(this)); | |
}, | |
shell: function(raw, pipe) { | |
raw.data.state = raw.data.state || ''; | |
switch(raw.data.state) { | |
case 'connected': | |
$('creds').setStyle('display', 'none'); | |
this.term = new VT100($('vt100')); | |
this.term.keysPressed = function(ch) { | |
this.core.request.send('ssh', {'cmd':'data','data':B64.encode(ch)}); | |
}.bind(this) | |
break; | |
case 'data': | |
this.term.vt100(B64.decode(raw.data.value)); | |
break; | |
case 'error': | |
if (raw.data.value == 2) { | |
alert('Auth error'); | |
} else { | |
alert('Error ' + raw.data.value); | |
} | |
break; | |
} | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********* Server-side JS ************/ | |
Ape.addEvent("init", function() { | |
include("framework/mootools.js"); | |
include("utils/utils.js"); | |
Ape.addEvent('deluser', function(user) { | |
if (user.ssh != null) { | |
Ape.log('Connection closed'); | |
user.ssh.close(); | |
} | |
}); | |
Ape.registerCmd('ssh', true, function(params, cmd) { | |
params.cmd = params.cmd || ''; | |
params.data = params.data || ''; | |
switch(params.cmd) { | |
case 'data': | |
if (cmd.user.ssh != null) { | |
cmd.user.ssh.send(Ape.base64.decode(unescape(params.data))); | |
} | |
break; | |
case 'connect': | |
params.ip = params.ip || ''; | |
params.login = params.login || ''; | |
params.pass = params.pass || ''; | |
cmd.user.ssh = new Ape.SSH(params.ip, params.login, params.pass); | |
cmd.user.ssh.onShell = function() { | |
Ape.log('New connection'); | |
cmd.user.pipe.sendRaw('ssh', {'state':'connected'}); | |
} | |
cmd.user.ssh.onError = function(err) { | |
cmd.user.pipe.sendRaw('ssh', {'state':'error','value':err}); | |
delete cmd.user.ssh; | |
} | |
cmd.user.ssh.onRead = function(data) { | |
cmd.user.pipe.sendRaw('ssh', {'state':'data', 'value':Ape.base64.encode(data)}); | |
} | |
break; | |
} | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- /home/para/dev/APE/crash/APE_Server/modules/libape-spidermonkey.c 2010-11-29 00:17:35.000000000 +0100 | |
+++ libape-spidermonkey.c 2011-02-22 10:14:59.000000000 +0100 | |
@@ -27,6 +27,7 @@ | |
#include <mysac.h> | |
#endif | |
#include <jsapi.h> | |
+#include <libssh2.h> | |
#include <stdio.h> | |
#include <glob.h> | |
#include "plugins.h" | |
@@ -162,6 +163,34 @@ | |
static struct _ape_mysql_queue *apemysql_push_queue(struct _ape_mysql_data *myhandle, char *query, unsigned int query_len, jsval callback); | |
static void apemysql_shift_queue(struct _ape_mysql_data *myhandle); | |
#endif | |
+ | |
+typedef enum { | |
+ SSH_STARTUP, | |
+ SSH_AUTH, | |
+ SSH_REQ_CHANNEL, | |
+ SSH_REQ_PTY, | |
+ SSH_REQ_SHELL, | |
+ SSH_CONNECTED, | |
+ SSH_ERR | |
+} ape_ssh_state; | |
+ | |
+struct _ape_ssh_ctx | |
+{ | |
+ JSContext *cx; | |
+ JSObject *jsssh; | |
+ | |
+ struct { | |
+ char *login; | |
+ char *password; | |
+ } cred; | |
+ | |
+ LIBSSH2_SESSION *session; | |
+ LIBSSH2_CHANNEL *channel; | |
+ | |
+ ape_ssh_state state; | |
+ void *data; | |
+ | |
+}; | |
//static JSBool sockserver_addproperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp); | |
static ace_plugin_infos infos_module = { | |
@@ -267,6 +296,13 @@ | |
}; | |
#endif | |
+static JSClass ssh_class = { | |
+ "SSH", JSCLASS_HAS_PRIVATE, | |
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, apemysql_finalize, | |
+ JSCLASS_NO_OPTIONAL_MEMBERS | |
+}; | |
+ | |
static JSClass cmdresponse_class = { | |
"cmdresponse", JSCLASS_HAS_PRIVATE, | |
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, | |
@@ -274,6 +310,40 @@ | |
JSCLASS_NO_OPTIONAL_MEMBERS | |
}; | |
+APE_JS_NATIVE(apessh_sm_send) | |
+//{ | |
+ struct _ape_ssh_ctx *sshctx = JS_GetPrivate(cx, obj); | |
+ JSString *string; | |
+ | |
+ if (sshctx == NULL) { | |
+ return JS_TRUE; | |
+ } | |
+ | |
+ if (!JS_ConvertArguments(cx, argc, argv, "S", &string)) { | |
+ return JS_TRUE; | |
+ } | |
+ | |
+ libssh2_channel_write(sshctx->channel, JS_GetStringBytes(string), JS_GetStringLength(string)); | |
+ | |
+ return JS_TRUE; | |
+} | |
+ | |
+APE_JS_NATIVE(apessh_sm_close) | |
+//{ | |
+ struct _ape_ssh_ctx *sshctx = JS_GetPrivate(cx, obj); | |
+ ape_socket *client; | |
+ | |
+ if (sshctx == NULL || sshctx->data == NULL) { | |
+ return JS_TRUE; | |
+ } | |
+ | |
+ client = (ape_socket *)sshctx->data; | |
+ | |
+ shutdown(client->fd, 2); | |
+ | |
+ return JS_TRUE; | |
+} | |
+ | |
APE_JS_NATIVE(apesocket_write) | |
//{ | |
@@ -1127,6 +1197,13 @@ | |
JS_FS_END | |
}; | |
+static JSFunctionSpec apessh_funcs[] = { | |
+ JS_FS("send", apessh_sm_send, 1, 0, 0), | |
+ JS_FS("close", apessh_sm_close, 0, 0, 0), | |
+ JS_FS_END | |
+}; | |
+ | |
+ | |
static JSObject *sm_ape_socket_to_jsobj(JSContext *cx, ape_socket *client) | |
{ | |
/*if (client->data != NULL) { | |
@@ -1258,6 +1335,168 @@ | |
} | |
} | |
+/* Async State machine pour libssh2 */ | |
+static void ape_ssh_io(ape_socket *client, int way, acetables *g_ape) | |
+{ | |
+ int ret = 0, err = 0; | |
+ struct _ape_ssh_ctx *sshctx = client->attach; | |
+ const char *login, *pass; | |
+ | |
+ for (;;) { | |
+ switch(sshctx->state) { | |
+ case SSH_STARTUP: | |
+ if ((ret = libssh2_session_startup(sshctx->session, client->fd)) == 0) { | |
+ sshctx->state = SSH_AUTH; | |
+ } else if (ret != LIBSSH2_ERROR_EAGAIN) { | |
+ err = 1; | |
+ sshctx->state = SSH_ERR; | |
+ } | |
+ break; | |
+ case SSH_AUTH: | |
+ /* hmm, bug in the libssh2 macro?, useless ptr : */ | |
+ login = sshctx->cred.login; | |
+ pass = sshctx->cred.password; | |
+ | |
+ if ((ret = libssh2_userauth_password(sshctx->session, login, pass)) == 0) { | |
+ sshctx->state = SSH_REQ_CHANNEL; | |
+ } else if (ret != LIBSSH2_ERROR_EAGAIN) { | |
+ err = 2; | |
+ sshctx->state = SSH_ERR; | |
+ } | |
+ break; | |
+ case SSH_REQ_CHANNEL: | |
+ if ((sshctx->channel = libssh2_channel_open_session(sshctx->session)) == NULL) { | |
+ ret = libssh2_session_last_errno(sshctx->session); | |
+ } else { | |
+ sshctx->state = SSH_REQ_PTY; | |
+ break; | |
+ } | |
+ if (sshctx->channel == NULL && ret != LIBSSH2_ERROR_EAGAIN) { | |
+ err = 3; | |
+ sshctx->state = SSH_ERR; | |
+ } | |
+ break; | |
+ case SSH_REQ_PTY: | |
+ if ((ret = libssh2_channel_request_pty(sshctx->channel, "vt100")) == 0) { | |
+ sshctx->state = SSH_REQ_SHELL; | |
+ | |
+ } else if (ret != LIBSSH2_ERROR_EAGAIN) { | |
+ err = 4; | |
+ sshctx->state = SSH_ERR; | |
+ } | |
+ break; | |
+ case SSH_REQ_SHELL: | |
+ if ((ret = libssh2_channel_shell(sshctx->channel)) == 0) { | |
+ jsval rval; | |
+ sshctx->state = SSH_CONNECTED; | |
+ | |
+ JS_CallFunctionName(sshctx->cx, sshctx->jsssh, "onShell", 0, NULL, &rval); | |
+ } else if (ret != LIBSSH2_ERROR_EAGAIN) { | |
+ err = 5; | |
+ sshctx->state = SSH_ERR; | |
+ } | |
+ break; | |
+ case SSH_CONNECTED: | |
+ { | |
+ char *buf = xmalloc(sizeof(char) * 2048); | |
+ int len = 0, r = 0; | |
+ | |
+ while ((r = libssh2_channel_read(sshctx->channel, buf + len, 2048)) > 0) { | |
+ len += r; | |
+ buf = realloc(buf, len + 2048); | |
+ | |
+ } | |
+ if (len > 0) { | |
+ jsval params[1], rval; | |
+ params[0] = STRING_TO_JSVAL(JS_NewStringCopyN(sshctx->cx, buf, len)); | |
+ | |
+ JS_CallFunctionName(sshctx->cx, sshctx->jsssh, "onRead", 1, params, &rval); | |
+ | |
+ } | |
+ free(buf); | |
+ if (r == -1) { | |
+ err = 6; | |
+ sshctx->state = SSH_ERR; | |
+ break; | |
+ } | |
+ | |
+ } | |
+ //printf("[APE SSH] Connected !\n"); | |
+ return; | |
+ break; | |
+ case SSH_ERR: | |
+ { | |
+ jsval params[1], rval; | |
+ params[0] = INT_TO_JSVAL(err); | |
+ | |
+ JS_CallFunctionName(sshctx->cx, sshctx->jsssh, "onError", 1, params, &rval); | |
+ | |
+ if (err > 1) { | |
+ libssh2_session_disconnect(sshctx->session, "Shutdown"); | |
+ } | |
+ if (err > 3) { | |
+ libssh2_channel_free(sshctx->channel); | |
+ } | |
+ | |
+ shutdown(client->fd, 2); | |
+ close_socket(client->fd, g_ape); | |
+ | |
+ libssh2_session_free(sshctx->session); | |
+ | |
+ free(sshctx->cred.login); | |
+ free(sshctx->cred.password); | |
+ | |
+ JS_SetPrivate(sshctx->cx, sshctx->jsssh, NULL); | |
+ JS_RemoveRoot(sshctx->cx, &sshctx->jsssh); | |
+ client->attach = NULL; | |
+ | |
+ free(sshctx); | |
+ | |
+ } | |
+ return; | |
+ | |
+ } | |
+ if (ret == LIBSSH2_ERROR_EAGAIN) { | |
+ break; | |
+ } | |
+ } | |
+} | |
+ | |
+static void ape_ssh_io_read(ape_socket *client, ape_buffer *buf, size_t offset, acetables *g_ape) | |
+{ | |
+ struct _ape_ssh_ctx *sshctx = client->attach; | |
+ | |
+ if (sshctx != NULL && libssh2_session_block_directions(sshctx->session) & LIBSSH2_SESSION_BLOCK_INBOUND) { | |
+ ape_ssh_io(client, LIBSSH2_SESSION_BLOCK_INBOUND, g_ape); | |
+ } | |
+ | |
+} | |
+ | |
+static void ape_ssh_io_write(ape_socket *client, acetables *g_ape) | |
+{ | |
+ struct _ape_ssh_ctx *sshctx = client->attach; | |
+ | |
+ if (sshctx != NULL && libssh2_session_block_directions(sshctx->session) & LIBSSH2_SESSION_BLOCK_OUTBOUND) { | |
+ ape_ssh_io(client, LIBSSH2_SESSION_BLOCK_OUTBOUND, g_ape); | |
+ } | |
+} | |
+ | |
+ | |
+static void sm_ssh_onconnect(ape_socket *client, acetables *g_ape) | |
+{ | |
+ struct _ape_ssh_ctx *sshctx = client->attach; | |
+ | |
+ sshctx->data = client; | |
+ | |
+ client->stream_type = STREAM_DELEGATE; | |
+ client->callbacks.on_read = ape_ssh_io_read; | |
+ client->callbacks.on_write = ape_ssh_io_write; | |
+ | |
+ ape_ssh_io(client, 0, g_ape); | |
+ | |
+ /* turn to delegate */ | |
+} | |
+ | |
static void sm_sock_onconnect(ape_socket *client, acetables *g_ape) | |
{ | |
jsval rval; | |
@@ -2503,6 +2742,73 @@ | |
return nqueue; | |
} | |
+/* | |
+struct _ape_ssh_ctx | |
+{ | |
+ JSContext *ctx; | |
+ JSObject *jsssh; | |
+ | |
+ struct { | |
+ const char *login; | |
+ const char *password; | |
+ } cred; | |
+ | |
+ LIBSSH2_SESSION *session; | |
+ | |
+ int state; | |
+ void *data; | |
+ | |
+}; | |
+*/ | |
+ | |
+ | |
+APE_JS_NATIVE(ape_sm_ssh_constructor) | |
+//{ | |
+ LIBSSH2_SESSION *session; | |
+ char *ip, *login, *pass; | |
+ | |
+ ape_socket *pattern; | |
+ struct _ape_ssh_ctx *sshctx; | |
+ | |
+ /* var ssh = new Ape.SSH('ape-project.org', 'root', 'lefu-'); */ | |
+ if (!JS_ConvertArguments(cx, argc, argv, "sss", &ip, &login, &pass)) { | |
+ return JS_TRUE; | |
+ } | |
+ | |
+ session = libssh2_session_init(); | |
+ | |
+ if (session == 0) { | |
+ return JS_TRUE; | |
+ } | |
+ | |
+ libssh2_session_set_blocking(session, 0); | |
+ | |
+ sshctx = xmalloc(sizeof(*sshctx)); | |
+ | |
+ sshctx->cred.login = xstrdup(login); | |
+ sshctx->cred.password = xstrdup(pass); | |
+ sshctx->session = session; | |
+ sshctx->cx = cx; | |
+ sshctx->jsssh = obj; | |
+ sshctx->state = SSH_STARTUP; | |
+ sshctx->data = NULL; | |
+ | |
+ JS_AddRoot(cx, &sshctx->jsssh); | |
+ | |
+ pattern = xmalloc(sizeof(*pattern)); | |
+ | |
+ pattern->callbacks.on_connect = sm_ssh_onconnect; | |
+ pattern->callbacks.on_disconnect = NULL; | |
+ | |
+ pattern->attach = sshctx; | |
+ | |
+ JS_SetPrivate(cx, obj, sshctx); | |
+ | |
+ ape_connect_name(ip, 22, pattern, g_ape); | |
+ | |
+ return JS_TRUE; | |
+} | |
+ | |
APE_JS_NATIVE(ape_sm_mysql_constructor) | |
//{ | |
char *host, *login, *pass, *db; | |
@@ -2678,6 +2984,7 @@ | |
#ifdef _USE_MYSQL | |
JSObject *jsmysql; | |
#endif | |
+ JSObject *jsssh; | |
obj = JS_DefineObject(asc->cx, asc->global, "Ape", &ape_class, NULL, 0); | |
b64 = JS_DefineObject(asc->cx, obj, "base64", &b64_class, NULL, 0); | |
@@ -2707,10 +3014,13 @@ | |
#ifdef _USE_MYSQL | |
jsmysql = JS_InitClass(asc->cx, obj, NULL, &mysql_class, ape_sm_mysql_constructor, 2, NULL, NULL, NULL, apemysql_funcs_static); | |
#endif | |
+ jsssh = JS_InitClass(asc->cx, obj, NULL, &ssh_class, ape_sm_ssh_constructor, 3, NULL, NULL, NULL, NULL); | |
JS_InitClass(asc->cx, obj, NULL, &raw_class, ape_sm_raw_constructor, 1, NULL, NULL, NULL, NULL); /* Not used */ | |
JS_DefineFunctions(asc->cx, sockclient, apesocket_client_funcs); | |
JS_DefineFunctions(asc->cx, sockclient, apesocket_funcs); | |
+ | |
+ JS_DefineFunctions(asc->cx, jsssh, apessh_funcs); | |
JS_DefineFunctions(asc->cx, sockserver, apesocket_client_funcs); | |
JS_DefineFunctions(asc->cx, sockserver, apesocketserver_funcs); | |
@@ -2886,7 +3196,7 @@ | |
glob_t globbuf; | |
- rt = JS_NewRuntime(8L * 1024L * 1024L); | |
+ rt = JS_NewRuntime(128L * 1024L * 1024L); | |
if (rt == NULL) { | |
printf("[ERR] Not enougth memory\n"); | |
@@ -2912,6 +3222,10 @@ | |
glob(rpath, 0, NULL, &globbuf); | |
+ if (libssh2_init(0) != 0) { | |
+ printf("[SSH] Error: Failed to initialize libssh2\n"); | |
+ } | |
+ | |
for (i = 0; i < globbuf.gl_pathc; i++) { | |
ape_sm_compiled *asc = xmalloc(sizeof(*asc)); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment