diff --git a/nse_libssh2.cc b/nse_libssh2.cc
index 1e5a72012..4429a21e4 100644
--- a/nse_libssh2.cc
+++ b/nse_libssh2.cc
@@ -758,22 +758,46 @@ static int l_channel_write (lua_State *L) {
return channel_write(L, 0, 0);
}
-static int channel_exec (lua_State *L, int status, lua_KContext ctx) {
+struct request_context {
+ LIBSSH2_CHANNEL *channel;
+ const char *request;
+ size_t request_len;
+ const char *message;
+ size_t message_len;
+};
+
+static int channel_request (lua_State *L, int status, lua_KContext ctx) {
int rc;
- // ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1);
- LIBSSH2_CHANNEL *channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2);
- const char *cmd = luaL_checkstring(L, 3);
+ request_context *req_ctx = (request_context *)ctx;
+
+ DO_OR_YIELD((rc = libssh2_channel_process_startup(req_ctx->channel,
+ req_ctx->request, req_ctx->request_len,
+ req_ctx->message, req_ctx->message_len)),
+ 1, channel_request, ctx);
+
+ free(req_ctx);
- DO_OR_YIELD((rc = libssh2_channel_exec(channel, cmd)),
- 1, channel_exec, ctx);
if (rc != 0)
- return luaL_error(L, "Error executing command");
+ return luaL_error(L, "Error sending %s request", req_ctx->request);
- return 0;
+ return 0;
+}
+
+static int l_channel_request (lua_State *L) {
+ request_context *ctx = (request_context *)safe_zalloc(sizeof(request_context));
+ ctx->channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2);
+ ctx->request = luaL_checklstring(L, 3, &ctx->request_len);
+ ctx->message = lua_tolstring(L, 3, &ctx->message_len);
+ return channel_request(L, 0, (lua_KContext)ctx);
}
static int l_channel_exec (lua_State *L) {
- return channel_exec(L, 0, 0);
+ request_context *ctx = (request_context *)safe_zalloc(sizeof(request_context));
+ ctx->channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2);
+ ctx->request = "exec";
+ ctx->request_len = sizeof("exec") - 1;
+ ctx->message = luaL_checklstring(L, 3, &ctx->message_len);
+ return channel_request(L, 0, (lua_KContext)ctx);
}
static int l_channel_eof(lua_State *L) {
@@ -806,42 +830,53 @@ static int l_channel_send_eof(lua_State *L) {
return channel_send_eof(L, 0, 0);
}
-struct channel_context {
- bool request_pty;
- LIBSSH2_CHANNEL *channel;
+struct pty_context {
+ LIBSSH2_CHANNEL *channel;
+ const char *term;
+ size_t term_len;
+ const char *modes;
+ size_t modes_len;
+ int width;
+ int height;
+ int width_px;
+ int height_px;
};
static int setup_channel(lua_State *L, int status, lua_KContext ctx) {
- int rc;
- channel_context *channel_ctx = (channel_context *) ctx;
+ assert(ctx == 0);
ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1);
+ LIBSSH2_CHANNEL *channel = NULL;
- if (channel_ctx->channel == NULL) {
- DO_OR_YIELD(((channel_ctx->channel = libssh2_channel_open_session(state->session)) == NULL ?
- libssh2_session_last_errno(state->session) : LIBSSH2_ERROR_NONE),
- 1, setup_channel, ctx);
- if (channel_ctx->channel == NULL) {
- free(channel_ctx);
+ DO_OR_YIELD(((channel = libssh2_channel_open_session(state->session)) == NULL ?
+ libssh2_session_last_errno(state->session) : LIBSSH2_ERROR_NONE),
+ 1, setup_channel, ctx);
+ if (channel == NULL) {
return luaL_error(L, "Opening channel");
- }
}
-
- if (channel_ctx->request_pty) {
- DO_OR_YIELD((rc = libssh2_channel_request_pty(channel_ctx->channel, "vanilla")),
- 1, setup_channel, ctx);
- if (rc != 0) {
- free(channel_ctx);
- return luaL_error(L, "Requesting pty");
- }
- channel_ctx->request_pty = false; // make sure we don't enter this block again
- }
-
- lua_pushlightuserdata(L, channel_ctx->channel);
- free(channel_ctx);
-
+ lua_pushlightuserdata(L, channel);
return 1;
}
+static int setup_pty(lua_State *L, int status, lua_KContext ctx) {
+ int rc;
+ pty_context *pty_ctx = (pty_context *)ctx;
+ DO_OR_YIELD((rc = libssh2_channel_request_pty_ex(pty_ctx->channel,
+ pty_ctx->term, pty_ctx->term_len,
+ pty_ctx->modes, pty_ctx->modes_len,
+ pty_ctx->width, pty_ctx->height,
+ pty_ctx->width_px, pty_ctx->height_px
+ )),
+ 1, setup_pty, ctx);
+
+ free(pty_ctx);
+
+ if (rc != 0) {
+ return luaL_error(L, "Requesting pty");
+ }
+
+ return 0;
+}
+
static int l_open_channel (lua_State *L) {
//ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1);
bool no_pty = false;
@@ -850,10 +885,31 @@ static int l_open_channel (lua_State *L) {
}
lua_settop(L, 1);
- channel_context *ctx = (channel_context *)safe_zalloc(sizeof(channel_context));
- ctx->request_pty = !no_pty;
+ setup_channel(L, 0, 0);
+ if (!no_pty) {
+ pty_context *ctx = (pty_context *)safe_zalloc(sizeof(pty_context));
+ ctx->channel = (LIBSSH2_CHANNEL *)lua_touserdata(L, -1);
+ ctx->term = "vanilla";
+ ctx->term_len = sizeof("vanilla") - 1;
+ ctx->width = LIBSSH2_TERM_WIDTH;
+ ctx->height = LIBSSH2_TERM_HEIGHT;
+ ctx->width_px = LIBSSH2_TERM_WIDTH_PX;
+ ctx->height_px = LIBSSH2_TERM_HEIGHT_PX;
+ setup_pty(L, 0, (lua_KContext)ctx);
+ }
+ return 0;
+}
- return setup_channel(L, 0, (lua_KContext) ctx);
+static int l_channel_request_pty_ex (lua_State *L) {
+ pty_context *ctx = (pty_context *)safe_zalloc(sizeof(pty_context));
+ ctx->channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2);
+ ctx->term = luaL_checklstring(L, 3, &ctx->term_len);
+ ctx->modes = lua_tolstring(L, 4, &ctx->modes_len);
+ ctx->width = luaL_checkinteger(L, 5);
+ ctx->height = luaL_checkinteger(L, 6);
+ ctx->width_px = luaL_checkinteger(L, 7);
+ ctx->height_px = luaL_checkinteger(L, 8);
+ return setup_pty(L, 0, (lua_KContext)ctx);
}
static int channel_close (lua_State *L, int status, lua_KContext ctx) {
@@ -886,6 +942,8 @@ static const struct luaL_Reg libssh2[] = {
{ "userauth_password", l_userauth_password },
{ "session_close", l_session_close },
{ "open_channel", l_open_channel},
+ { "channel_request_pty_ex", l_channel_request_pty_ex},
+ { "channel_request", l_channel_request},
{ "channel_read", l_channel_read},
{ "channel_read_stderr", l_channel_read_stderr},
{ "channel_write", l_channel_write},
diff --git a/nselib/libssh2.luadoc b/nselib/libssh2.luadoc
index 13f6bce7e..8630e2e16 100644
--- a/nselib/libssh2.luadoc
+++ b/nselib/libssh2.luadoc
@@ -93,6 +93,31 @@ function channel_read_stderr(session, channel)
-- @return Number of bytes written to channel
function channel_write(session, channel, buffer)
+--- Sends a request on libssh2 channel.
+--
+-- For example, request a shell with
+-- channel_request(s, c, "shell"). The equivalent of
+-- channel_request(s, c, "exec", cmd)
+-- is channel_exec(s, c, cmd).
+-- @param session Authenticated libssh2 session
+-- @param channel Open libssh2 channel
+-- @param request String identifier for the request, e.g. "shell", "exec", "subsystem"
+-- @param message Optional string payload for the request.
+function channel_request(session, channel, request, message)
+
+--- Request a PTY on a channel
+--
+-- @param session Authenticated libssh2 session
+-- @param channel Open libssh2 channel
+-- @param term string Terminal emulation
+-- @param modes optional string Terminal mode modifiers
+-- @param width integer Width of pty in characters
+-- @param height integer Height of pty in characters
+-- @param width_ex integer Width of pty in pixels
+-- @param height_px integer Height of pty in pixels
+function channel_request_pty_ex(session, channel, term, modes,
+ width, height, width_px, height_px)
+
--- Executes command on libssh2 channel
-- @param session Authenticated libssh2 session
-- @param channel Open libssh2 channel