From d08f03058bc9680cd39c427b8adac87aa0a44429 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 9 Sep 2019 23:46:38 +0200 Subject: [PATCH] add support for (nested) cmd scripts in script list/run --- client/cmdscript.c | 102 ++++++++++++++++++++++++++------------------- client/fileutils.c | 1 + client/proxmark3.c | 63 +++++++++++++++++++++------- client/proxmark3.h | 2 + 4 files changed, 111 insertions(+), 57 deletions(-) diff --git a/client/cmdscript.c b/client/cmdscript.c index 473477228..a721acee5 100644 --- a/client/cmdscript.c +++ b/client/cmdscript.c @@ -33,7 +33,10 @@ static int CmdHelp(const char *Cmd); */ static int CmdScriptList(const char *Cmd) { (void)Cmd; // Cmd is not used so far - return searchAndList(LUA_SCRIPTS_SUBDIR, ".lua"); + int ret = searchAndList(LUA_SCRIPTS_SUBDIR, ".lua"); + if (ret != PM3_SUCCESS) + return ret; + return searchAndList(CMD_SCRIPTS_SUBDIR, ".cmd"); } /** @@ -43,21 +46,6 @@ static int CmdScriptList(const char *Cmd) { * @return */ static int CmdScriptRun(const char *Cmd) { - // create new Lua state - lua_State *lua_state; - lua_state = luaL_newstate(); - - // load Lua libraries - luaL_openlibs(lua_state); - - //Sets the pm3 core libraries, that go a bit 'under the hood' - set_pm3_libraries(lua_state); - - //Add the 'bin' library - set_bin_library(lua_state); - - //Add the 'bit' library - set_bit_library(lua_state); char preferredName[128] = {0}; char arguments[256] = {0}; @@ -67,37 +55,65 @@ static int CmdScriptRun(const char *Cmd) { sscanf(Cmd, "%127s%n %255[^\n\r]%n", preferredName, &name_len, arguments, &arg_len); char *script_path; - int res = searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", false); - if (res != PM3_SUCCESS) - return res; + if ((!str_endswith(preferredName, ".cmd")) && (searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", true) == PM3_SUCCESS)) { + int error; + PrintAndLogEx(SUCCESS, "Executing Lua script: %s, args '%s'\n", script_path, arguments); - int error; - PrintAndLogEx(SUCCESS, "Executing: %s, args '%s'\n", script_path, arguments); - error = luaL_loadfile(lua_state, script_path); - free(script_path); - if (!error) { - lua_pushstring(lua_state, arguments); - lua_setglobal(lua_state, "args"); + // create new Lua state + lua_State *lua_state; + lua_state = luaL_newstate(); - //Call it with 0 arguments - error = lua_pcall(lua_state, 0, LUA_MULTRET, 0); // once again, returns non-0 on error, + // load Lua libraries + luaL_openlibs(lua_state); + + //Sets the pm3 core libraries, that go a bit 'under the hood' + set_pm3_libraries(lua_state); + + //Add the 'bin' library + set_bin_library(lua_state); + + //Add the 'bit' library + set_bit_library(lua_state); + + error = luaL_loadfile(lua_state, script_path); + free(script_path); + if (!error) { + lua_pushstring(lua_state, arguments); + lua_setglobal(lua_state, "args"); + + //Call it with 0 arguments + error = lua_pcall(lua_state, 0, LUA_MULTRET, 0); // once again, returns non-0 on error, + } + if (error) { // if non-0, then an error + // the top of the stack should be the error string + if (!lua_isstring(lua_state, lua_gettop(lua_state))) + PrintAndLogEx(FAILED, "Error - but no error (?!)"); + + // get the top of the stack as the error and pop it off + const char *str = lua_tostring(lua_state, lua_gettop(lua_state)); + lua_pop(lua_state, 1); + puts(str); + } + + //luaL_dofile(lua_state, buf); + // close the Lua state + lua_close(lua_state); + PrintAndLogEx(SUCCESS, "\nFinished\n"); + return PM3_SUCCESS; } - if (error) { // if non-0, then an error - // the top of the stack should be the error string - if (!lua_isstring(lua_state, lua_gettop(lua_state))) - PrintAndLogEx(FAILED, "Error - but no error (?!)"); - - // get the top of the stack as the error and pop it off - const char *str = lua_tostring(lua_state, lua_gettop(lua_state)); - lua_pop(lua_state, 1); - puts(str); + if ((!str_endswith(preferredName, ".lua")) && (searchFile(&script_path, CMD_SCRIPTS_SUBDIR, preferredName, ".cmd", true) == PM3_SUCCESS)) { + PrintAndLogEx(SUCCESS, "Executing Cmd script: %s, args '%s'\n", script_path, arguments); + int ret = push_cmdscriptfile(script_path, true); + if (ret != PM3_SUCCESS) + PrintAndLogEx(ERR, "could not open " _YELLOW_("%s") "...", script_path); + free(script_path); + return ret; } - - //luaL_dofile(lua_state, buf); - // close the Lua state - lua_close(lua_state); - PrintAndLogEx(SUCCESS, "\nFinished\n"); - return 0; + // file not found, let's search again to display the error messages + int ret = PM3_EUNDEF; + if (!str_endswith(preferredName, ".cmd")) ret = searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", false); + if (!str_endswith(preferredName, ".lua")) ret = searchFile(&script_path, CMD_SCRIPTS_SUBDIR, preferredName, ".cmd", false); + return ret; } static command_t CommandTable[] = { diff --git a/client/fileutils.c b/client/fileutils.c index f379f56d3..8e0e3bb72 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -933,6 +933,7 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea ((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) || (strcmp(LUA_LIBRARIES_SUBDIR, pm3dir) == 0) || (strcmp(LUA_SCRIPTS_SUBDIR, pm3dir) == 0) || + (strcmp(CMD_SCRIPTS_SUBDIR, pm3dir) == 0) || (strcmp(RESOURCES_SUBDIR, pm3dir) == 0))) { char *path = calloc(strlen(exec_path) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); if (path == NULL) diff --git a/client/proxmark3.c b/client/proxmark3.c index dbca25d17..aa37cda9a 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -63,6 +63,38 @@ int check_comm(void) { return 0; } +// first slot is always NULL, indicating absence of script when idx=0 +FILE *cmdscriptfile[MAX_NESTED_CMDSCRIPT + 1] = {0}; +uint8_t cmdscriptfile_idx = 0; +bool cmdscriptfile_stayafter = false; + +int push_cmdscriptfile(char *path, bool stayafter) { + if (cmdscriptfile_idx == MAX_NESTED_CMDSCRIPT) { + PrintAndLogEx(ERR, "Too many nested scripts, skipping %s\n", path); + return PM3_EMALLOC; + } + FILE *tmp = fopen(path, "r"); + if (tmp == NULL) + return PM3_EFILE; + if (cmdscriptfile_idx == 0) + cmdscriptfile_stayafter = stayafter; + cmdscriptfile[++cmdscriptfile_idx] = tmp; + return PM3_SUCCESS; +} + +FILE *current_cmdscriptfile() { + return cmdscriptfile[cmdscriptfile_idx]; +} + +bool pop_cmdscriptfile() { + fclose(cmdscriptfile[cmdscriptfile_idx]); + cmdscriptfile[cmdscriptfile_idx--] = NULL; + if (cmdscriptfile_idx == 0) + return cmdscriptfile_stayafter; + else + return true; +} + // Main thread of PM3 Client void #ifdef __has_attribute @@ -80,7 +112,6 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { strcreplace(script_cmd, script_cmd_len, ';', '\0'); } bool stdinOnPipe = !isatty(STDIN_FILENO); - FILE *sf = NULL; char script_cmd_buf[256] = {0x00}; // iceman, needs lua script the same file_path_buffer as the rest PrintAndLogEx(DEBUG, "ISATTY/STDIN_FILENO == %s\n", (stdinOnPipe) ? "true" : "false"); @@ -98,8 +129,7 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { char *path; int res = searchFile(&path, CMD_SCRIPTS_SUBDIR, script_cmds_file, ".cmd", false); if (res == PM3_SUCCESS) { - sf = fopen(path, "r"); - if (sf) + if (push_cmdscriptfile(path, stayInCommandLoop) == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "executing commands from file: %s\n", path); else PrintAndLogEx(ERR, "could not open " _YELLOW_("%s") "...", path); @@ -119,16 +149,18 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { bool printprompt = false; char *prompt = PROXPROMPT; +check_script: // If there is a script file - if (sf) { + if (current_cmdscriptfile()) { // clear array memset(script_cmd_buf, 0, sizeof(script_cmd_buf)); // read script file - if (!fgets(script_cmd_buf, sizeof(script_cmd_buf), sf)) { - fclose(sf); - sf = NULL; + if (!fgets(script_cmd_buf, sizeof(script_cmd_buf), current_cmdscriptfile())) { + if (!pop_cmdscriptfile()) + break; + goto check_script; } else { // remove linebreaks @@ -205,12 +237,15 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { PrintAndLogEx(NORMAL, "%s%s", prompt, cmd); g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; + // add to history if not from a script + if (!current_cmdscriptfile()) { + HIST_ENTRY *entry = history_get(history_length); + // add if not identical to latest recorded cmd + if ((!entry) || (strcmp(entry->line, cmd) != 0)) + add_history(cmd); + } + // process cmd int ret = CommandReceived(cmd); - - HIST_ENTRY *entry = history_get(history_length); - if ((!entry) || (strcmp(entry->line, cmd) != 0)) - add_history(cmd); - // exit or quit if (ret == PM3_EFATAL) break; @@ -230,8 +265,8 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { SendCommandNG(CMD_QUIT_SESSION, NULL, 0); msleep(100); // Make sure command is sent before killing client - if (sf) - fclose(sf); + while (current_cmdscriptfile()) + pop_cmdscriptfile(); if (my_history_path) { write_history(my_history_path); diff --git a/client/proxmark3.h b/client/proxmark3.h index 3da261c31..14148747c 100644 --- a/client/proxmark3.h +++ b/client/proxmark3.h @@ -20,11 +20,13 @@ #define PROXPROMPT_OFFLINE "[offline] pm3 --> " #define PROXHISTORY "history.txt" #define PROXLOG "log_%Y%m%d.txt" +#define MAX_NESTED_CMDSCRIPT 10 #ifdef __cplusplus extern "C" { #endif +int push_cmdscriptfile(char *path, bool stayafter); const char *get_my_executable_path(void); const char *get_my_executable_directory(void); void main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop);