diff --git a/Target.cc b/Target.cc index a4cc6e9..e23b5f2 100644 --- a/Target.cc +++ b/Target.cc @@ -162,6 +162,12 @@ void Target::Recycle() { Target::~Target() { FreeInternal(); +#ifndef NOLUA + while (!scriptResults.empty()) { + delete scriptResults.front(); + scriptResults.pop_front(); + } +#endif } void Target::FreeInternal() { diff --git a/docs/nmap.dtd b/docs/nmap.dtd index 49924b0..a20e30c 100644 --- a/docs/nmap.dtd +++ b/docs/nmap.dtd @@ -229,10 +229,19 @@ - + + + + + + diff --git a/nmap.cc b/nmap.cc index eca2aa7..277228d 100644 --- a/nmap.cc +++ b/nmap.cc @@ -1735,7 +1735,10 @@ int nmap_main(int argc, char *argv[]) { script_scan_results = get_script_scan_results_obj(); script_scan(Targets, SCRIPT_PRE_SCAN); printscriptresults(script_scan_results, SCRIPT_PRE_SCAN); - script_scan_results->clear(); + while (!script_scan_results->empty()) { + delete script_scan_results->front(); + script_scan_results->pop_front(); + } } #endif @@ -2032,7 +2035,10 @@ int nmap_main(int argc, char *argv[]) { if (o.script) { script_scan(Targets, SCRIPT_POST_SCAN); printscriptresults(script_scan_results, SCRIPT_POST_SCAN); - script_scan_results->clear(); + while (!script_scan_results->empty()) { + delete script_scan_results->front(); + script_scan_results->pop_front(); + } delete new_targets; new_targets = NULL; } diff --git a/nse_main.cc b/nse_main.cc index 3c64b4e..0f5106d 100644 --- a/nse_main.cc +++ b/nse_main.cc @@ -110,22 +110,175 @@ static int ports (lua_State *L) return 3; } +/* Escape any character outside the range 32-126 except for tab, + carriage return, and line feed. This makes the string safe for + screen display as well as XML (see section 2.2 of the XML spec). + safe[] generated with $(perl -e 'print chr for 32..126') + */ +std::string script_result_escape (const char *in) +{ + std::string out=in; + size_t found; + char safe[] = "\t\r\n !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + char replace[4] = "\0"; + found = out.find_first_not_of(safe); + while (found != std::string::npos) + { + snprintf(replace, 4, "x%02X", out[found]); + out.insert(found+1, replace, 3); + out[found] = '\\'; + found = out.find_first_not_of(safe, found+4); + } + return out; +} + +static ScriptOutputNode *script_result_convert (lua_State *L, int pos) +{ + ScriptOutputNode *so = NULL; + if (pos < 0) + { //make pos positive + pos += lua_gettop(L) + 1; + } + if (lua_isstring(L, pos)) + { //simple string case + so = new ScriptOutputNode; + //so->set_display(FLOW); + so->set_output( script_result_escape(luaL_checkstring(L, pos)) ); + } + else if (lua_istable(L, pos)) + { /* make a node of a table. Possibilities: + * {"line","line",["name"]="title"} -- ScriptOutputContainer + * {[0]="Error message"} -- ScriptOutputError + * { ["key"]="value" } -- ScriptOutputKeyValue + */ + int n = lua_objlen(L, pos); + if (n > 0) + { //Container + so = new ScriptOutputContainer; + so->set_display( BLOCK ); + lua_getfield(L, pos, "name"); + if (lua_isstring(L, -1)) + { + so->set_output( script_result_escape(luaL_checkstring(L, -1)) ); + } + lua_pop(L, 1); + if (o.debugging) + { + lua_getfield(L, pos, "warning"); + if (lua_isstring(L, -1)) + { + ((ScriptOutputContainer *)so)->set_warning( + script_result_escape(luaL_checkstring(L, -1)) ); + } + lua_pop(L, 1); + } + for (int i=1; i<=n; ++i) + { + lua_rawgeti(L, pos, i); + ScriptOutputNode *sn = script_result_convert(L, -1); + if (sn) { //test for empty table/nil + ((ScriptOutputContainer *)so)->add_contents(sn); + } + lua_pop(L, 1); + } + } + else + { + lua_rawgeti(L, pos, 0); + if (lua_isstring(L, -1)) + { //Error + so = new ScriptOutputError; + //so->set_display(FLOW); + so->set_output( script_result_escape(luaL_checkstring(L, -1)) ); + } + else //KeyValue + { + lua_pushnil(L); + if (lua_next(L, pos)) + { + so = new ScriptOutputKeyValue; + if (lua_isstring(L, -2)) + { + ((ScriptOutputKeyValue *)so)->set_key( + script_result_escape(luaL_checkstring(L, -2)) ); + } + else + { + ((ScriptOutputKeyValue *)so)->set_key( + lua_typename(L, lua_type(L, -2)) ); + } + if (lua_isstring(L, -1)) + { + so->set_output( script_result_escape(luaL_checkstring(L, -1)) ); + } + else + { + lua_pushstring(L, "Nested dictionary-tables not supported"); + lua_error(L); + } + lua_pop(L, 2); + } + //else empty table, no output + lua_pop(L, 1); + } + } + } + else if (lua_isboolean(L,pos)) + { + so = new ScriptOutputNode; + //so->set_display(FLOW); + so->set_output( lua_toboolean(L, pos) ? "true" : "false" ); + } + else + { + lua_pushstring(L, "Scripts must return table, string, number, or boolean"); + lua_error(L); + } + return so; +} + +ScriptResult *script_to_result (lua_State *L, int pos) +{ + ScriptOutputNode *so = NULL; + ScriptResult *sr = NULL; + if (lua_istable(L, pos+1) && lua_objlen(L, pos+1) > 0) + { //passed a Container-style table + so = script_result_convert(L, pos+1); + if (so) + { + sr = new ScriptResult; + sr->set_id(script_result_escape(luaL_checkstring(L, pos))); + sr->set_output((ScriptOutputContainer *) so); + } + } + else + { //some other single element + so = script_result_convert(L, pos+1); + if (so) + { + so->set_display( FLOW ); + sr = new ScriptResult; + sr->set_id(script_result_escape(luaL_checkstring(L, pos))); + sr->add_contents( so ); + } + } + return sr; +} + static int script_set_output (lua_State *L) { - ScriptResult sr; - sr.set_id(luaL_checkstring(L, 1)); - sr.set_output(luaL_checkstring(L, 2)); - script_scan_results.push_back(sr); + ScriptResult *sr = script_to_result(L, 1); + if (sr) + script_scan_results.push_back(sr); return 0; } static int host_set_output (lua_State *L) { - ScriptResult sr; Target *target = get_target(L, 1); - sr.set_id(luaL_checkstring(L, 2)); - sr.set_output(luaL_checkstring(L, 3)); - target->scriptResults.push_back(sr); + ScriptResult *sr = script_to_result(L, 2); + if (sr) + target->scriptResults.push_back(sr); return 0; } @@ -133,14 +286,15 @@ static int port_set_output (lua_State *L) { Port *p; Port port; - ScriptResult sr; Target *target = get_target(L, 1); p = get_port(L, target, &port, 2); - sr.set_id(luaL_checkstring(L, 3)); - sr.set_output(luaL_checkstring(L, 4)); - target->ports.addScriptResult(p->portno, p->proto, sr); - /* increment host port script results*/ - target->ports.numscriptresults++; + ScriptResult *sr = script_to_result(L, 3); + if (sr) + { + target->ports.addScriptResult(p->portno, p->proto, sr); + /* increment host port script results*/ + target->ports.numscriptresults++; + } return 0; } @@ -294,24 +448,283 @@ static void open_cnse (lua_State *L) setsfield(L, -1, "NMAP_URL", NMAP_URL); } -void ScriptResult::set_output (const char *out) +void ScriptResult::set_output (ScriptOutputContainer *c) { - output = std::string(out); + container = c; } -const char *ScriptResult::get_output (void) const +void ScriptResult::write_xml (void) const { - return output.c_str(); + ScriptOutputNode *curr; + if (container) + { + if (container->name != "" || container->warning != "") + { + container->write_xml(); + } + else + { + curr = container->head; + while (curr) + { + curr->write_xml(); + curr = curr->next; + } + } + } + else if (head) + { + curr = head; + while (curr) + { + curr->write_xml(); + curr = curr->next; + } + } + + return; +} + +void ScriptOutputNode::set_display (ScriptDisplay_t disp) +{ + display = disp; +} + +const ScriptDisplay_t ScriptOutputNode::get_display (void) const +{ + return display; +} + +void ScriptOutputNode::set_output (const std::string &out) +{ + name = out; +} + +const std::string ScriptOutputNode::get_output (std::string strindent) const +{ + /* Container handles indentation, otherwise: + * return strindent + name; + * and similar for ScriptOutputError, ScriptOutputKeyValue, ScriptOutputNode + */ + return name; +} + +const std::string ScriptOutputError::get_output (std::string strindent) const +{ + return "ERROR: "+name; +} + +void ScriptOutputKeyValue::set_key (const std::string &str) +{ + key = str; +} + +const std::string ScriptOutputKeyValue::get_output (std::string strindent) const +{ + return key + ": " + name; +} + +const std::string ScriptOutputNode::get_sep (const std::string &strindent) const +{ + switch (display) + { + case FLOW: + return ""; + break; + case TABLE: + fatal("TABLE display type not supported yet\n"); + case BLOCK: + default: + return ("\n"+strindent); + break; + } +} + +const std::string ScriptOutputContainer::get_sep (const std::string &strindent) const +{ + switch (display) + { + case FLOW: + case TABLE: + fatal("TABLE and FLOW display types not yet supported for containers\n"); + case BLOCK: + default: + return head + ? "\n"+strindent + : std::string(""); + break; + } +} + +void ScriptOutputContainer::set_warning (const std::string &str) +{ + warning = str; + return; +} + +void ScriptResult::add_contents (ScriptOutputNode *node) +{ + if (tail) + { + tail->next = node; + tail = node; + } + else + { + head = tail = node; + } + while (tail->next) + { + tail = tail->next; + } + return; +} + +void ScriptOutputContainer::add_contents (ScriptOutputNode *node) +{ + if (tail) + { + tail->next = node; + tail = node; + } + else + { + head = tail = node; + } + while (tail->next) + { + tail = tail->next; + } + return; +} + +const std::string ScriptResult::get_output (void) const +{ + std::string out; + if (container) + { + return container->get_output(out); + } + else if (head) + { + std::string strindent = NSE_INDENT; + ScriptOutputNode *curr = head; + while (curr) + { + if (curr->get_display() != FLOW) + out += "\n" NSE_INDENT; + out += curr->get_output(strindent); + curr = curr->next; + } + return out; + } + else + return out; +} + +const std::string ScriptOutputContainer::get_output (std::string strindent) const +{ + std::string out; + ScriptOutputNode *curr; + + out = name; + if (warning != "") + { + if (out != "") + out += " (WARNING: " + warning + ")"; + else + out = "(WARNING: " + warning + ")"; + } + if (out != "" || strindent == "") + { //avoid blank lines and indents for nameless containers + //but need a blank line if we are a ScriptResult->container + strindent += NSE_INDENT; + out += get_sep(strindent); + } + + curr = head; + while (curr) + { + out += curr->get_output(strindent); + curr = curr->next; + if (curr) + out += get_sep(strindent); + } + return out; +} + +void ScriptOutputNode::write_xml (void) const +{ + xml_start_tag("elem"); + char *n = strdup(name.c_str()); + xml_write_escaped("%s", n); + free(n); + xml_end_tag(); + return; +} + +void ScriptOutputError::write_xml (void) const +{ + xml_start_tag("error"); + char *n = strdup(name.c_str()); + xml_write_escaped("%s", n); + free(n); + xml_end_tag(); + return; +} + +void ScriptOutputKeyValue::write_xml (void) const +{ + xml_open_start_tag("elem"); + char *n = strdup(key.c_str()); + xml_attribute("key", "%s", n); + free(n); + xml_close_start_tag(); + n = strdup(name.c_str()); + xml_write_escaped("%s", n); + free(n); + xml_end_tag(); + return; +} + +void ScriptOutputContainer::write_xml (void) const +{ + ScriptOutputNode *curr; + xml_open_start_tag("container"); + char *n; + if (name != "") + { + n = strdup(name.c_str()); + xml_attribute("name", "%s", n); + free(n); + } + if (warning != "") + { + n = strdup(warning.c_str()); + xml_attribute("warning", "%s", n); + free(n); + } + xml_close_start_tag(); + + curr = head; + while (curr) + { + curr->write_xml(); + curr = curr->next; + } + + xml_end_tag(); + return; } -void ScriptResult::set_id (const char *ident) +void ScriptResult::set_id (const std::string &ident) { - id = std::string(ident); + id = ident; } -const char *ScriptResult::get_id (void) const +const std::string ScriptResult::get_id (void) const { - return id.c_str(); + return id; } ScriptResults *get_script_scan_results_obj (void) diff --git a/nse_main.h b/nse_main.h index 3a1455d..01f7d1a 100644 --- a/nse_main.h +++ b/nse_main.h @@ -16,19 +16,131 @@ extern "C" { #include "nmap.h" #include "global_structures.h" +#define NSE_INDENT " " + +/* Flow types not completely implemented. See YAML 1.1 specification for + * an idea of how this ought to work. + */ +typedef enum _ScriptDisplay_t +{ + TABLE, + FLOW, + BLOCK +} ScriptDisplay_t; + +/* An item of script output. + * Equivalent to a Lua variable. + * Rendered as a line of text, or an XML element. + */ +class ScriptOutputNode +{ + protected: + ScriptDisplay_t display; + std::string name; + public: + ScriptOutputNode *next; + ScriptOutputNode () + { + display = BLOCK; + next = NULL; + } + virtual ~ScriptOutputNode () + { + delete next; + } + const ScriptDisplay_t get_display (void) const; + virtual const std::string get_output (std::string) const; + virtual const std::string get_sep (const std::string &) const; + virtual void write_xml (void) const; + void set_output (const std::string &); + void set_display (ScriptDisplay_t); +}; + +/* Represents an error returned from a script. + * Rendered in Normal output as a line of text beginning with "ERROR:" + * and in XML as an element + */ +class ScriptOutputError: public ScriptOutputNode +{ + public: + const std::string get_output (std::string) const; + void write_xml (void) const; +}; + +/* Represents a Lua table with a single non-numeric key, string or number value + * Rendered in Normal output as "key: value" + * and in XML as value + */ +class ScriptOutputKeyValue: public ScriptOutputNode +{ + private: + std::string key; + public: + const std::string get_output (std::string) const; + void write_xml (void) const; + void set_key (const std::string &); +}; + +/* Represents a Lua table as described in stdnse.format_output. + * Renders in XML as + */ +class ScriptOutputContainer: public ScriptOutputNode +{ + protected: + std::string warning; + ScriptOutputNode *head; + ScriptOutputNode *tail; + public: + ScriptOutputContainer () + { + next = NULL; + head = NULL; + tail = NULL; + } + ~ScriptOutputContainer () + { + delete head; + //tail should be chained to head + } + const std::string get_sep (const std::string &) const; + const std::string get_output (std::string strindent="") const; + void write_xml (void) const; + void set_warning (const std::string &); + void add_contents (ScriptOutputNode *); + friend class ScriptResult; + /* For TABLE flow, possibly use a member function like this: + * const std::list *get_headers (void) const;*/ +}; + +/* Represents the total output of a script. + */ class ScriptResult { private: - std::string output; std::string id; + ScriptOutputNode *head; + ScriptOutputNode *tail; + ScriptOutputContainer *container; public: - void set_output (const char *); - const char *get_output (void) const; - void set_id (const char *); - const char *get_id (void) const; + ScriptResult () + { + head = tail = NULL; + container = NULL; + } + ~ScriptResult () + { + delete head; + delete container; + } + void write_xml (void) const; + const std::string get_output (void) const; + void set_output (ScriptOutputContainer *); + const std::string get_id (void) const; + void set_id (const std::string &); + void add_contents (ScriptOutputNode *); }; -typedef std::list ScriptResults; +typedef std::list ScriptResults; /* Call this to get a ScriptResults object which can be * used to store Pre-Scan and Post-Scan script Results */ diff --git a/nse_main.lua b/nse_main.lua index 8fd4aab..da9b398 100644 --- a/nse_main.lua +++ b/nse_main.lua @@ -899,13 +899,7 @@ local function run (threads_iter, hosts) end elseif status(co) == "dead" then all[co], num_threads = nil, num_threads-1; - if type(result) == "string" then - -- Escape any character outside the range 32-126 except for tab, - -- carriage return, and line feed. This makes the string safe for - -- screen display as well as XML (see section 2.2 of the XML spec). - result = gsub(result, "[^\t\r\n\032-\126]", function(a) - return format("\\x%02X", byte(a)); - end); + if result ~= nil then thread:set_output(result); end thread:d("Finished %THREAD_AGAINST."); diff --git a/nselib/stdnse.lua b/nselib/stdnse.lua index 7a7ed7e..b9bd52b 100644 --- a/nselib/stdnse.lua +++ b/nselib/stdnse.lua @@ -471,80 +471,21 @@ end -- A helper for format_output (see below). -local function format_output_sub(status, data, indent) - if (#data == 0) then - return "" - end - - -- Used to put 'ERROR: ' in front of all lines on error messages - local prefix = "" - -- Initialize the output string to blank (or, if we're at the top, add a newline) - local output = {} - if(not(indent)) then - insert(output, '\n') - end - - if(not(status)) then - if(nmap.debugging() < 1) then - return nil - end - prefix = "ERROR: " - end - - -- If a string was passed, turn it into a table - if(type(data) == 'string') then - data = {data} - end - - -- Make sure we have an indent value - indent = indent or {} - - if(data['name']) then - if(data['warning'] and nmap.debugging() > 0) then - insert(output, format("%s%s%s (WARNING: %s)\n", - format_get_indent(indent), prefix, - data['name'], data['warning'])) - else - insert(output, format("%s%s%s\n", - format_get_indent(indent), prefix, - data['name'])) - end - elseif(data['warning'] and nmap.debugging() > 0) then - insert(output, format("%s%s(WARNING: %s)\n", - format_get_indent(indent), prefix, - data['warning'])) - end - - for i, value in ipairs(data) do - if(type(value) == 'table') then - -- Do a shallow copy of indent - local new_indent = {} - for _, v in ipairs(indent) do - insert(new_indent, v) - end - - if(i ~= #data) then - insert(new_indent, false) - else - insert(new_indent, true) - end - - insert(output, format_output_sub(status, value, new_indent)) - - elseif(type(value) == 'string') then - local lines = splitlines(value) - - for j, line in ipairs(lines) do - insert(output, format("%s %s%s\n", - format_get_indent(indent, i == #data and j == #lines), - prefix, line)) +--- Helper function for format_output +-- Ensures that tables with "name" or "warning" members get treated as +-- containers, not ScriptOutputKeyValue in nse_main.cc, by adding an empty +-- table at a numeric index, ensuring that #t > 0 +local function fill_containers(t) + if(type(t) ~= "table") then return end + if(#t == 0 and (t['name'] or t['warning'])) then + insert(t,{}) + else + for i,v in ipairs(t) do + fill_containers(t[i]) end end end - return concat(output) -end - ---Takes a table of output on the commandline and formats it for display to the -- user. This is basically done by converting an array of nested tables into a -- string. In addition to numbered array elements, each table can have a 'name' @@ -556,8 +497,8 @@ end -- -- local domains = {} -- domains['name'] = "DOMAINS" --- table.insert(domains, 'Domain 1') --- table.insert(domains, 'Domain 2') +-- table.insert(domains, {['Domain 1']="example.com"}) +-- table.insert(domains, {['Domain 2']="nmap.org"}) -- -- local names = {} -- names['name'] = "NAMES" @@ -578,38 +519,56 @@ end -- | smb-enum-domains: -- | Apple pie -- | DOMAINS --- | Domain 1 --- | Domain 2 +-- | Domain 1: example.com +-- | Domain 2: nmap.org -- | NAMES (WARNING: Not all names could be determined!) -- |_ Name 1 -- -- +-- The same table will also be rendered for XML output as +-- +-- +-- +-- --@param status A boolean value dictating whether or not the script succeeded. -- If status is false, and debugging is enabled, 'ERROR' is prepended --- to every line. If status is false and debugging is disabled, no output +-- to the line. If status is false and debugging is disabled, no output -- occurs. ---@param data The table of output. ---@param indent Used for indentation on recursive calls; should generally be set to --- nil when callling from a script. --- @return nil, if data is empty, otherwise a --- multiline string. -function format_output(status, data, indent) +--@param data The table of output. This table may be modified by the function. +-- @return nil, if data is empty or status is false +-- and debugging is disabled, otherwise a table properly formatted +-- for the Scripting Engine to output. +function format_output(status, data) -- If data is nil, die with an error (I keep doing that by accident) assert(data, "No data was passed to format_output()") + fill_containers(data) + -- Don't bother if we don't have any data - if (#data == 0) then + if (data == nil or #data == 0 or data == "\n") then return nil end - local result = format_output_sub(status, data, indent) - - -- Check for an empty result - if(result == nil or #result == "" or result == "\n" or result == "\n") then - return nil + if(not(status)) then + if(nmap.debugging() < 1) then + return nil + end + if(type(data) == "table") then + data = {name="ERROR:", data} + else + data = {[0]=data} + end end - - return result + return data end -- Get the value of a script argument, or nil if the script argument was not diff --git a/output.cc b/output.cc index 57eb005..8195df7 100644 --- a/output.cc +++ b/output.cc @@ -425,27 +425,24 @@ int print_iflist(void) { } #ifndef NOLUA -static char *formatScriptOutput(ScriptResult sr) { +static char *formatScriptOutput( const ScriptResult* sr) { std::vector lines; - const char *c_output; - const char *p, *q; + std::string c_output; std::string result; unsigned int i; - c_output = sr.get_output(); - p = c_output; + c_output = sr->get_output(); - while (*p != '\0') { - q = strchr(p, '\n'); - if (q == NULL) { - lines.push_back(std::string(p)); - break; - } else { - lines.push_back(std::string(p, q - p)); - p = q + 1; - } + size_t pos, prev = 0; + pos = c_output.find('\n'); + while ( pos != std::string::npos ) + { + lines.push_back(c_output.substr(prev, pos - prev)); + prev = pos+1; + pos = c_output.find('\n', prev); } + lines.push_back(c_output.substr(prev)); if (lines.empty()) lines.push_back(""); @@ -455,7 +452,7 @@ static char *formatScriptOutput(ScriptResult sr) { else result += "|_"; if (i == 0) - result += std::string(sr.get_id()) + ": "; + result += sr->get_id() + ": "; result += lines[i]; if (i < lines.size() - 1) result += "\n"; @@ -789,11 +786,12 @@ void printportoutput(Target *currenths, PortList *plist) { for (ssr_iter = current->scriptResults.begin(); ssr_iter != current->scriptResults.end(); ssr_iter++) { xml_open_start_tag("script"); - xml_attribute("id", "%s", ssr_iter->get_id()); - xml_attribute("output", "%s", ssr_iter->get_output()); - xml_close_empty_tag(); + xml_attribute("id", "%s", (*ssr_iter)->get_id().c_str()); + xml_close_start_tag(); + (*ssr_iter)->write_xml(); + xml_end_tag(); - char *script_output = formatScriptOutput((*ssr_iter)); + char *script_output = formatScriptOutput(*ssr_iter); Tbl->addItem(rowno, 0, true, true, script_output); free(script_output); rowno++; @@ -949,7 +947,7 @@ void log_vwrite(int logt, const char *fmt, va_list ap) { l >>= 1; } assert(fileidx < LOG_NUM_FILES); - if (o.logfd[fileidx]) { + if (o.logfd[fileidx] && len) { if (logt == LOG_SKID && !skid_noxlate) skid_output(writebuf); rc = fwrite(writebuf, len, 1, o.logfd[fileidx]); @@ -2183,10 +2181,11 @@ void printscriptresults(ScriptResults *scriptResults, stype scantype) { iter != scriptResults->end(); iter++) { xml_open_start_tag("script"); - xml_attribute("id", "%s", iter->get_id()); - xml_attribute("output", "%s", iter->get_output()); - xml_close_empty_tag(); - script_output = formatScriptOutput((*iter)); + xml_attribute("id", "%s", (*iter)->get_id().c_str()); + xml_close_start_tag(); + (*iter)->write_xml(); + xml_end_tag(); + script_output = formatScriptOutput(*iter); log_write(LOG_PLAIN, "%s\n", script_output); free(script_output); } @@ -2205,10 +2204,11 @@ void printhostscriptresults(Target *currenths) { iter != currenths->scriptResults.end(); iter++) { xml_open_start_tag("script"); - xml_attribute("id", "%s", iter->get_id()); - xml_attribute("output", "%s", iter->get_output()); - xml_close_empty_tag(); - script_output = formatScriptOutput((*iter)); + xml_attribute("id", "%s", (*iter)->get_id().c_str()); + xml_close_start_tag(); + (*iter)->write_xml(); + xml_end_tag(); + script_output = formatScriptOutput(*iter); log_write(LOG_PLAIN, "%s\n", script_output); free(script_output); } diff --git a/portlist.cc b/portlist.cc index eeb40ef..5a66e4a 100644 --- a/portlist.cc +++ b/portlist.cc @@ -453,7 +453,7 @@ void PortList::setRPCProbeResults(u16 portno, int proto, int rpcs, unsigned long #ifndef NOLUA -void PortList::addScriptResult(u16 portno, int protocol, ScriptResult& sr) { +void PortList::addScriptResult(u16 portno, int protocol, ScriptResult *sr) { Port *port; port = createPort(portno, protocol); @@ -508,6 +508,12 @@ PortList::~PortList() { for(i=0; i < port_list_count[proto]; i++) { // free every Port if(port_list[proto][i]) { port_list[proto][i]->freeService(true); +#ifndef NOLUA + while (!port_list[proto][i]->scriptResults.empty()) { + delete port_list[proto][i]->scriptResults.front(); + port_list[proto][i]->scriptResults.pop_front(); + } +#endif delete port_list[proto][i]; } } diff --git a/portlist.h b/portlist.h index 0d39fc4..ea6f48a 100644 --- a/portlist.h +++ b/portlist.h @@ -285,7 +285,7 @@ class PortList { unsigned int rpc_lowver, unsigned int rpc_highver); #ifndef NOLUA - void addScriptResult(u16 portno, int protocol, ScriptResult& sr); + void addScriptResult(u16 portno, int protocol, ScriptResult *sr); #endif /* Cycles through the 0 or more "ignored" ports which should be