1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 12:41:29 +00:00

NSE libssh2 bindings: allow exec without pty

This commit is contained in:
dmiller
2024-11-11 21:07:01 +00:00
parent e2ccdb8074
commit 2d43280b16
3 changed files with 59 additions and 44 deletions

View File

@@ -14,6 +14,7 @@ extern "C" {
#include "nse_nsock.h" #include "nse_nsock.h"
#include "nse_utility.h" #include "nse_utility.h"
#include "nbase.h"
#include <fcntl.h> #include <fcntl.h>
#include <assert.h> #include <assert.h>
@@ -702,10 +703,10 @@ static int channel_read (lua_State *L, int status, lua_KContext ctx) {
int rc; int rc;
char buf[2048]; char buf[2048];
size_t buflen = 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); 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); 1, channel_read, ctx);
if (rc > 0) { if (rc > 0) {
@@ -734,14 +735,14 @@ static int channel_write (lua_State *L, int status, lua_KContext ctx) {
int rc; int rc;
const char *buf; const char *buf;
size_t buflen = 0; 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)) if (lua_isstring(L, 3))
buf = lua_tolstring(L, 3, &buflen); buf = lua_tolstring(L, 3, &buflen);
else else
return luaL_error(L, "Invalid buffer"); 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); 1, channel_write, ctx);
if (rc < 0) 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) { static int channel_exec (lua_State *L, int status, lua_KContext ctx) {
int rc; int rc;
// ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); // 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); 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); 1, channel_exec, ctx);
if (rc != 0) if (rc != 0)
return luaL_error(L, "Error executing command"); 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) { static int l_channel_eof(lua_State *L) {
int result; 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) if (result >= 0)
lua_pushboolean(L, result); lua_pushboolean(L, result);
else 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) { static int channel_send_eof(lua_State *L, int status, lua_KContext ctx) {
int rc; int rc;
// ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); // 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); 1, channel_send_eof, ctx);
if (rc != 0) if (rc != 0)
return luaL_error(L, "Error sending EOF"); 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); 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) { static int setup_channel(lua_State *L, int status, lua_KContext ctx) {
int rc; int rc;
// ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); channel_context *channel_ctx = (channel_context *) ctx;
LIBSSH2_CHANNEL **channel = (LIBSSH2_CHANNEL **) lua_touserdata(L, 2); ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1);
DO_OR_YIELD((rc = libssh2_channel_request_pty(*channel, "vanilla")), if (channel_ctx->channel == NULL) {
1, setup_channel, ctx); DO_OR_YIELD(((channel_ctx->channel = libssh2_channel_open_session(state->session)) == NULL ?
if (rc != 0) 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"); 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; 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) { static int l_open_channel (lua_State *L) {
ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); //ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1);
LIBSSH2_CHANNEL **channel = (LIBSSH2_CHANNEL **)lua_newuserdatauv(L, sizeof(LIBSSH2_CHANNEL *), 0); 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 ? channel_context *ctx = (channel_context *)safe_zalloc(sizeof(channel_context));
libssh2_session_last_errno(state->session) : LIBSSH2_ERROR_NONE), ctx->request_pty = !no_pty;
1, finish_open_channel, 0);
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) { static int channel_close (lua_State *L, int status, lua_KContext ctx) {
int rc; int rc;
// ssh_userdata *state = (ssh_userdata *)lua_touserdata(L, 1); // 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); 1, channel_close, ctx);
if (rc != 0) if (rc != 0)
return luaL_error(L, "Error closing channel");; return luaL_error(L, "Error closing channel");;

View File

@@ -57,12 +57,13 @@ end
-- Runs a shell command on the remote host. -- Runs a shell command on the remote host.
-- --
-- @param cmd A command to run. -- @param cmd A command to run.
-- @param no_pty If true, skip requesting a PTY.
-- @return The command output. -- @return The command output.
function SSHConnection:run_remote (cmd) function SSHConnection:run_remote (cmd, no_pty)
if not (self.session and self.authenticated) then if not (self.session and self.authenticated) then
return false return false
end 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_exec(self.session, channel, cmd)
libssh2.channel_send_eof(self.session, channel) libssh2.channel_send_eof(self.session, channel)
local buff = {} local buff = {}
@@ -71,6 +72,9 @@ function SSHConnection:run_remote (cmd)
data = libssh2.channel_read(self.session, channel) data = libssh2.channel_read(self.session, channel)
if data then if data then
table.insert(buff, data) table.insert(buff, data)
elseif no_pty then
-- PTY is responsible for sending EOF
break
end end
end end
return table.concat(buff) return table.concat(buff)

View File

@@ -67,11 +67,12 @@ function read_publickey(publickeyfile)
-- @return true/false, depending on whether user can authenticate with given key -- @return true/false, depending on whether user can authenticate with given key
function publickey_canauth(session, username, publickeydata) 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. -- terminal mode.
-- @param session Authenticated libssh2 session -- @param session Authenticated libssh2 session
-- @param no_pty If true, skip requesting a PTY.
-- @return libssh2 channel -- @return libssh2 channel
function open_channel(session) function open_channel(session, pty)
--- Reads data from stdin on libssh2 channel. --- Reads data from stdin on libssh2 channel.
-- @param session Authenticated libssh2 session -- @param session Authenticated libssh2 session