Index: nmap.cc =================================================================== --- nmap.cc (revision 33625) +++ nmap.cc (working copy) @@ -147,6 +147,7 @@ #ifndef NOLUA #include "nse_main.h" +#include "nse_utility.h" /* for nseU_traceback in apply_nmaprc_profile(). */ #endif #ifdef WIN32 @@ -326,6 +327,9 @@ " --webxml: Reference stylesheet from Nmap.Org for more portable XML\n" " --no-stylesheet: Prevent associating of XSL stylesheet w/XML output\n" "MISC:\n" +#ifndef NOLUA + " -w/--profile: Apply the profile specified in .nmaprc.lua file\n" +#endif " -6: Enable IPv6 scanning\n" " -A: Enable OS detection, version detection, script scanning, and traceroute\n" " --datadir : Specify custom Nmap data file location\n" @@ -505,6 +509,64 @@ struct tm *local_time; +#ifndef NOLUA +static char** apply_nmaprc_profile(char* profile, int* argc, char** argv) { + + lua_State *L; + int last_function_number; + + L = luaL_newstate(); + luaL_openlibs(L); + + char nmaprc_path[MAXPATHLEN]; + char* homedir = getenv("HOME"); + if (homedir == NULL) + fatal("Could not determine the home directory."); + Snprintf(nmaprc_path, sizeof(nmaprc_path), "%s/.nmaprc.lua", homedir); + + if (luaL_loadfile(L, nmaprc_path) != 0) + fatal("Error loading \"%s\".", nmaprc_path); + + /* install the traceback function */ + last_function_number = lua_gettop(L); + lua_pushcfunction(L, nseU_traceback); + lua_insert(L, last_function_number); + + if (lua_pcall(L, 0, 0, last_function_number) != 0 && !lua_isnil(L, -1)) { + /* handle the error; the code below is taken from lua.c, Lua source code */ + lua_remove(L, last_function_number); + fatal("Error running the Lua script"); + } else { + + lua_getglobal(L, "profiles"); + if (!lua_istable(L, -1)) + fatal("No \"profile\" table defined in nmaprc.lua!"); + lua_getfield(L, -1, profile); + if (lua_isnil(L, -1)) + fatal("Profile \"%s\" not found!", profile); + + lua_len(L, -1); + size_t num_args = lua_tointeger(L, -1); + lua_pop(L, 1); + + char** ret = (char**)safe_realloc(argv, (*argc + num_args + 1) * sizeof(char *)); + + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + ret[(*argc)++] = strdup(lua_tostring(L, -1)); + lua_pop(L, 1); + } + ret[*argc] = NULL; + + lua_pop(L, 2); + lua_close(L); + + return ret; + + } +} +#endif + static void test_file_name(const char *filename, const char *option) { if (filename[0] == '-' && filename[1] != '\0') { fatal("Output filename begins with '-'. Try '-%s ./%s' if you really want it to be named as such.", option, filename); @@ -513,7 +575,14 @@ } } -void parse_options(int argc, char **argv) { +/* Parses nmap options. The third argument, profile_arg_idx is the index of + --profile command argument and should be set to -1 at the first call. It + is going to be used in another, recursive call of this function that happens + if we actually find any invocation of --profile. + + The function returns char**, which is the argv that should be used after + the parsing of the options. This is only modified if --profile was used. */ +char** parse_options(int argc, char **argv, int profile_arg_idx) { char *p, *q; int arg; long l; @@ -654,6 +723,7 @@ {"script_args_file", required_argument, 0, 0}, {"script-help", required_argument, 0, 0}, {"script_help", required_argument, 0, 0}, + {"profile", required_argument, 0, 'w'}, #endif {"ip_options", required_argument, 0, 0}, {"ip-options", required_argument, 0, 0}, @@ -673,7 +743,7 @@ /* OK, lets parse these args! */ optind = 1; /* so it can be called multiple times */ - while ((arg = getopt_long_only(argc, argv, "6Ab:D:d::e:Ffg:hIi:M:m:nO::o:P:p:qRrS:s:T:Vv::", long_options, &option_index)) != EOF) { + while ((arg = getopt_long_only(argc, argv, "6Ab:D:d::e:Ffg:hIi:M:m:nO::o:P:p:qRrS:s:T:w:Vv::", long_options, &option_index)) != EOF) { switch (arg) { case 0: #ifndef NOLUA @@ -1369,9 +1439,31 @@ fatal("Invalid argument to -v: \"%s\".", optarg); } break; - } +#ifndef NOLUA + case 'w': + if (profile_arg_idx == -1) { + + int new_argc = argc; + char** new_argv = apply_nmaprc_profile(optarg, &new_argc, argv); + if (new_argv == NULL) + fatal("Could not find .nmaprc profile: %s", optarg); + + if (o.debugging) + log_write(LOG_PLAIN, "Running parse_options() again.\n"); + + return parse_options(new_argc, new_argv, optind); + } else { + if (optind != profile_arg_idx) { + fatal("Cannot specify more than one --profile."); + } + + } + break; +#endif + } } + return argv; } void apply_delayed_options() { @@ -1631,6 +1723,14 @@ } +char** copy_argv(int argc, char **argv) { + char** ret = (char **)safe_malloc(sizeof(char*) * (argc)); + for (int i = 0; i Targets; @@ -1671,7 +1771,8 @@ win_pre_init(); #endif - parse_options(argc, argv); + char** copied_argv = copy_argv(argc, argv); + argv = parse_options(argc, copied_argv, -1); tty_init(); // Put the keyboard in raw mode