summaryrefslogtreecommitdiffstats
path: root/epan/wslua/init_wslua.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/wslua/init_wslua.c')
-rw-r--r--epan/wslua/init_wslua.c1760
1 files changed, 1760 insertions, 0 deletions
diff --git a/epan/wslua/init_wslua.c b/epan/wslua/init_wslua.c
new file mode 100644
index 0000000..4009326
--- /dev/null
+++ b/epan/wslua/init_wslua.c
@@ -0,0 +1,1760 @@
+/*
+ * init_wslua.c
+ *
+ * Wireshark's interface to the Lua Programming Language
+ *
+ * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+#define WS_LOG_DOMAIN LOG_DOMAIN_WSLUA
+
+#include "wslua.h"
+#include "init_wslua.h"
+
+#include <epan/dissectors/packet-frame.h>
+#include <errno.h>
+#include <math.h>
+#include <stdio.h>
+#include <epan/expert.h>
+#include <epan/ex-opt.h>
+#include <epan/introspection.h>
+#include <wiretap/introspection.h>
+#include <wsutil/privileges.h>
+#include <wsutil/file_util.h>
+#include <wsutil/wslog.h>
+
+/* linked list of Lua plugins */
+typedef struct _wslua_plugin {
+ gchar *name; /**< plugin name */
+ gchar *version; /**< plugin version */
+ gchar *filename; /**< plugin filename */
+ struct _wslua_plugin *next;
+} wslua_plugin;
+
+static wslua_plugin *wslua_plugin_list = NULL;
+
+static lua_State* L = NULL;
+
+static void (*wslua_gui_print_func_ptr)(const char *, void *) = NULL;
+static void *wslua_gui_print_data_ptr = NULL;
+static int wslua_lua_print_func_ref = LUA_NOREF;
+
+/* XXX: global variables? Really?? Yuck. These could be done differently,
+ using the Lua registry */
+packet_info* lua_pinfo;
+struct _wslua_treeitem* lua_tree;
+tvbuff_t* lua_tvb;
+int lua_dissectors_table_ref = LUA_NOREF;
+int lua_heur_dissectors_table_ref = LUA_NOREF;
+
+static int proto_lua = -1;
+
+static int hf_wslua_fake = -1;
+static int hf_wslua_text = -1;
+
+static expert_field ei_lua_error = EI_INIT;
+
+static expert_field ei_lua_proto_checksum_comment = EI_INIT;
+static expert_field ei_lua_proto_checksum_chat = EI_INIT;
+static expert_field ei_lua_proto_checksum_note = EI_INIT;
+static expert_field ei_lua_proto_checksum_warn = EI_INIT;
+static expert_field ei_lua_proto_checksum_error = EI_INIT;
+
+static expert_field ei_lua_proto_sequence_comment = EI_INIT;
+static expert_field ei_lua_proto_sequence_chat = EI_INIT;
+static expert_field ei_lua_proto_sequence_note = EI_INIT;
+static expert_field ei_lua_proto_sequence_warn = EI_INIT;
+static expert_field ei_lua_proto_sequence_error = EI_INIT;
+
+static expert_field ei_lua_proto_response_comment = EI_INIT;
+static expert_field ei_lua_proto_response_chat = EI_INIT;
+static expert_field ei_lua_proto_response_note = EI_INIT;
+static expert_field ei_lua_proto_response_warn = EI_INIT;
+static expert_field ei_lua_proto_response_error = EI_INIT;
+
+static expert_field ei_lua_proto_request_comment = EI_INIT;
+static expert_field ei_lua_proto_request_chat = EI_INIT;
+static expert_field ei_lua_proto_request_note = EI_INIT;
+static expert_field ei_lua_proto_request_warn = EI_INIT;
+static expert_field ei_lua_proto_request_error = EI_INIT;
+
+static expert_field ei_lua_proto_undecoded_comment = EI_INIT;
+static expert_field ei_lua_proto_undecoded_chat = EI_INIT;
+static expert_field ei_lua_proto_undecoded_note = EI_INIT;
+static expert_field ei_lua_proto_undecoded_warn = EI_INIT;
+static expert_field ei_lua_proto_undecoded_error = EI_INIT;
+
+static expert_field ei_lua_proto_reassemble_comment = EI_INIT;
+static expert_field ei_lua_proto_reassemble_chat = EI_INIT;
+static expert_field ei_lua_proto_reassemble_note = EI_INIT;
+static expert_field ei_lua_proto_reassemble_warn = EI_INIT;
+static expert_field ei_lua_proto_reassemble_error = EI_INIT;
+
+static expert_field ei_lua_proto_malformed_comment = EI_INIT;
+static expert_field ei_lua_proto_malformed_chat = EI_INIT;
+static expert_field ei_lua_proto_malformed_note = EI_INIT;
+static expert_field ei_lua_proto_malformed_warn = EI_INIT;
+static expert_field ei_lua_proto_malformed_error = EI_INIT;
+
+static expert_field ei_lua_proto_debug_comment = EI_INIT;
+static expert_field ei_lua_proto_debug_chat = EI_INIT;
+static expert_field ei_lua_proto_debug_note = EI_INIT;
+static expert_field ei_lua_proto_debug_warn = EI_INIT;
+static expert_field ei_lua_proto_debug_error = EI_INIT;
+
+static expert_field ei_lua_proto_protocol_comment = EI_INIT;
+static expert_field ei_lua_proto_protocol_chat = EI_INIT;
+static expert_field ei_lua_proto_protocol_note = EI_INIT;
+static expert_field ei_lua_proto_protocol_warn = EI_INIT;
+static expert_field ei_lua_proto_protocol_error = EI_INIT;
+
+static expert_field ei_lua_proto_security_comment = EI_INIT;
+static expert_field ei_lua_proto_security_chat = EI_INIT;
+static expert_field ei_lua_proto_security_note = EI_INIT;
+static expert_field ei_lua_proto_security_warn = EI_INIT;
+static expert_field ei_lua_proto_security_error = EI_INIT;
+
+static expert_field ei_lua_proto_comments_comment = EI_INIT;
+static expert_field ei_lua_proto_comments_chat = EI_INIT;
+static expert_field ei_lua_proto_comments_note = EI_INIT;
+static expert_field ei_lua_proto_comments_warn = EI_INIT;
+static expert_field ei_lua_proto_comments_error = EI_INIT;
+
+static expert_field ei_lua_proto_decryption_comment = EI_INIT;
+static expert_field ei_lua_proto_decryption_chat = EI_INIT;
+static expert_field ei_lua_proto_decryption_note = EI_INIT;
+static expert_field ei_lua_proto_decryption_warn = EI_INIT;
+static expert_field ei_lua_proto_decryption_error = EI_INIT;
+
+static expert_field ei_lua_proto_assumption_comment = EI_INIT;
+static expert_field ei_lua_proto_assumption_chat = EI_INIT;
+static expert_field ei_lua_proto_assumption_note = EI_INIT;
+static expert_field ei_lua_proto_assumption_warn = EI_INIT;
+static expert_field ei_lua_proto_assumption_error = EI_INIT;
+
+static expert_field ei_lua_proto_deprecated_comment = EI_INIT;
+static expert_field ei_lua_proto_deprecated_chat = EI_INIT;
+static expert_field ei_lua_proto_deprecated_note = EI_INIT;
+static expert_field ei_lua_proto_deprecated_warn = EI_INIT;
+static expert_field ei_lua_proto_deprecated_error = EI_INIT;
+
+static gint ett_wslua_traceback = -1;
+
+static bool
+lua_pinfo_end(wmem_allocator_t *allocator _U_, wmem_cb_event_t event _U_,
+ void *user_data _U_)
+{
+ clear_outstanding_Tvb();
+ clear_outstanding_TvbRange();
+ clear_outstanding_Pinfo();
+ clear_outstanding_Column();
+ clear_outstanding_Columns();
+ clear_outstanding_PrivateTable();
+ clear_outstanding_TreeItem();
+ clear_outstanding_FieldInfo();
+ clear_outstanding_FuncSavers();
+
+ /* keep invoking this callback later? */
+ return FALSE;
+}
+
+static int wslua_not_register_menu(lua_State* LS) {
+ luaL_error(LS,"too late to register a menu");
+ return 0;
+}
+
+/* a getter for wslua_tree.c's TreeItem_add_item_any() to use */
+int get_hf_wslua_text(void) {
+ return hf_wslua_text;
+}
+
+#if LUA_VERSION_NUM >= 502
+// Attach the lua traceback to the proto_tree
+static int dissector_error_handler(lua_State *LS) {
+ // Entering, stack: [ error_handler, dissector, errmsg ]
+
+ proto_item *tb_item;
+ proto_tree *tb_tree;
+
+ // Add the expert info Lua error message
+ proto_tree_add_expert_format(lua_tree->tree, lua_pinfo, &ei_lua_error, lua_tvb, 0, 0,
+ "Lua Error: %s", lua_tostring(LS,-1));
+
+ // Create a new proto sub_tree for the traceback
+ tb_item = proto_tree_add_text_internal(lua_tree->tree, lua_tvb, 0, 0, "Lua Traceback");
+ tb_tree = proto_item_add_subtree(tb_item, ett_wslua_traceback);
+
+ // Push the traceback onto the stack
+ // After call, stack: [ error_handler, dissector, errmsg, tb_string ]
+ luaL_traceback(LS, LS, NULL, 1);
+
+ // Get the string length of the traceback. Note that the string
+ // has a terminating NUL, but string_length doesn't include it.
+ // The lua docs say the string can have NULs in it too, but we
+ // ignore that because the traceback string shouldn't have them.
+ // This function does not own the string; it's still owned by lua.
+ size_t string_length;
+ const char *orig_tb_string = lua_tolstring(LS, -1, &string_length);
+
+ // We make the copy so we can modify the string. Don't forget the
+ // extra byte for the terminating NUL!
+ char *tb_string = (char*) g_memdup2(orig_tb_string, string_length+1);
+
+ // The string has tabs and new lines in it
+ // We will add proto_items for each new-line-delimited sub-string.
+ // We also convert tabs to spaces, because the Wireshark GUI
+ // shows tabs literally as "\t".
+
+ // 'beginning' is the beginning of the sub-string
+ char *beginning = tb_string;
+
+ // 'p' is the pointer to the byte as we iterate over the string
+ char *p = tb_string;
+
+ size_t i;
+ bool skip_initial_tabs = true;
+ size_t last_eol_i = 0;
+ for (i = 0 ; i < string_length ; i++) {
+ // At the beginning of a sub-string, we will convert tabs to spaces
+ if (skip_initial_tabs) {
+ if (*p == '\t') {
+ *p = ' ';
+ } else {
+ // Once we hit the first non-tab character in a substring,
+ // we won't convert tabs (until the next substring)
+ skip_initial_tabs = false;
+ }
+ }
+ // If we see a newline, we add the substring to the proto tree
+ if (*p == '\n') {
+ // Terminate the string.
+ *p = '\0';
+ proto_tree_add_text_internal(tb_tree, lua_tvb, 0, 0, "%s", beginning);
+ beginning = ++p;
+ skip_initial_tabs = true;
+ last_eol_i = i;
+ } else {
+ ++p;
+ }
+ }
+
+ // The last portion of the string doesn't have a newline, so add it here
+ // after the loop. But to be sure, check that we didn't just add it, in
+ // case lua decides to change it in the future.
+ if ( last_eol_i < i-1 ) {
+ proto_tree_add_text_internal(tb_tree, lua_tvb, 0, 0, "%s", beginning);
+ }
+
+ // Cleanup
+ g_free(tb_string);
+
+ // Return the same original error message
+ return -2;
+}
+
+#else
+
+static int dissector_error_handler(lua_State *LS) {
+ // Entering, stack: [ error_handler, dissector, errmsg ]
+ proto_tree_add_expert_format(lua_tree->tree, lua_pinfo, &ei_lua_error, lua_tvb, 0, 0,
+ "Lua Error: %s", lua_tostring(LS,-1));
+
+ // Return the same error message
+ return -1;
+}
+
+#endif
+
+int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_) {
+ int consumed_bytes = tvb_captured_length(tvb);
+ tvbuff_t *saved_lua_tvb = lua_tvb;
+ packet_info *saved_lua_pinfo = lua_pinfo;
+ struct _wslua_treeitem *saved_lua_tree = lua_tree;
+ lua_pinfo = pinfo;
+ lua_tvb = tvb;
+
+ /*
+ * almost equivalent to Lua:
+ * dissectors[current_proto](tvb,pinfo,tree)
+ */
+
+ // set the stack top be index 0
+ lua_settop(L,0);
+
+ // After call, stack: [ error_handler_func ]
+ lua_pushcfunction(L, dissector_error_handler);
+
+ // Push the dissectors table onto the the stack
+ // After call, stack: [ error_handler_func, dissectors_table ]
+ lua_rawgeti(L, LUA_REGISTRYINDEX, lua_dissectors_table_ref);
+
+ // Push a copy of the current_proto string onto the stack
+ // After call, stack: [ error_handler_func, dissectors_table, current_proto ]
+ lua_pushstring(L, pinfo->current_proto);
+
+ // dissectors_table[current_proto], a dissector, goes into the stack
+ // The key (current_proto) is popped off the stack.
+ // After call, stack: [ error_handler_func, dissectors_table, dissector ]
+ lua_gettable(L, -2);
+
+ // We don't need the dissectors_table in the stack
+ // After call, stack: [ error_handler_func, dissector ]
+ lua_remove(L,2);
+
+ // Is the dissector a function?
+ if (lua_isfunction(L,2)) {
+
+ // After call, stack: [ error_handler_func, dissector, tvb ]
+ push_Tvb(L,tvb);
+ // After call, stack: [ error_handler_func, dissector, tvb, pinfo ]
+ push_Pinfo(L,pinfo);
+ // After call, stack: [ error_handler_func, dissector, tvb, pinfo, TreeItem ]
+ lua_tree = push_TreeItem(L, tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
+ proto_item_set_hidden(lua_tree->item);
+
+ if ( lua_pcall(L, /*num_args=*/3, /*num_results=*/1, /*error_handler_func_stack_position=*/1) ) {
+ // do nothing; the traceback error message handler function does everything
+ } else {
+
+ /* if the Lua dissector reported the consumed bytes, pass it to our caller */
+ if (lua_isnumber(L, -1)) {
+ /* we got the consumed bytes or the missing bytes as a negative number */
+ consumed_bytes = wslua_togint(L, -1);
+ lua_pop(L, 1);
+ }
+ }
+
+ } else {
+ proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,
+ "Lua Error: did not find the %s dissector in the dissectors table", pinfo->current_proto);
+ }
+
+ wmem_register_callback(pinfo->pool, lua_pinfo_end, NULL);
+
+ lua_pinfo = saved_lua_pinfo;
+ lua_tree = saved_lua_tree;
+ lua_tvb = saved_lua_tvb;
+
+ return consumed_bytes;
+
+}
+
+/** Type of a heuristic dissector, used in heur_dissector_add().
+ *
+ * @param tvb the tvbuff with the (remaining) packet data
+ * @param pinfo the packet info of this packet (additional info)
+ * @param tree the protocol tree to be build or NULL
+ * @return TRUE if the packet was recognized by the sub-dissector (stop dissection here)
+ */
+gboolean heur_dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_) {
+ gboolean result = FALSE;
+ tvbuff_t *saved_lua_tvb = lua_tvb;
+ packet_info *saved_lua_pinfo = lua_pinfo;
+ struct _wslua_treeitem *saved_lua_tree = lua_tree;
+ lua_tvb = tvb;
+ lua_pinfo = pinfo;
+
+ ws_assert(tvb && pinfo);
+
+ if (!pinfo->heur_list_name || !pinfo->current_proto) {
+ proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,
+ "internal error in heur_dissect_lua: NULL list name or current proto");
+ return FALSE;
+ }
+
+ /* heuristic functions are stored in a table in the registry; the registry has a
+ * table at reference lua_heur_dissectors_table_ref, and that table has keys for
+ * the heuristic listname (e.g., "udp", "tcp", etc.), and that key's value is a
+ * table of keys of the Proto->name, and their value is the function.
+ * So it's like registry[table_ref][heur_list_name][proto_name] = func
+ */
+
+ lua_settop(L,0);
+
+ /* get the table of all lua heuristic dissector lists */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, lua_heur_dissectors_table_ref);
+
+ /* get the table inside that, for the lua heuristic dissectors of the requested heur list */
+ if (!wslua_get_table(L, -1, pinfo->heur_list_name)) {
+ /* this shouldn't happen */
+ lua_settop(L,0);
+ proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,
+ "internal error in heur_dissect_lua: no %s heur list table", pinfo->heur_list_name);
+ return FALSE;
+ }
+
+ /* get the table inside that, for the specific lua heuristic dissector */
+ if (!wslua_get_field(L,-1,pinfo->current_proto)) {
+ /* this shouldn't happen */
+ lua_settop(L,0);
+ proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,
+ "internal error in heur_dissect_lua: no %s heuristic dissector for list %s",
+ pinfo->current_proto, pinfo->heur_list_name);
+ return FALSE;
+ }
+
+ /* remove the table of all lists (the one in the registry) */
+ lua_remove(L,1);
+ /* remove the heur_list_name heur list table */
+ lua_remove(L,1);
+
+ if (!lua_isfunction(L,-1)) {
+ /* this shouldn't happen */
+ lua_settop(L,0);
+ proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,
+ "internal error in heur_dissect_lua: %s heuristic dissector is not a function", pinfo->current_proto);
+ return FALSE;
+ }
+
+ push_Tvb(L,tvb);
+ push_Pinfo(L,pinfo);
+ lua_tree = push_TreeItem(L, tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
+ proto_item_set_hidden(lua_tree->item);
+
+ if ( lua_pcall(L,3,1,0) ) {
+ proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,
+ "Lua Error: error calling %s heuristic dissector: %s", pinfo->current_proto, lua_tostring(L,-1));
+ lua_settop(L,0);
+ } else {
+ if (lua_isboolean(L, -1) || lua_isnil(L, -1)) {
+ result = lua_toboolean(L, -1);
+ } else if (lua_type(L, -1) == LUA_TNUMBER) {
+ result = lua_tointeger(L,-1) != 0 ? TRUE : FALSE;
+ } else {
+ proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,
+ "Lua Error: invalid return value from Lua %s heuristic dissector", pinfo->current_proto);
+ }
+ lua_pop(L, 1);
+ }
+
+ wmem_register_callback(pinfo->pool, lua_pinfo_end, NULL);
+
+ lua_pinfo = saved_lua_pinfo;
+ lua_tree = saved_lua_tree;
+ lua_tvb = saved_lua_tvb;
+
+ return result;
+}
+
+static void iter_table_and_call(lua_State* LS, const gchar* table_name, lua_CFunction error_handler) {
+ lua_settop(LS,0);
+
+ lua_pushcfunction(LS,error_handler);
+ lua_getglobal(LS, table_name);
+
+ if (!lua_istable(LS, 2)) {
+ report_failure("Lua: either `%s' does not exist or it is not a table!\n",table_name);
+ lua_close(LS);
+ L = NULL;
+ return;
+ }
+
+ lua_pushnil(LS);
+
+ while (lua_next(LS, 2)) {
+ const gchar* name = lua_tostring(L,-2);
+
+ if (lua_isfunction(LS,-1)) {
+
+ if ( lua_pcall(LS,0,0,1) ) {
+ lua_pop(LS,1);
+ }
+
+ } else {
+ report_failure("Lua: Something not a function got its way into the %s.%s",table_name,name);
+ lua_close(LS);
+ L = NULL;
+ return;
+ }
+ }
+
+ lua_settop(LS,0);
+}
+
+
+static int init_error_handler(lua_State* LS) {
+ const gchar* error = lua_tostring(LS,1);
+ report_failure("Lua: Error during execution of initialization:\n %s",error);
+ return 0;
+}
+
+
+static gboolean init_routine_initialized = FALSE;
+static void wslua_init_routine(void) {
+
+ if ( ! init_routine_initialized ) {
+ /*
+ * This must be done only once during the entire life of
+ * tshark/wireshark, because it must be done only once per the life of
+ * the Lua state/engine, so we guard this with the boolean above;
+ * otherwise it would occur every time a file is opened (every time
+ * epan_new() is called).
+ *
+ * If we ever allow the Lua state to be restarted, or to have multiple
+ * Lua states, we'll need to change this.
+ */
+ lua_prime_all_fields(NULL);
+ init_routine_initialized = TRUE;
+ }
+
+ if (L) {
+ iter_table_and_call(L, WSLUA_INIT_ROUTINES,init_error_handler);
+ }
+
+}
+
+static void wslua_cleanup_routine(void) {
+ if (L) {
+ iter_table_and_call(L, WSLUA_INIT_ROUTINES,init_error_handler);
+ }
+}
+
+static int prefs_changed_error_handler(lua_State* LS) {
+ const gchar* error = lua_tostring(LS,1);
+ report_failure("Lua: Error during execution of prefs apply callback:\n %s",error);
+ return 0;
+}
+
+void wslua_prefs_changed(void) {
+ if (L) {
+ iter_table_and_call(L, WSLUA_PREFS_CHANGED,prefs_changed_error_handler);
+ }
+}
+
+static const char *getF(lua_State *LS _U_, void *ud, size_t *size)
+{
+ FILE *f=(FILE *)ud;
+ static char buff[512];
+ if (feof(f)) return NULL;
+ *size=fread(buff,1,sizeof(buff),f);
+ return (*size>0) ? buff : NULL;
+}
+
+static int error_handler_with_callback(lua_State *LS) {
+#if LUA_VERSION_NUM >= 502
+ const char *msg = lua_tostring(LS, 1);
+ luaL_traceback(LS, LS, msg, 1); /* push message with traceback. */
+ lua_remove(LS, -2); /* remove original msg */
+#else
+ /* Return error message, unmodified */
+ (void)LS;
+#endif
+ return 1;
+}
+
+static void wslua_add_plugin(const gchar *name, const gchar *version, const gchar *filename)
+{
+ wslua_plugin *new_plug, *lua_plug;
+
+ lua_plug = wslua_plugin_list;
+ new_plug = g_new(wslua_plugin, 1);
+
+ if (!lua_plug) { /* the list is empty */
+ wslua_plugin_list = new_plug;
+ } else {
+ while (lua_plug->next != NULL) {
+ lua_plug = lua_plug->next;
+ }
+ lua_plug->next = new_plug;
+ }
+
+ new_plug->name = g_strdup(name);
+ new_plug->version = g_strdup(version);
+ new_plug->filename = g_strdup(filename);
+ new_plug->next = NULL;
+}
+
+static void wslua_clear_plugin_list(void)
+{
+ wslua_plugin *lua_plug;
+
+ while (wslua_plugin_list) {
+ lua_plug = wslua_plugin_list;
+ wslua_plugin_list = wslua_plugin_list->next;
+ g_free (lua_plug->name);
+ g_free (lua_plug->version);
+ g_free (lua_plug->filename);
+ g_free (lua_plug);
+ }
+}
+
+static int lua_script_push_args(const int script_num) {
+ gchar* argname = ws_strdup_printf("lua_script%d", script_num);
+ const gchar* argvalue = NULL;
+ int i, count = ex_opt_count(argname);
+
+ for (i = 0; i < count; i++) {
+ argvalue = ex_opt_get_nth(argname, i);
+ lua_pushstring(L,argvalue);
+ }
+
+ g_free(argname);
+ return count;
+}
+
+#define FILE_NAME_KEY "__FILE__"
+#define DIR_NAME_KEY "__DIR__"
+#define DIR_SEP_NAME_KEY "__DIR_SEPARATOR__"
+/* assumes a loaded chunk's function is on top of stack */
+static void set_file_environment(const gchar* filename, const gchar* dirname) {
+ const char* path;
+
+ lua_newtable(L); /* environment for script (index 3) */
+
+ lua_pushstring(L, filename); /* tell the script about its filename */
+ lua_setfield(L, -2, FILE_NAME_KEY); /* make it accessible at __FILE__ */
+
+ lua_pushstring(L, dirname); /* tell the script about its dirname */
+ lua_setfield(L, -2, DIR_NAME_KEY); /* make it accessible at __DIR__ */
+
+ lua_pushstring(L, G_DIR_SEPARATOR_S); /* tell the script the directory separator */
+ lua_setfield(L, -2, DIR_SEP_NAME_KEY); /* make it accessible at __DIR__ */
+
+ lua_newtable(L); /* new metatable */
+
+#if LUA_VERSION_NUM >= 502
+ lua_pushglobaltable(L);
+#else
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+#endif
+ /* prepend the directory name to _G.package.path */
+ lua_getfield(L, -1, "package"); /* get the package table from the global table */
+ lua_getfield(L, -1, "path"); /* get the path field from the package table */
+ path = luaL_checkstring(L, -1); /* get the path string */
+ lua_pop(L, 1); /* pop the path string */
+ /* prepend the various paths */
+ lua_pushfstring(L, "%s" G_DIR_SEPARATOR_S "?.lua;%s" G_DIR_SEPARATOR_S "?.lua;%s" G_DIR_SEPARATOR_S "?.lua;%s",
+ dirname, get_plugins_pers_dir(), get_plugins_dir(), path);
+ lua_setfield(L, -2, "path"); /* set the new string to be the path field of the package table */
+ lua_setfield(L, -2, "package"); /* set the package table to be the package field of the global */
+
+ lua_setfield(L, -2, "__index"); /* make metatable's __index point to global table */
+
+ lua_setmetatable(L, -2); /* pop metatable, set it as metatable of environment */
+
+#if LUA_VERSION_NUM >= 502
+ lua_setupvalue(L, -2, 1); /* pop environment and assign it to upvalue 1 */
+#else
+ lua_setfenv(L, -2); /* pop environment and set it as the func's environment */
+#endif
+}
+
+
+/* If file_count > 0 then it's a command-line-added user script, and the count
+ * represents which user script it is (first=1, second=2, etc.).
+ * If dirname != NULL, then it's a user script and the dirname will get put in a file environment
+ * If dirname == NULL then it's a wireshark script and no file environment is created
+ */
+static gboolean lua_load_script(const gchar* filename, const gchar* dirname, const int file_count) {
+ FILE* file;
+ int error;
+ int numargs = 0;
+
+ if (! ( file = ws_fopen(filename,"r")) ) {
+ report_open_failure(filename,errno,FALSE);
+ return FALSE;
+ }
+
+ lua_settop(L,0);
+
+ lua_pushcfunction(L, error_handler_with_callback);
+ /* The source argument should start with '@' to indicate a file. */
+ lua_pushfstring(L, "@%s", filename);
+
+#if LUA_VERSION_NUM >= 502
+ error = lua_load(L, getF, file, lua_tostring(L, -1), NULL);
+#else
+ error = lua_load(L, getF, file, lua_tostring(L, -1));
+#endif
+
+ switch (error) {
+ case 0: /* LUA_OK */
+ if (dirname) {
+ set_file_environment(filename, dirname);
+ }
+ if (file_count > 0) {
+ numargs = lua_script_push_args(file_count);
+ }
+ error = lua_pcall(L, numargs, 0, 1);
+ if (error) {
+ switch (error) {
+ case LUA_ERRRUN:
+ report_failure("Lua: Error during loading:\n%s", lua_tostring(L, -1));
+ break;
+ case LUA_ERRMEM:
+ report_failure("Lua: Error during loading: out of memory");
+ break;
+ case LUA_ERRERR:
+ report_failure("Lua: Error during loading: error while retrieving error message");
+ break;
+ default:
+ report_failure("Lua: Error during loading: unknown error %d", error);
+ break;
+ }
+ }
+ break;
+
+ case LUA_ERRSYNTAX:
+ report_failure("Lua: syntax error: %s", lua_tostring(L, -1));
+ break;
+
+ case LUA_ERRMEM:
+ report_failure("Lua: memory allocation error during precompilation of %s", filename);
+ break;
+
+ default:
+ report_failure("Lua: unknown error during precompilation of %s: %d", filename, error);
+ break;
+ }
+ fclose(file);
+ lua_pop(L, 2); /* pop the filename and error handler */
+ return error == 0;
+}
+
+/* This one is used to load the init.lua scripts, or anything else
+ * that shouldn't really be considered a real plugin.
+ */
+static gboolean lua_load_internal_script(const gchar* filename) {
+ return lua_load_script(filename, NULL, 0);
+}
+
+/* This one is used to load plugins: either from the plugin directories,
+ * or from the command line.
+ */
+static gboolean lua_load_plugin_script(const gchar* name,
+ const gchar* filename,
+ const gchar* dirname,
+ const int file_count)
+{
+ ws_debug("Loading lua script: %s", filename);
+ if (lua_load_script(filename, dirname, file_count)) {
+ wslua_add_plugin(name, get_current_plugin_version(), filename);
+ clear_current_plugin_version();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int wslua_panic(lua_State* LS) {
+ ws_error("LUA PANIC: %s",lua_tostring(LS,-1));
+ /** ws_error() does an abort() and thus never returns **/
+ return 0; /* keep gcc happy */
+}
+
+static gint string_compare(gconstpointer a, gconstpointer b) {
+ return strcmp((const char*)a, (const char*)b);
+}
+
+static int lua_load_plugins(const char *dirname, register_cb cb, gpointer client_data,
+ gboolean count_only, const gboolean is_user, GHashTable *loaded_files,
+ int depth)
+{
+ WS_DIR *dir; /* scanned directory */
+ WS_DIRENT *file; /* current file */
+ gchar *filename, *dot;
+ const gchar *name;
+ int plugins_counter = 0;
+ GList *sorted_dirnames = NULL;
+ GList *sorted_filenames = NULL;
+ GList *l = NULL;
+
+ if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL) {
+ while ((file = ws_dir_read_name(dir)) != NULL) {
+ name = ws_dir_get_name(file);
+
+ if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+ /* skip "." and ".." */
+ continue;
+ }
+ if (depth == 0 && strcmp(name, "init.lua") == 0) {
+ /* If we are in the root directory skip the special "init.lua"
+ * file that was already loaded before every other user script.
+ * (If we are below the root script directory we just treat it like any other
+ * lua script.) */
+ continue;
+ }
+
+ filename = ws_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname, name);
+ if (test_for_directory(filename) == EISDIR) {
+ sorted_dirnames = g_list_prepend(sorted_dirnames, (gpointer)filename);
+ continue;
+ }
+
+ /* skip files starting wih . */
+ if (name[0] == '.') {
+ g_free(filename);
+ continue;
+ }
+
+ /* skip anything but files with .lua suffix */
+ dot = strrchr(name, '.');
+ if (dot == NULL || g_ascii_strcasecmp(dot+1, "lua") != 0) {
+ g_free(filename);
+ continue;
+ }
+
+ if (file_exists(filename)) {
+ sorted_filenames = g_list_prepend(sorted_filenames, (gpointer)filename);
+ }
+ else {
+ g_free(filename);
+ }
+ }
+ ws_dir_close(dir);
+ }
+
+ /* Depth first; ie, process subdirectories (in ASCIIbetical order) before files */
+ if (sorted_dirnames != NULL) {
+ sorted_dirnames = g_list_sort(sorted_dirnames, string_compare);
+ for (l = sorted_dirnames; l != NULL; l = l->next) {
+ plugins_counter += lua_load_plugins((const char *)l->data, cb, client_data, count_only, is_user, loaded_files, depth + 1);
+ }
+ g_list_free_full(sorted_dirnames, g_free);
+ }
+
+ /* Process files in ASCIIbetical order */
+ if (sorted_filenames != NULL) {
+ sorted_filenames = g_list_sort(sorted_filenames, string_compare);
+ for (l = sorted_filenames; l != NULL; l = l->next) {
+ filename = (gchar *)l->data;
+ name = strrchr(filename, G_DIR_SEPARATOR) + 1;
+
+ /* Check if we have already loaded this file name, if provided with a set */
+ if (loaded_files && g_hash_table_lookup_extended(loaded_files, name, NULL, NULL)) {
+ continue;
+ }
+
+ if (!count_only) {
+ if (cb)
+ (*cb)(RA_LUA_PLUGINS, name, client_data);
+ lua_load_plugin_script(name, filename, is_user ? dirname : NULL, 0);
+
+ if (loaded_files) {
+ g_hash_table_insert(loaded_files, g_strdup(name), NULL);
+ }
+ }
+ plugins_counter++;
+ }
+ g_list_free_full(sorted_filenames, g_free);
+ }
+
+ return plugins_counter;
+}
+
+static int lua_load_global_plugins(register_cb cb, gpointer client_data,
+ gboolean count_only)
+{
+ return lua_load_plugins(get_plugins_dir(), cb, client_data, count_only, FALSE, NULL, 0);
+}
+
+static int lua_load_pers_plugins(register_cb cb, gpointer client_data,
+ gboolean count_only)
+{
+ int plugins_counter = 0;
+
+ /* aux table (set) to make sure we only load each file once (by name) */
+ GHashTable *loaded_user_scripts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+
+ /* load user scripts */
+ plugins_counter += lua_load_plugins(get_plugins_pers_dir(), cb, client_data, count_only, TRUE, loaded_user_scripts, 0);
+
+ /* for backward compatibility check old plugin directory */
+ char *old_path = get_persconffile_path("plugins", FALSE);
+ if (strcmp(get_plugins_pers_dir(), old_path) != 0) {
+ plugins_counter += lua_load_plugins(old_path, cb, client_data, count_only, TRUE, loaded_user_scripts, 0);
+ }
+ g_free(old_path);
+
+ g_hash_table_destroy(loaded_user_scripts);
+
+ return plugins_counter;
+}
+
+int wslua_count_plugins(void) {
+ int plugins_counter;
+
+ /* count global scripts */
+ plugins_counter = lua_load_global_plugins(NULL, NULL, TRUE);
+
+ /* count user scripts */
+ plugins_counter += lua_load_pers_plugins(NULL, NULL, TRUE);
+
+ /* count scripts from command line */
+ plugins_counter += ex_opt_count("lua_script");
+
+ return plugins_counter;
+}
+
+void wslua_plugins_get_descriptions(wslua_plugin_description_callback callback, void *user_data) {
+ wslua_plugin *lua_plug;
+
+ for (lua_plug = wslua_plugin_list; lua_plug != NULL; lua_plug = lua_plug->next)
+ {
+ callback(lua_plug->name, lua_plug->version, wslua_plugin_type_name(),
+ lua_plug->filename, user_data);
+ }
+}
+
+static void
+print_wslua_plugin_description(const char *name, const char *version,
+ const char *description, const char *filename,
+ void *user_data _U_)
+{
+ printf("%s\t%s\t%s\t%s\n", name, version, description, filename);
+}
+
+void
+wslua_plugins_dump_all(void)
+{
+ wslua_plugins_get_descriptions(print_wslua_plugin_description, NULL);
+}
+
+const char *wslua_plugin_type_name(void) {
+ return "lua script";
+}
+
+static ei_register_info* ws_lua_ei = NULL;
+static int ws_lua_ei_len = 0;
+
+expert_field*
+wslua_get_expert_field(const int group, const int severity)
+{
+ int i;
+ const ei_register_info *ei = ws_lua_ei;
+
+ ws_assert(ei);
+
+ for (i=0; i < ws_lua_ei_len; i++, ei++) {
+ if (ei->eiinfo.group == group && ei->eiinfo.severity == severity)
+ return ei->ids;
+ }
+
+ return &ei_lua_error;
+}
+
+static void *
+wslua_allocf(void *ud _U_, void *ptr, size_t osize _U_, size_t nsize)
+{
+ /* g_realloc frees ptr if nsize==0 and returns NULL (as desired).
+ * Furthermore it simplifies error handling by aborting on OOM */
+ return g_realloc(ptr, nsize);
+}
+
+#define WSLUA_EPAN_ENUMS_TABLE "_EPAN"
+#define WSLUA_WTAP_ENUMS_TABLE "_WTAP"
+
+#define WSLUA_BASE_TABLE "base"
+#define WSLUA_FTYPE_TABLE "ftypes"
+#define WSLUA_FRAMETYPE_TABLE "frametype"
+#define WSLUA_EXPERT_TABLE "expert"
+#define WSLUA_EXPERT_GROUP_TABLE "group"
+#define WSLUA_EXPERT_SEVERITY_TABLE "severity"
+#define WSLUA_WTAP_ENCAPS_TABLE "wtap_encaps"
+#define WSLUA_WTAP_TSPREC_TABLE "wtap_tsprecs"
+#define WSLUA_WTAP_COMMENTS_TABLE "wtap_comments"
+#define WSLUA_WTAP_RECTYPES_TABLE "wtap_rec_types"
+#define WSLUA_WTAP_PRESENCE_FLAGS_TABLE "wtap_presence_flags"
+
+static void
+add_table_symbol(const char *table, const char *name, int value)
+{
+ /* Get table from the global environment. */
+ lua_getglobal(L, table);
+ /* Set symbol in table. */
+ lua_pushstring(L, name);
+ lua_pushnumber(L, value);
+ lua_settable(L, -3);
+ /* Pop table from stack. */
+ lua_pop(L, 1);
+}
+
+static void
+add_global_symbol(const char *name, int value)
+{
+ /* Set symbol in global environment. */
+ lua_pushnumber(L, value);
+ lua_setglobal(L, name);
+}
+
+static void
+add_pi_severity_symbol(const char *name, int value)
+{
+ lua_getglobal(L, WSLUA_EXPERT_TABLE);
+ lua_getfield(L, -1, WSLUA_EXPERT_SEVERITY_TABLE);
+ lua_pushnumber(L, value);
+ lua_setfield(L, -2, name);
+ lua_pop(L, 2);
+}
+
+static void
+add_pi_group_symbol(const char *name, int value)
+{
+ lua_getglobal(L, WSLUA_EXPERT_TABLE);
+ lua_getfield(L, -1, WSLUA_EXPERT_GROUP_TABLE);
+ lua_pushnumber(L, value);
+ lua_setfield(L, -2, name);
+ lua_pop(L, 2);
+}
+
+static void
+add_menu_group_symbol(const char *name, int value)
+{
+ /* Set symbol in global environment. */
+ lua_pushnumber(L, value);
+ char *str = g_strdup(name);
+ char *s = strstr(str, "_GROUP_");
+ if (s == NULL)
+ return;
+ *s = '\0';
+ s += strlen("_GROUP_");
+ char *str2 = ws_strdup_printf("MENU_%s_%s", str, s);
+ lua_setglobal(L, str2);
+ g_free(str);
+ g_free(str2);
+}
+
+/*
+ * Read introspection constants and add them according to the historical
+ * (sometimes arbitrary) rules of make-init-lua.py. For efficiency reasons
+ * we only loop the enums array once.
+ */
+static void
+wslua_add_introspection(void)
+{
+ const ws_enum_t *ep;
+
+ /* Add empty tables to be populated. */
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_BASE_TABLE);
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_FTYPE_TABLE);
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_FRAMETYPE_TABLE);
+ lua_newtable(L);
+ lua_pushstring(L, WSLUA_EXPERT_GROUP_TABLE);
+ lua_newtable(L);
+ lua_settable(L, -3);
+ lua_pushstring(L, WSLUA_EXPERT_SEVERITY_TABLE);
+ lua_newtable(L);
+ lua_settable(L, -3);
+ lua_setglobal(L, WSLUA_EXPERT_TABLE);
+ /* Add catch-all _EPAN table. */
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_EPAN_ENUMS_TABLE);
+
+ for (ep = epan_inspect_enums(); ep->symbol != NULL; ep++) {
+
+ if (g_str_has_prefix(ep->symbol, "BASE_")) {
+ add_table_symbol(WSLUA_BASE_TABLE, ep->symbol + strlen("BASE_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "SEP_")) {
+ add_table_symbol(WSLUA_BASE_TABLE, ep->symbol + strlen("SEP_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "ABSOLUTE_TIME_")) {
+ add_table_symbol(WSLUA_BASE_TABLE, ep->symbol + strlen("ABSOLUTE_TIME_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "ENC_")) {
+ add_global_symbol(ep->symbol, ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "FT_FRAMENUM_")) {
+ add_table_symbol(WSLUA_FRAMETYPE_TABLE, ep->symbol + strlen("FT_FRAMENUM_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "FT_")) {
+ add_table_symbol(WSLUA_FTYPE_TABLE, ep->symbol + strlen("FT_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "PI_")) {
+ if (ep->value & PI_SEVERITY_MASK) {
+ add_pi_severity_symbol(ep->symbol + strlen("PI_"), ep->value);
+ }
+ else {
+ add_pi_group_symbol(ep->symbol + strlen("PI_"), ep->value);
+ }
+ /* For backward compatibility. */
+ add_global_symbol(ep->symbol, ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "REGISTER_")) {
+ add_menu_group_symbol(ep->symbol + strlen("REGISTER_"), ep->value);
+ }
+ add_table_symbol(WSLUA_EPAN_ENUMS_TABLE, ep->symbol, ep->value);
+ }
+
+ /* Add empty tables to be populated. */
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_WTAP_ENCAPS_TABLE);
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_WTAP_TSPREC_TABLE);
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_WTAP_COMMENTS_TABLE);
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_WTAP_RECTYPES_TABLE);
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_WTAP_PRESENCE_FLAGS_TABLE);
+ /* Add catch-all _WTAP table. */
+ lua_newtable(L);
+ lua_setglobal(L, WSLUA_WTAP_ENUMS_TABLE);
+
+ for (ep = wtap_inspect_enums(); ep->symbol != NULL; ep++) {
+
+ if (g_str_has_prefix(ep->symbol, "WTAP_ENCAP_")) {
+ add_table_symbol(WSLUA_WTAP_ENCAPS_TABLE, ep->symbol + strlen("WTAP_ENCAP_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "WTAP_TSPREC_")) {
+ add_table_symbol(WSLUA_WTAP_TSPREC_TABLE, ep->symbol + strlen("WTAP_TSPREC_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "WTAP_COMMENT_")) {
+ add_table_symbol(WSLUA_WTAP_COMMENTS_TABLE, ep->symbol + strlen("WTAP_COMMENT_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "REC_TYPE_")) {
+ add_table_symbol(WSLUA_WTAP_RECTYPES_TABLE, ep->symbol + strlen("REC_TYPE_"), ep->value);
+ }
+ else if (g_str_has_prefix(ep->symbol, "WTAP_HAS_")) {
+ add_table_symbol(WSLUA_WTAP_PRESENCE_FLAGS_TABLE, ep->symbol + strlen("WTAP_HAS_"), ep->value);
+ }
+ add_table_symbol(WSLUA_WTAP_ENUMS_TABLE, ep->symbol, ep->value);
+ }
+}
+
+static void wslua_add_deprecated(void)
+{
+ /* For backward compatibility. */
+ lua_getglobal(L, "wtap_encaps");
+ lua_setglobal(L, "wtap");
+
+ /*
+ * Generate the wtap_filetypes items for file types, for backwards
+ * compatibility.
+ * We no longer have WTAP_FILE_TYPE_SUBTYPE_ #defines;
+ * built-in file types are registered the same way that
+ * plugin file types are registered.
+ *
+ * New code should use wtap_name_to_file_type_subtype to
+ * look up file types by name.
+ */
+ wslua_init_wtap_filetypes(L);
+
+ /* Old / deprecated menu groups. These shoudn't be used in new code. */
+ lua_getglobal(L, "MENU_PACKET_ANALYZE_UNSORTED");
+ lua_setglobal(L, "MENU_ANALYZE_UNSORTED");
+ lua_getglobal(L, "MENU_ANALYZE_CONVERSATION_FILTER");
+ lua_setglobal(L, "MENU_ANALYZE_CONVERSATION");
+ lua_getglobal(L, "MENU_STAT_CONVERSATION_LIST");
+ lua_setglobal(L, "MENU_STAT_CONVERSATION");
+ lua_getglobal(L, "MENU_STAT_ENDPOINT_LIST");
+ lua_setglobal(L, "MENU_STAT_ENDPOINT");
+ lua_getglobal(L, "MENU_STAT_RESPONSE_TIME");
+ lua_setglobal(L, "MENU_STAT_RESPONSE");
+ lua_getglobal(L, "MENU_PACKET_STAT_UNSORTED");
+ lua_setglobal(L, "MENU_STAT_UNSORTED");
+
+ /* deprecated function names */
+ lua_getglobal(L, "Dir");
+ lua_getfield(L, -1, "global_config_path");
+ lua_setglobal(L, "datafile_path");
+ lua_getfield(L, -1, "personal_config_path");
+ lua_setglobal(L, "persconffile_path");
+ lua_pop(L, 1);
+}
+
+static int wslua_console_print(lua_State *_L);
+
+static const char *lua_error_msg(int code)
+{
+ switch (code) {
+ case LUA_ERRSYNTAX: return "syntax error during precompilation";
+ case LUA_ERRMEM: return "memory allocation error";
+#if LUA_VERSION_NUM == 502
+ case LUA_ERRGCMM: return "error while running a __gc metamethod";
+#endif
+ case LUA_ERRRUN: return "runtime error";
+ case LUA_ERRERR: return "error while running the message handler";
+ default: break; /* Should not happen. */
+ }
+ return "unknown error";
+}
+
+#if LUA_VERSION_NUM == 501
+#define LUA_OK 0
+#endif
+
+static int lua_funnel_console_eval(const char *console_input,
+ char **error_ptr,
+ char **error_hint,
+ void *callback_data _U_)
+{
+ int lcode;
+
+ const int curr_top = lua_gettop(L);
+
+ // If it starts with an equals sign replace it with "return"
+ char *codestr;
+ while (g_ascii_isspace(*console_input))
+ console_input++;
+ if (*console_input == '=')
+ codestr = ws_strdup_printf("return %s", console_input+1);
+ else
+ codestr = (char *)console_input; /* Violate const safety to avoid a strdup() */
+
+ ws_noisy("Console input: %s", codestr);
+ lcode = luaL_loadstring(L, codestr);
+ /* Free only if we called strdup(). */
+ if (codestr != console_input)
+ g_free(codestr);
+ codestr = NULL;
+
+ if (lcode != LUA_OK) {
+ ws_debug("luaL_loadstring(): %s (%d)", lua_error_msg(lcode), lcode);
+ if (error_hint) {
+ *error_hint = g_strdup(lua_error_msg(lcode));
+ }
+ /* If we have an error message return it. */
+ if (error_ptr && !lua_isnil(L, -1)) {
+ *error_ptr = g_strdup(lua_tostring(L, -1));
+ }
+ return -1;
+ }
+
+ lcode = lua_pcall(L, 0, LUA_MULTRET, 0);
+ if (lcode != LUA_OK) {
+ ws_debug("lua_pcall(): %s (%d)", lua_error_msg(lcode), lcode);
+ if (error_hint) {
+ *error_hint = g_strdup(lua_error_msg(lcode));
+ }
+ /* If we have an error message return it. */
+ if (error_ptr && !lua_isnil(L, -1)) {
+ *error_ptr = g_strdup(lua_tostring(L, -1));
+ }
+ return 1;
+ }
+
+ // If we have values returned print them all
+ if (lua_gettop(L) > curr_top) { /* any arguments? */
+ lua_pushcfunction(L, wslua_console_print);
+ lua_insert(L, curr_top+1);
+ lcode = lua_pcall(L, lua_gettop(L)-curr_top-1, 0, 0);
+ if (lcode != LUA_OK) {
+ /* Error printing result */
+ if (error_hint)
+ *error_hint = ws_strdup_printf("error printing return values: %s", lua_error_msg(lcode));
+ return 1;
+ }
+ }
+
+ // Maintain stack discipline
+ if (lua_gettop(L) != curr_top) {
+ ws_critical("Expected stack top == %d, have %d", curr_top, lua_gettop(L));
+ }
+
+ ws_noisy("Success");
+ return 0;
+}
+
+#if LUA_VERSION_NUM == 501
+static const char *luaL_tolstring (lua_State *_L, int idx, size_t *len) {
+ if (!luaL_callmeta(_L, idx, "__tostring")) { /* no metafield? */
+ switch (lua_type(_L, idx)) {
+ case LUA_TNUMBER:
+ case LUA_TSTRING:
+ lua_pushvalue(_L, idx);
+ break;
+ case LUA_TBOOLEAN:
+ lua_pushstring(_L, (lua_toboolean(_L, idx) ? "true" : "false"));
+ break;
+ case LUA_TNIL:
+ lua_pushliteral(_L, "nil");
+ break;
+ default:
+ lua_pushfstring(_L, "%s: %p", luaL_typename(_L, idx),
+ lua_topointer(_L, idx));
+ break;
+ }
+ }
+ return lua_tolstring(_L, -1, len);
+}
+#endif /* LUA_VERSION_NUM == 501 */
+
+/* Receives C print function pointer as first upvalue. */
+/* Receives C print function data pointer as second upvalue. */
+static int wslua_console_print(lua_State *_L)
+{
+ GString *gstr = g_string_new(NULL);
+ const char *repr;
+
+ /* Print arguments. */
+ for (int i = 1; i <= lua_gettop(_L); i++) {
+ repr = luaL_tolstring(_L, i, NULL);
+ if (i > 1)
+ g_string_append_c(gstr, '\t');
+ g_string_append(gstr, repr);
+ lua_pop(_L, 1);
+ }
+ g_string_append_c(gstr, '\n');
+
+ if (wslua_gui_print_func_ptr == NULL) {
+ ws_critical("GUI print function not registered; Trying to print: %s", gstr->str);
+ }
+ else {
+ wslua_gui_print_func_ptr(gstr->str, wslua_gui_print_data_ptr);
+ }
+ g_string_free(gstr, TRUE);
+ return 0;
+}
+
+// Replace lua print function with a custom print function.
+// We will place the original function in the Lua registry and return the reference.
+static void lua_funnel_console_open(void (*print_func_ptr)(const char *, void *),
+ void *print_data_ptr,
+ void *callback_data _U_)
+{
+ /* Store original print value in the registry (even if it is nil). */
+ lua_getglobal(L, "print");
+ wslua_lua_print_func_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ /* Set new "print" function (to output to the GUI) */
+ lua_pushcfunction(L, wslua_console_print);
+ lua_setglobal(L, "print");
+
+ /* Save the globals */
+ ws_assert(print_func_ptr);
+ wslua_gui_print_func_ptr = print_func_ptr;
+ wslua_gui_print_data_ptr = print_data_ptr;
+}
+
+// Restore original Lua print function. Clean state.
+static void lua_funnel_console_close(void *callback_data _U_)
+{
+ /* Restore the original print function. */
+ int ref = (int)wslua_lua_print_func_ref;
+ /* push original function into stack */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
+ lua_setglobal(L, "print");
+ /* Release reference */
+ luaL_unref(L, LUA_REGISTRYINDEX, ref);
+
+ /* Clear the globals. */
+ wslua_gui_print_func_ptr = NULL;
+ wslua_gui_print_data_ptr = NULL;
+ wslua_lua_print_func_ref = LUA_NOREF;
+}
+
+static int wslua_file_exists(lua_State *_L)
+{
+ const char *path = luaL_checkstring(_L, 1);
+ lua_pushboolean(_L, g_file_test(path, G_FILE_TEST_EXISTS));
+ return 1;
+}
+
+static int wslua_lua_typeof(lua_State *_L)
+{
+ const char *classname = wslua_typeof(_L, 1);
+ lua_pushstring(_L, classname);
+ return 1;
+}
+
+/* Other useful constants */
+void wslua_add_useful_constants(void)
+{
+ const funnel_ops_t *ops = funnel_get_funnel_ops();
+ char *path;
+
+ WSLUA_REG_GLOBAL_BOOL(L,"GUI_ENABLED",ops && ops->new_dialog);
+
+ /* DATA_DIR has a trailing directory separator. */
+ path = get_datafile_path("");
+ lua_pushfstring(L, "%s"G_DIR_SEPARATOR_S, path);
+ g_free(path);
+ lua_setglobal(L, "DATA_DIR");
+
+ /* USER_DIR has a trailing directory separator. */
+ path = get_persconffile_path("", FALSE);
+ lua_pushfstring(L, "%s"G_DIR_SEPARATOR_S, path);
+ g_free(path);
+ lua_setglobal(L, "USER_DIR");
+
+ lua_pushcfunction(L, wslua_file_exists);
+ lua_setglobal(L, "file_exists");
+
+ lua_pushcfunction(L, wslua_lua_typeof);
+ lua_setglobal(L, "typeof");
+}
+
+void wslua_init(register_cb cb, gpointer client_data) {
+ gchar* filename;
+ gboolean enable_lua = TRUE;
+ gboolean run_anyway = FALSE;
+ expert_module_t* expert_lua;
+ int file_count = 1;
+ static gboolean first_time = TRUE;
+ int i;
+
+ static hf_register_info hf[] = {
+ { &hf_wslua_fake,
+ { "Wireshark Lua fake item", "_ws.lua.fake",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ "Fake internal item for Wireshark Lua", HFILL }},
+ { &hf_wslua_text,
+ { "Wireshark Lua text", "_ws.lua.text",
+ FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ };
+ static gint *ett[] = {
+ &ett_wslua_traceback,
+ };
+
+ static ei_register_info ei[] = {
+ /* the following are created so we can continue to support the TreeItem_add_expert_info()
+ function to Lua scripts. That function doesn't know what registered protocol to use,
+ so it uses the "_ws.lua" one. */
+ /* XXX: it seems to me we should not be offering PI_GROUP_MASK nor PI_SEVERITY_MASK since
+ they are not real settings, so I'm not adding them below (should they also not be exported
+ into Lua? they are right now.) */
+ /* NOTE: do not add expert entries at the top of this array - only at the bottom. This array
+ is not only used by expert.c, but also by wslua_get_expert_field() to find the appropriate
+ "dummy" entry. So this array's ordering matters. */
+ { &ei_lua_proto_checksum_comment, { "_ws.lua.proto.comment", PI_CHECKSUM, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_checksum_chat, { "_ws.lua.proto.chat", PI_CHECKSUM, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_checksum_note, { "_ws.lua.proto.note", PI_CHECKSUM, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_checksum_warn, { "_ws.lua.proto.warning", PI_CHECKSUM, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_checksum_error, { "_ws.lua.proto.error", PI_CHECKSUM, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_sequence_comment, { "_ws.lua.proto.comment", PI_SEQUENCE, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_sequence_chat, { "_ws.lua.proto.chat", PI_SEQUENCE, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_sequence_note, { "_ws.lua.proto.note", PI_SEQUENCE, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_sequence_warn, { "_ws.lua.proto.warning", PI_SEQUENCE, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_sequence_error, { "_ws.lua.proto.error", PI_SEQUENCE, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_response_comment, { "_ws.lua.proto.comment", PI_RESPONSE_CODE, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_response_chat, { "_ws.lua.proto.chat", PI_RESPONSE_CODE, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_response_note, { "_ws.lua.proto.note", PI_RESPONSE_CODE, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_response_warn, { "_ws.lua.proto.warning", PI_RESPONSE_CODE, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_response_error, { "_ws.lua.proto.error", PI_RESPONSE_CODE, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_request_comment, { "_ws.lua.proto.comment", PI_REQUEST_CODE, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_request_chat, { "_ws.lua.proto.chat", PI_REQUEST_CODE, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_request_note, { "_ws.lua.proto.note", PI_REQUEST_CODE, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_request_warn, { "_ws.lua.proto.warning", PI_REQUEST_CODE, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_request_error, { "_ws.lua.proto.error", PI_REQUEST_CODE, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_undecoded_comment, { "_ws.lua.proto.comment", PI_UNDECODED, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_undecoded_chat, { "_ws.lua.proto.chat", PI_UNDECODED, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_undecoded_note, { "_ws.lua.proto.note", PI_UNDECODED, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_undecoded_warn, { "_ws.lua.proto.warning", PI_UNDECODED, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_undecoded_error, { "_ws.lua.proto.error", PI_UNDECODED, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_reassemble_comment, { "_ws.lua.proto.comment", PI_REASSEMBLE, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_reassemble_chat, { "_ws.lua.proto.chat", PI_REASSEMBLE, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_reassemble_note, { "_ws.lua.proto.note", PI_REASSEMBLE, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_reassemble_warn, { "_ws.lua.proto.warning", PI_REASSEMBLE, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_reassemble_error, { "_ws.lua.proto.error", PI_REASSEMBLE, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_malformed_comment, { "_ws.lua.proto.comment", PI_MALFORMED, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_malformed_chat, { "_ws.lua.proto.chat", PI_MALFORMED, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_malformed_note, { "_ws.lua.proto.note", PI_MALFORMED, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_malformed_warn, { "_ws.lua.proto.warning", PI_MALFORMED, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_malformed_error, { "_ws.lua.proto.error", PI_MALFORMED, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_debug_comment, { "_ws.lua.proto.comment", PI_DEBUG, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_debug_chat, { "_ws.lua.proto.chat", PI_DEBUG, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_debug_note, { "_ws.lua.proto.note", PI_DEBUG, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_debug_warn, { "_ws.lua.proto.warning", PI_DEBUG, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_debug_error, { "_ws.lua.proto.error", PI_DEBUG, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_protocol_comment, { "_ws.lua.proto.comment", PI_PROTOCOL, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_protocol_chat, { "_ws.lua.proto.chat", PI_PROTOCOL, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_protocol_note, { "_ws.lua.proto.note", PI_PROTOCOL, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_protocol_warn, { "_ws.lua.proto.warning", PI_PROTOCOL, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_protocol_error, { "_ws.lua.proto.error", PI_PROTOCOL, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_security_comment, { "_ws.lua.proto.comment", PI_SECURITY, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_security_chat, { "_ws.lua.proto.chat", PI_SECURITY, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_security_note, { "_ws.lua.proto.note", PI_SECURITY, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_security_warn, { "_ws.lua.proto.warning", PI_SECURITY, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_security_error, { "_ws.lua.proto.error", PI_SECURITY, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_comments_comment, { "_ws.lua.proto.comment", PI_COMMENTS_GROUP, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_comments_chat, { "_ws.lua.proto.chat", PI_COMMENTS_GROUP, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_comments_note, { "_ws.lua.proto.note", PI_COMMENTS_GROUP, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_comments_warn, { "_ws.lua.proto.warning", PI_COMMENTS_GROUP, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_comments_error, { "_ws.lua.proto.error", PI_COMMENTS_GROUP, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_decryption_comment, { "_ws.lua.proto.comment", PI_DECRYPTION, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_decryption_chat, { "_ws.lua.proto.chat", PI_DECRYPTION, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_decryption_note, { "_ws.lua.proto.note", PI_DECRYPTION, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_decryption_warn, { "_ws.lua.proto.warning", PI_DECRYPTION, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_decryption_error, { "_ws.lua.proto.error", PI_DECRYPTION, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_assumption_comment, { "_ws.lua.proto.comment", PI_ASSUMPTION, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_assumption_chat, { "_ws.lua.proto.chat", PI_ASSUMPTION, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_assumption_note, { "_ws.lua.proto.note", PI_ASSUMPTION, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_assumption_warn, { "_ws.lua.proto.warning", PI_ASSUMPTION, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_assumption_error, { "_ws.lua.proto.error", PI_ASSUMPTION, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ { &ei_lua_proto_deprecated_comment, { "_ws.lua.proto.comment", PI_DEPRECATED, PI_COMMENT ,"Protocol Comment", EXPFILL }},
+ { &ei_lua_proto_deprecated_chat, { "_ws.lua.proto.chat", PI_DEPRECATED, PI_CHAT ,"Protocol Chat", EXPFILL }},
+ { &ei_lua_proto_deprecated_note, { "_ws.lua.proto.note", PI_DEPRECATED, PI_NOTE ,"Protocol Note", EXPFILL }},
+ { &ei_lua_proto_deprecated_warn, { "_ws.lua.proto.warning", PI_DEPRECATED, PI_WARN ,"Protocol Warning", EXPFILL }},
+ { &ei_lua_proto_deprecated_error, { "_ws.lua.proto.error", PI_DEPRECATED, PI_ERROR ,"Protocol Error", EXPFILL }},
+
+ /* this one is for reporting errors executing Lua code */
+ { &ei_lua_error, { "_ws.lua.error", PI_UNDECODED, PI_ERROR ,"Lua Error", EXPFILL }},
+ };
+
+ if (first_time) {
+ ws_lua_ei = ei;
+ ws_lua_ei_len = array_length(ei);
+ }
+
+ if (!L) {
+ L = lua_newstate(wslua_allocf, NULL);
+ }
+
+ WSLUA_INIT(L);
+
+#if LUA_VERSION_NUM == 501
+ /* table.unpack was introduced with Lua 5.2, alias it to unpack. */
+ lua_getglobal(L, "table");
+ lua_getglobal(L, "unpack");
+ lua_setfield(L, -2, "unpack");
+ lua_pop(L, 1);
+#endif
+
+ if (first_time) {
+ proto_lua = proto_register_protocol("Lua Dissection", "Lua Dissection", "_ws.lua");
+ proto_register_field_array(proto_lua, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_lua = expert_register_protocol(proto_lua);
+ expert_register_field_array(expert_lua, ei, array_length(ei));
+ }
+
+ lua_atpanic(L,wslua_panic);
+
+ /*
+ * The init_routines table (accessible by the user).
+ *
+ * For a table a, a.init is syntactic sugar for a["init"], and
+ *
+ * function t.a.b.c.f () body end
+ *
+ * is syntactic sugar for
+ *
+ * t.a.b.c.f = function () body end
+ *
+ * so
+ *
+ * function proto.init () body end
+ *
+ * means
+ *
+ * proto["init"] = function () body end
+ *
+ * and the Proto class has an "init" method, with Proto_set_init()
+ * being the setter for that method; that routine adds the Lua
+ * function passed to it as a Lua argument to the WSLUA_INIT_ROUTINES
+ * table - i.e., "init_routines".
+ */
+ lua_newtable (L);
+ lua_setglobal(L, WSLUA_INIT_ROUTINES);
+
+ /* the dissectors table goes in the registry (not accessible) */
+ lua_newtable (L);
+ lua_dissectors_table_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+ lua_newtable (L);
+ lua_heur_dissectors_table_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ /* the preferences apply_cb table (accessible by the user) */
+ lua_newtable (L);
+ lua_setglobal(L, WSLUA_PREFS_CHANGED);
+
+ /* set running_superuser variable to its proper value */
+ WSLUA_REG_GLOBAL_BOOL(L,"running_superuser",started_with_special_privs());
+
+ /* special constant used by PDU reassembly handling */
+ /* see dissect_lua() for notes */
+ WSLUA_REG_GLOBAL_NUMBER(L,"DESEGMENT_ONE_MORE_SEGMENT",DESEGMENT_ONE_MORE_SEGMENT);
+
+ /* the possible values for Pinfo's p2p_dir attribute */
+ WSLUA_REG_GLOBAL_NUMBER(L,"P2P_DIR_UNKNOWN",-1);
+ WSLUA_REG_GLOBAL_NUMBER(L,"P2P_DIR_SENT",0);
+ WSLUA_REG_GLOBAL_NUMBER(L,"P2P_DIR_RECV",1);
+
+ wslua_add_introspection();
+
+ wslua_add_useful_constants();
+
+ wslua_add_deprecated();
+
+ // Register Lua's console menu (in the GUI)
+ if (first_time) {
+ funnel_register_console_menu("Lua",
+ lua_funnel_console_eval,
+ lua_funnel_console_open,
+ lua_funnel_console_close,
+ NULL, NULL);
+ }
+ else if (wslua_gui_print_func_ptr) {
+ // If we we have an open GUI console dialog re-register the global "print to console" function
+ lua_funnel_console_open(wslua_gui_print_func_ptr, wslua_gui_print_data_ptr, NULL);
+ }
+
+ /* load system's init.lua */
+ filename = g_build_filename(get_plugins_dir(), "init.lua", (char *)NULL);
+ if (file_exists(filename)) {
+ ws_debug("Loading init.lua file: %s", filename);
+ lua_load_internal_script(filename);
+ }
+ g_free(filename);
+
+ /* load user's init.lua */
+ /* if we are indeed superuser run user scripts only if told to do so */
+ if (!started_with_special_privs() || run_anyway) {
+ filename = g_build_filename(get_plugins_pers_dir(), "init.lua", (char *)NULL);
+ if (file_exists(filename)) {
+ ws_debug("Loading init.lua file: %s", filename);
+ lua_load_internal_script(filename);
+ }
+ g_free(filename);
+
+ /* For backward compatibility also load it from the configuration directory. */
+ filename = get_persconffile_path("init.lua", FALSE);
+ if (file_exists(filename)) {
+ ws_message("Loading init.lua file from deprecated path: %s", filename);
+ lua_load_internal_script(filename);
+ }
+ g_free(filename);
+ }
+
+ filename = NULL;
+
+ /* check if lua is to be disabled */
+ lua_getglobal(L, "disable_lua"); // 2.6 and earlier, deprecated
+ if (lua_isboolean(L,-1)) {
+ enable_lua = ! lua_toboolean(L,-1);
+ }
+ lua_pop(L,1); /* pop the getglobal result */
+
+ lua_getglobal(L, "enable_lua"); // 3.0 and later
+ if (lua_isboolean(L,-1)) {
+ enable_lua = lua_toboolean(L,-1);
+ }
+ lua_pop(L,1); /* pop the getglobal result */
+
+ if (!enable_lua) {
+ /* disable lua */
+ lua_close(L);
+ L = NULL;
+ first_time = FALSE;
+ return;
+ }
+
+ /* load global scripts */
+ lua_load_global_plugins(cb, client_data, FALSE);
+
+ /* check whether we should run other scripts even if running superuser */
+ lua_getglobal(L,"run_user_scripts_when_superuser");
+
+ if (lua_isboolean(L,-1) && lua_toboolean(L,-1)) {
+ run_anyway = TRUE;
+ }
+ lua_pop(L,1); /* pop the getglobal result */
+
+ /* if we are indeed superuser run user scripts only if told to do so */
+ if (!started_with_special_privs() || run_anyway) {
+
+ /* load user scripts */
+ lua_load_pers_plugins(cb, client_data, FALSE);
+
+ /* load scripts from command line */
+ for (i = 0; i < ex_opt_count("lua_script"); i++) {
+ const gchar *script_filename = ex_opt_get_nth("lua_script", i);
+ char* dirname = g_strdup(script_filename);
+ char* dname = get_dirname(dirname);
+
+ if (cb)
+ (*cb)(RA_LUA_PLUGINS, get_basename(script_filename), client_data);
+
+ lua_load_plugin_script(ws_dir_get_name(script_filename),
+ script_filename,
+ dname ? dname : "",
+ file_count);
+ file_count++;
+ g_free(dirname);
+ }
+ }
+
+ if (first_time) {
+ /* at this point we're set up so register the init and cleanup routines */
+ register_init_routine(wslua_init_routine);
+ register_cleanup_routine(wslua_cleanup_routine);
+ }
+
+ /*
+ * after this point it is too late to register a menu
+ * disable the function to avoid weirdness
+ */
+ lua_pushcfunction(L, wslua_not_register_menu);
+ lua_setglobal(L, "register_menu");
+
+ /* set up some essential globals */
+ lua_pinfo = NULL;
+ lua_tree = NULL;
+ lua_tvb = NULL;
+
+ Proto_commit(L);
+
+ first_time = FALSE;
+}
+
+void wslua_early_cleanup(void) {
+ wslua_deregister_protocols(L);
+}
+
+void wslua_reload_plugins (register_cb cb, gpointer client_data) {
+ const funnel_ops_t* ops = funnel_get_funnel_ops();
+
+ if (cb)
+ (*cb)(RA_LUA_DEREGISTER, NULL, client_data);
+
+ if (ops->close_dialogs)
+ ops->close_dialogs();
+
+ wslua_deregister_heur_dissectors(L);
+ wslua_deregister_protocols(L);
+ wslua_deregister_dissector_tables(L);
+ wslua_deregister_listeners(L);
+ wslua_deregister_fields(L);
+ wslua_deregister_filehandlers(L);
+ wslua_deregister_menus();
+ wslua_clear_plugin_list();
+
+ wslua_cleanup();
+ wslua_init(cb, client_data); /* reinitialize */
+}
+
+void wslua_cleanup(void) {
+ /* cleanup lua */
+ if (L) {
+ lua_close(L);
+ L = NULL;
+ }
+ init_routine_initialized = FALSE;
+}
+
+lua_State* wslua_state(void) { return L; }
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */