From 2d43280b162bf0e9cb95c4761f6f5b141b62a43a Mon Sep 17 00:00:00 2001 From: dmiller Date: Mon, 11 Nov 2024 21:07:01 +0000 Subject: [PATCH] NSE libssh2 bindings: allow exec without pty --- nse_libssh2.cc | 90 +++++++++++++++++++++----------------- nselib/libssh2-utility.lua | 8 +++- nselib/libssh2.luadoc | 5 ++- 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/nse_libssh2.cc b/nse_libssh2.cc index 0584b7f7e..4601bc020 100644 --- a/nse_libssh2.cc +++ b/nse_libssh2.cc @@ -14,6 +14,7 @@ extern "C" { #include "nse_nsock.h" #include "nse_utility.h" +#include "nbase.h" #include #include @@ -702,10 +703,10 @@ static int channel_read (lua_State *L, int status, lua_KContext ctx) { int rc; char buf[2048]; size_t buflen = 2048; - LIBSSH2_CHANNEL **channel = (LIBSSH2_CHANNEL **) lua_touserdata(L, 2); + LIBSSH2_CHANNEL *channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2); int stream_id = luaL_checkinteger(L, 3); - DO_OR_YIELD((rc = libssh2_channel_read_ex(*channel, stream_id, buf, buflen)), + DO_OR_YIELD((rc = libssh2_channel_read_ex(channel, stream_id, buf, buflen)), 1, channel_read, ctx); if (rc > 0) { @@ -734,14 +735,14 @@ static int channel_write (lua_State *L, int status, lua_KContext ctx) { int rc; const char *buf; size_t buflen = 0; - LIBSSH2_CHANNEL **channel = (LIBSSH2_CHANNEL **) lua_touserdata(L, 2); + LIBSSH2_CHANNEL *channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2); if (lua_isstring(L, 3)) buf = lua_tolstring(L, 3, &buflen); else return luaL_error(L, "Invalid buffer"); - DO_OR_YIELD((rc = libssh2_channel_write(*channel, buf, buflen)), + DO_OR_YIELD((rc = libssh2_channel_write(channel, buf, buflen)), 1, channel_write, ctx); if (rc < 0) @@ -758,10 +759,10 @@ static int l_channel_write (lua_State *L) { static int channel_exec (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); + LIBSSH2_CHANNEL *channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2); const char *cmd = luaL_checkstring(L, 3); - DO_OR_YIELD((rc = libssh2_channel_exec(*channel, cmd)), + DO_OR_YIELD((rc = libssh2_channel_exec(channel, cmd)), 1, channel_exec, ctx); if (rc != 0) return luaL_error(L, "Error executing command"); @@ -775,9 +776,9 @@ static int l_channel_exec (lua_State *L) { static int l_channel_eof(lua_State *L) { int result; - LIBSSH2_CHANNEL **channel = (LIBSSH2_CHANNEL **) lua_touserdata(L, 1); + LIBSSH2_CHANNEL *channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 1); - result = libssh2_channel_eof(*channel); + result = libssh2_channel_eof(channel); if (result >= 0) lua_pushboolean(L, result); else @@ -789,9 +790,9 @@ static int l_channel_eof(lua_State *L) { static int channel_send_eof(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); + LIBSSH2_CHANNEL *channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2); - DO_OR_YIELD((rc = libssh2_channel_send_eof(*channel)), + DO_OR_YIELD((rc = libssh2_channel_send_eof(channel)), 1, channel_send_eof, ctx); if (rc != 0) return luaL_error(L, "Error sending EOF"); @@ -803,53 +804,62 @@ 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; +}; + static int setup_channel(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); + channel_context *channel_ctx = (channel_context *) ctx; + ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); - DO_OR_YIELD((rc = libssh2_channel_request_pty(*channel, "vanilla")), - 1, setup_channel, ctx); - if (rc != 0) + 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); + 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); return 1; } -static int l_setup_channel (lua_State *L) { - return setup_channel(L, 0, 0); -} - -static int finish_open_channel (lua_State *L, int status, lua_KContext ctx) { - ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); - LIBSSH2_CHANNEL **channel = (LIBSSH2_CHANNEL **) lua_touserdata(L, 2); - - DO_OR_YIELD(((*channel = libssh2_channel_open_session(state->session)) == NULL ? - libssh2_session_last_errno(state->session) : LIBSSH2_ERROR_NONE), - 1, finish_open_channel, ctx); - if (*channel == NULL) - return luaL_error(L, "Opening channel"); - - return setup_channel(L, 0, 0); -} - static int l_open_channel (lua_State *L) { - ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); - LIBSSH2_CHANNEL **channel = (LIBSSH2_CHANNEL **)lua_newuserdatauv(L, sizeof(LIBSSH2_CHANNEL *), 0); + //ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); + bool no_pty = false; + if (lua_gettop(L) > 1) { + no_pty = lua_toboolean(L, 2); + } + lua_settop(L, 1); - DO_OR_YIELD(((*channel = libssh2_channel_open_session(state->session)) == NULL ? - libssh2_session_last_errno(state->session) : LIBSSH2_ERROR_NONE), - 1, finish_open_channel, 0); + channel_context *ctx = (channel_context *)safe_zalloc(sizeof(channel_context)); + ctx->request_pty = !no_pty; - return l_setup_channel(L); + return setup_channel(L, 0, (lua_KContext) ctx); } static int channel_close (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); + LIBSSH2_CHANNEL *channel = (LIBSSH2_CHANNEL *) lua_touserdata(L, 2); - DO_OR_YIELD((rc = libssh2_channel_close(*channel)), + DO_OR_YIELD((rc = libssh2_channel_close(channel)), 1, channel_close, ctx); if (rc != 0) return luaL_error(L, "Error closing channel");; diff --git a/nselib/libssh2-utility.lua b/nselib/libssh2-utility.lua index 5795de140..7c830892e 100644 --- a/nselib/libssh2-utility.lua +++ b/nselib/libssh2-utility.lua @@ -57,12 +57,13 @@ end -- Runs a shell command on the remote host. -- -- @param cmd A command to run. +-- @param no_pty If true, skip requesting a PTY. -- @return The command output. -function SSHConnection:run_remote (cmd) +function SSHConnection:run_remote (cmd, no_pty) if not (self.session and self.authenticated) then return false end - local channel = libssh2.open_channel(self.session) + local channel = libssh2.open_channel(self.session, no_pty) libssh2.channel_exec(self.session, channel, cmd) libssh2.channel_send_eof(self.session, channel) local buff = {} @@ -71,6 +72,9 @@ function SSHConnection:run_remote (cmd) data = libssh2.channel_read(self.session, channel) if data then table.insert(buff, data) + elseif no_pty then + -- PTY is responsible for sending EOF + break end end return table.concat(buff) diff --git a/nselib/libssh2.luadoc b/nselib/libssh2.luadoc index 1801ead42..20faddbb5 100644 --- a/nselib/libssh2.luadoc +++ b/nselib/libssh2.luadoc @@ -67,11 +67,12 @@ function read_publickey(publickeyfile) -- @return true/false, depending on whether user can authenticate with given key function publickey_canauth(session, username, publickeydata) ---- Opens channel on authenticated ssh2 session and sets it to pseudo +--- Opens channel on authenticated ssh2 session and optionally sets it to pseudo -- terminal mode. -- @param session Authenticated libssh2 session +-- @param no_pty If true, skip requesting a PTY. -- @return libssh2 channel -function open_channel(session) +function open_channel(session, pty) --- Reads data from stdin on libssh2 channel. -- @param session Authenticated libssh2 session