1
0
mirror of https://github.com/nmap/nmap.git synced 2026-01-15 02:49:02 +00:00

Adapted current nse_main to use the new action closure change discussed here:

(http://seclists.org/nmap-dev/2008/q2/0549.html).
This commit is contained in:
batrick
2008-07-07 17:34:37 +00:00
parent f424fd21b2
commit f9e6d7d01a
2 changed files with 135 additions and 176 deletions

View File

@@ -66,7 +66,7 @@ static int loadfile (lua_State *L)
static const char *required_fields[] = {ACTION, DESCRIPTION};
lua_settop(L, 1); // removes other arguments
lua_createtable(L, 0, 11); // Environment for script
lua_createtable(L, 0, 11); // Environment for script (index 2)
lua_pushvalue(L, 1); // tell the script about its filename
lua_setfield(L, -2, FILENAME);
@@ -81,9 +81,10 @@ static int loadfile (lua_State *L)
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
if (luaL_loadfile(L, filename) != 0) // load the file
if (luaL_loadfile(L, filename) != 0) // load the file (index 3)
luaL_error(L, "'%s' could not be loaded!", filename);
lua_pushvalue(L, -2); // push environment table
lua_pushvalue(L, -1);
lua_pushvalue(L, 2); // push environment table
lua_setfenv(L, -2); // set it
lua_call(L, 0, 0); // Call the function (loads globals)
@@ -91,7 +92,7 @@ static int loadfile (lua_State *L)
for (i = 0; i < ARRAY_LEN(required_fields); i++)
{
lua_pushstring(L, required_fields[i]);
lua_gettable(L, -2);
lua_gettable(L, 2);
if (lua_isnil(L, -1))
luaL_error(L, "No '%s' field in script '%s'.", required_fields[i],
filename);
@@ -101,31 +102,39 @@ static int loadfile (lua_State *L)
/* store the initialized test in either
* the hosttests or the porttests
*/
lua_getfield(L, -1, PORTRULE); // script's portrule
lua_getfield(L, -2, HOSTRULE); // script's hostrule
lua_getfield(L, 2, PORTRULE); // script's portrule
lua_getfield(L, 2, HOSTRULE); // script's hostrule
/* if we are looking at a portrule then store it in the porttestsets table,
* else if it is a hostrule, then it goes into the hosttestsets table,
* otherwise we fail if there.
*/
if (!lua_isnil(L, -2))
if (!lua_isnil(L, -2)) // script has a port rule
{
lua_pop(L, 2); // pop port/host rules
lua_getfield(L, LUA_REGISTRYINDEX, PORTTESTS); // Get global PORTTESTS table
lua_pushvalue(L, -2); // script's environment
lua_rawseti(L, -2, lua_objlen(L, -2) + 1); // add it
lua_pop(L, 1); // pop the porttests table
lua_getfield(L, LUA_REGISTRYINDEX, PORTTESTS); // Get PORTTESTS table
lua_pushvalue(L, -3); // script's portrule
lua_pushvalue(L, 3); // script's file closure
lua_getfenv(L, -1);
lua_pushliteral(L, FILENAME);
lua_pushvalue(L, 1); // filename
lua_settable(L, -3);
lua_pop(L, 1); // file closure environment
lua_settable(L, -3);
}
else if (!lua_isnil(L, -1))
else if (!lua_isnil(L, -1)) // script has a hostrule
{
lua_pop(L, 2);
lua_getfield(L, LUA_REGISTRYINDEX, HOSTTESTS);
lua_pushvalue(L, -2);
lua_rawseti(L, -2, lua_objlen(L, -2) + 1);
lua_pop(L, 1); // pop the hosttests table
lua_pushvalue(L, -2); // script's hostrule
lua_pushvalue(L, 3); // script's file closure
lua_getfenv(L, -1);
lua_pushliteral(L, FILENAME);
lua_pushvalue(L, 1); // filename
lua_settable(L, -3);
lua_pop(L, 1); // file closure environment
lua_settable(L, -3);
}
else
luaL_error(L, "No rules in script '%s'.", filename);
return luaL_error(L, "No rules in script '%s'.", filename);
return 0;
}

View File

@@ -19,7 +19,6 @@ extern NmapOps o;
struct run_record {
short type; // 0 - hostrule; 1 - portrule
unsigned int index; // index in the corresponding table
Port* port;
Target* host;
};
@@ -48,7 +47,7 @@ public:
// prior execution
int process_preparerunlevels(std::list<struct thread_record> torun_threads);
int process_preparehost(lua_State* L, Target* target, std::list<struct thread_record>& torun_threads);
int process_preparethread(lua_State* L, struct run_record rr, struct thread_record* tr);
int process_preparethread(lua_State* L, struct run_record *rr, struct thread_record* tr);
// helper functions
int process_getScriptId(lua_State* L, struct script_scan_result* ssr);
@@ -56,7 +55,7 @@ int process_pickScriptsForPort(
lua_State* L,
Target* target,
Port* port,
std::vector<run_record>& torun);
std::list<thread_record>& torun_threads);
// execution
int process_mainloop(lua_State* L);
@@ -110,7 +109,6 @@ static int escape_char (lua_State *L)
return 1;
}
int script_updatedb (void)
{
int status;
@@ -233,7 +231,7 @@ int script_scan(std::vector<Target*> &targets) {
)
L = luaL_newstate();
if(L == NULL) {
if (L == NULL) {
error("%s: Failed luaL_newstate()", SCRIPT_ENGINE);
return SCRIPT_ENGINE_ERROR;
}
@@ -553,109 +551,66 @@ int process_getScriptId(lua_State* L, struct script_scan_result *ssr) {
int process_preparehost(lua_State* L, Target* target, std::list<struct thread_record>& torun_threads) {
PortList* plist = &(target->ports);
Port* current = NULL;
size_t rules_count;
unsigned int i;
std::vector<run_record> torun;
std::vector<run_record>::iterator iter;
struct run_record rr;
/* find the matching hostrules
* */
lua_getfield(L, LUA_REGISTRYINDEX, HOSTTESTS);
rules_count = lua_objlen(L, -1);
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
// Hostrule function & file closure on stack
lua_pushvalue(L, -2); // hostrule function (key)
lua_newtable(L);
set_hostinfo(L, target); // hostrule argument
SCRIPT_ENGINE_LUA_TRY(lua_pcall(L, 1, 1, 0));
for(i = 1; i <= rules_count; i++) {
lua_rawgeti(L, -1, i);
if (lua_isboolean(L, -1) && lua_toboolean(L, -1))
{
struct thread_record tr;
tr.rr = (struct run_record *) safe_malloc(sizeof(struct run_record));
tr.rr->type = 0;
tr.rr->port = NULL;
tr.rr->host = target;
lua_getfield(L, -1, HOSTRULE);
SCRIPT_ENGINE_TRY(process_preparethread(L, tr.rr, &tr));
lua_newtable(L);
set_hostinfo(L, target);
torun_threads.push_back(tr);
SCRIPT_ENGINE_LUA_TRY(lua_pcall(L, 1, 1, 0));
if(lua_isboolean (L, -1) && lua_toboolean(L, -1)) {
rr.type = 0;
rr.index = i;
rr.port = NULL;
rr.host = target;
torun.push_back(rr);
SCRIPT_ENGINE_DEBUGGING(
lua_getfield(L, -2, FILENAME);
log_write(LOG_STDOUT, "%s: Will run %s against %s\n",
SCRIPT_ENGINE,
lua_tostring(L, -1),
target->targetipstr());
lua_pop(L, 1);
)
}
lua_pop(L, 2);
}
SCRIPT_ENGINE_DEBUGGING(
lua_getfenv(L, -2); // file closure environment
lua_getfield(L, -1, FILENAME);
log_write(LOG_STDOUT, "%s: Will run %s against %s\n",
SCRIPT_ENGINE,
lua_tostring(L, -1),
target->targetipstr());
lua_pop(L, 2);
)
}
lua_pop(L, 2); // boolean and file closure
}
/* find the matching port rules
* */
lua_getfield(L, LUA_REGISTRYINDEX, PORTTESTS);
/* we only publish hostinfo once per portrule */
lua_newtable(L);
set_hostinfo(L, target);
/* because of the port iteration API we need to awkwardly iterate
* over the kinds of ports we're interested in explictely.
* */
current = NULL;
while((current = plist->nextPort(current, TCPANDUDP, PORT_OPEN)) != NULL) {
SCRIPT_ENGINE_TRY(process_pickScriptsForPort(L, target, current, torun));
SCRIPT_ENGINE_TRY(process_pickScriptsForPort(L, target, current, torun_threads));
}
while((current = plist->nextPort(current, TCPANDUDP, PORT_OPENFILTERED)) != NULL) {
SCRIPT_ENGINE_TRY(process_pickScriptsForPort(L, target, current, torun));
SCRIPT_ENGINE_TRY(process_pickScriptsForPort(L, target, current, torun_threads));
}
while((current = plist->nextPort(current, TCPANDUDP, PORT_UNFILTERED)) != NULL) {
SCRIPT_ENGINE_TRY(process_pickScriptsForPort(L, target, current, torun));
SCRIPT_ENGINE_TRY(process_pickScriptsForPort(L, target, current, torun_threads));
}
// pop the hostinfo, we don't need it anymore
lua_pop(L, 1);
lua_pop(L, 2); // Hostrules, Portrules
/* ok, let's setup threads for the scripts which said they'd like
* to run
* Remember:
* we have the hosttestset and the porttestset on the stack!
* */
struct thread_record tr;
for(iter = torun.begin(); iter != torun.end(); iter++) {
/* If it is a host rule, execute the action
* and append the output to the host output i
* If it is a port rule, append the output to
* the port and increase the number of scripts
* which produced output. We need that number
* to generate beautiful output later.
* */
switch((*iter).type) {
case 0: // this script runs against a host
lua_pushvalue(L, -2);
SCRIPT_ENGINE_TRY(process_preparethread(L, (*iter), &tr));
lua_pop(L, 1);
break;
case 1: // this script runs against a port
lua_pushvalue(L, -1);
SCRIPT_ENGINE_TRY(process_preparethread(L, (*iter), &tr));
lua_pop(L, 1);
break;
default:
fatal("%s: In: %s:%i This should never happen.",
SCRIPT_ENGINE, __FILE__, __LINE__);
}
torun_threads.push_back(tr);
}
lua_pop(L, 2);
torun.clear();
return SCRIPT_ENGINE_SUCCESS;
}
@@ -687,109 +642,104 @@ int process_preparerunlevels(std::list<struct thread_record> torun_threads) {
/* Because we can't iterate over all ports of interest in one go
* we need to do port matching in a separate function (unlike host
* rule matching)
* Note that we assume that at -2 on the stack we can find the portrules
* and at -1 the hostinfo table
* Note that we assume that at -1 on the stack we can find the portrules
* */
int process_pickScriptsForPort(
lua_State* L,
Target* target,
Port* port,
std::vector<run_record>& torun) {
size_t rules_count = lua_objlen(L, -2);
struct run_record rr;
unsigned int i;
int process_pickScriptsForPort(lua_State* L, Target* target, Port* port, std::list<thread_record>& torun_threads) {
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
// Portrule function & file closure on stack
lua_pushvalue(L, -2); // portrule function (key)
lua_newtable(L);
set_hostinfo(L, target); // portrule argument 1
lua_newtable(L);
set_portinfo(L, port); // portrule argument 2
SCRIPT_ENGINE_LUA_TRY(lua_pcall(L, 2, 1, 0));
for(i = 1; i <= rules_count; i++) {
lua_rawgeti(L, -2, i);
if (lua_isboolean(L, -1) && lua_toboolean(L, -1))
{
struct thread_record tr;
tr.rr = (struct run_record *) safe_malloc(sizeof(struct run_record));
tr.rr->type = 1;
tr.rr->port = port;
tr.rr->host = target;
lua_getfield(L, -1, PORTRULE);
lua_pushvalue(L, -3);
lua_newtable(L);
set_portinfo(L, port);
SCRIPT_ENGINE_LUA_TRY(lua_pcall(L, 2, 1, 0));
if(lua_isboolean (L, -1) && lua_toboolean(L, -1)) {
rr.type = 1;
rr.index = i;
rr.port = port;
rr.host = target;
torun.push_back(rr);
SCRIPT_ENGINE_DEBUGGING(
lua_getfield(L, -2, FILENAME);
log_write(LOG_STDOUT, "%s: Will run %s against %s:%d\n",
SCRIPT_ENGINE,
lua_tostring(L, -1),
target->targetipstr(),
port->portno);
lua_pop(L, 1);
)
} else if(!lua_isboolean (L, -1)) {
lua_getfield(L, -2, FILENAME);
error("%s: Rule in %s returned %s but boolean was expected.",
SCRIPT_ENGINE,
lua_tostring(L, -1),
lua_typename(L, lua_type(L, -2)));
return SCRIPT_ENGINE_LUA_ERROR;
}
lua_pop(L, 2);
}
SCRIPT_ENGINE_TRY(process_preparethread(L, tr.rr, &tr));
torun_threads.push_back(tr);
SCRIPT_ENGINE_DEBUGGING(
lua_getfenv(L, -2); // file closure environment
lua_getfield(L, -1, FILENAME);
log_write(LOG_STDOUT, "%s: Will run %s against %s\n",
SCRIPT_ENGINE,
lua_tostring(L, -1),
target->targetipstr());
lua_pop(L, 2);
)
}
lua_pop(L, 2); // boolean and file closure
}
return SCRIPT_ENGINE_SUCCESS;
}
/* Create a new lua thread and prepare it for execution
* we store target info in the thread so that the mainloop
* knows where to put the script result
* knows where to put the script result. File closure is expected
* at stack index -2.
* */
int process_preparethread(lua_State* L, struct run_record rr, struct thread_record* tr){
int process_preparethread(lua_State* L, struct run_record *rr, struct thread_record *tr){
lua_State *thread = lua_newthread(L);
tr->registry_idx = luaL_ref(L, LUA_REGISTRYINDEX); // store thread
tr->thread = thread;
lua_rawgeti(L, -2, rr.index); // get the script closure
lua_pushvalue(L, -2); // File closure
lua_getfenv(L, -1); // get script file environment
lua_getfield(L, -1, FILENAME); // get its filename
lua_createtable(L, 0, 11); // new environment
lua_pushvalue(L, -2); // script filename
lua_setfield(L, -2, FILENAME);
lua_pushnumber(L, 1.0); // set a default RUNLEVEL
lua_setfield(L, -2, RUNLEVEL);
lua_createtable(L, 0, 1); // metatable for env
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setfield(L, -2, "__index"); // global access
lua_setmetatable(L, -2);
// move the script closure into the thread
lua_xmove(L, thread, 1);
lua_pushvalue(L, -4); // script file closure
lua_pushvalue(L, -2); // script env
lua_setfenv(L, -2);
SCRIPT_ENGINE_LUA_TRY(
lua_pcall(L, 0, 0, 0) // file closure loads globals (action, id, etc.)
);
// store the target of this thread in the thread
struct run_record *rr_thread = (struct run_record*) safe_malloc(sizeof(struct run_record));
rr_thread->type = rr.type;
rr_thread->index = rr.index;
rr_thread->host = rr.host;
rr_thread->port = rr.port;
lua_getfield(L, -1, RUNLEVEL);
tr->runlevel = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(thread, -1, RUNLEVEL);
tr->runlevel = lua_tonumber(thread, -1);
lua_pop(thread, 1);
// prepare the thread for a resume by
// pushing the action method onto the stack
lua_getfield(thread, -1, ACTION);
// move the script action closure into the thread
lua_getfield(L, -1, ACTION); // action closure
lua_xmove(L, thread, 2);
lua_pop(L, 1); // filename
lua_setfenv(L, -2); // reset old env
lua_pop(L, 1); // file closure
// make the info table
lua_newtable(thread);
set_hostinfo(thread, rr.host);
tr->thread = thread;
tr->rr = rr_thread;
tr->resume_arguments = 1;
// we store the thread in the registry to prevent
// garbage collection +
tr->registry_idx = luaL_ref(L, LUA_REGISTRYINDEX);
set_hostinfo(thread, rr->host);
/* if this is a host rule we don't have
* a port state
* */
if(rr.port != NULL) {
if(rr->port != NULL) {
lua_newtable(thread);
set_portinfo(thread, rr.port);
set_portinfo(thread, rr->port);
tr->resume_arguments = 2;
}
else
tr->resume_arguments = 1;
return SCRIPT_ENGINE_SUCCESS;
}