TODO netlogon_user_flags_ntlmv2_enabled
[wireshark-sm.git] / epan / wslua / wslua_utility.c
blob67cf8e4cca1f1647dd5f12860af9ebbc8d560efc
1 /*
2 * wslua_utility.c
4 * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "config.h"
14 #define WS_LOG_DOMAIN LOG_DOMAIN_WSLUA
16 /* WSLUA_MODULE Utility Utility Functions */
18 #include "wslua.h"
19 #include <math.h>
20 #include <epan/stat_tap_ui.h>
21 #include <epan/prefs.h>
22 #include <epan/prefs-int.h>
25 WSLUA_FUNCTION wslua_get_version(lua_State* L) { /* Gets the Wireshark version as a string. */
26 const char* str = VERSION;
27 lua_pushstring(L,str);
28 WSLUA_RETURN(1); /* The version string, e.g. "3.2.5". */
32 static char* current_plugin_version = NULL;
34 const char* get_current_plugin_version(void) {
35 return current_plugin_version ? current_plugin_version : "";
38 void clear_current_plugin_version(void) {
39 if (current_plugin_version != NULL) {
40 g_free(current_plugin_version);
41 current_plugin_version = NULL;
45 WSLUA_FUNCTION wslua_set_plugin_info(lua_State* L) {
47 Set a Lua table with meta-data about the plugin, such as version.
49 The passed-in Lua table entries need to be keyed/indexed by the following:
51 * "version" with a string value identifying the plugin version (required)
52 * "description" with a string value describing the plugin (optional)
53 * "author" with a string value of the author's name(s) (optional)
54 * "repository" with a string value of a URL to a repository (optional)
56 Not all of the above key entries need to be in the table. The 'version'
57 entry is required, however. The others are not currently used for anything, but
58 might be in the future and thus using them might be useful. Table entries keyed
59 by other strings are ignored, and do not cause an error.
61 ===== Example
63 [source,lua]
64 ----
65 local my_info = {
66 version = "1.0.1",
67 author = "Jane Doe",
68 repository = "https://github.com/octocat/Spoon-Knife"
71 set_plugin_info(my_info)
72 ----
74 #define WSLUA_ARG_set_plugin_info_TABLE 1 /* The Lua table of information. */
76 if ( lua_istable(L,WSLUA_ARG_set_plugin_info_TABLE) ) {
77 int top;
78 lua_getfield(L, WSLUA_ARG_set_plugin_info_TABLE, "version");
79 top = lua_gettop(L);
80 if (lua_isstring(L, top)) {
81 clear_current_plugin_version();
82 current_plugin_version = g_strdup( luaL_checkstring(L, top) );
83 /* pop the string */
84 lua_pop(L, 1);
86 else {
87 return luaL_error(L,"the Lua table must have a 'version' key entry with a string value");
89 } else {
90 return luaL_error(L,"a Lua table with at least a 'version' string entry");
93 return 0;
97 WSLUA_FUNCTION wslua_format_date(lua_State* LS) { /* Formats an absolute timestamp into a human readable date. */
98 #define WSLUA_ARG_format_date_TIMESTAMP 1 /* A timestamp value to convert. */
99 lua_Number timestamp = luaL_checknumber(LS,WSLUA_ARG_format_date_TIMESTAMP);
100 nstime_t then;
101 char* str;
103 then.secs = (time_t)(floor(timestamp));
104 then.nsecs = (uint32_t) ( (timestamp-(double)(then.secs))*1000000000);
105 str = abs_time_to_str(NULL, &then, ABSOLUTE_TIME_LOCAL, true);
106 lua_pushstring(LS,str);
107 wmem_free(NULL, str);
109 WSLUA_RETURN(1); /* A string with the formated date */
112 WSLUA_FUNCTION wslua_format_time(lua_State* LS) { /* Formats a relative timestamp in a human readable time. */
113 #define WSLUA_ARG_format_time_TIMESTAMP 1 /* A timestamp value to convert. */
114 lua_Number timestamp = luaL_checknumber(LS,WSLUA_ARG_format_time_TIMESTAMP);
115 nstime_t then;
116 char* str;
118 then.secs = (time_t)(floor(timestamp));
119 then.nsecs = (uint32_t) ( (timestamp-(double)(then.secs))*1000000000);
120 str = rel_time_to_str(NULL, &then);
121 lua_pushstring(LS,str);
122 wmem_free(NULL, str);
124 WSLUA_RETURN(1); /* A string with the formated time */
127 WSLUA_FUNCTION wslua_get_preference(lua_State *L) {
128 /* Get a preference value. */
129 #define WSLUA_ARG_get_preference_PREFERENCE 1 /* The name of the preference. */
130 const char* preference = luaL_checkstring(L,WSLUA_ARG_get_preference_PREFERENCE);
132 /* Split preference from module.preference */
133 char *module_name = g_strdup(preference);
134 char *preference_name = strchr(module_name, '.');
135 pref_t *pref = NULL;
137 if (preference_name) {
138 *preference_name = '\0';
139 preference_name++;
141 module_t *module = prefs_find_module(module_name);
142 pref = prefs_find_preference(module, preference_name);
144 g_free (module_name);
146 if (pref) {
147 switch (prefs_get_type(pref)) {
148 case PREF_UINT:
150 unsigned uint_value = prefs_get_uint_value(pref, pref_current);
151 lua_pushinteger(L, uint_value);
152 break;
154 case PREF_BOOL:
156 bool bool_value = prefs_get_bool_value(pref, pref_current);
157 lua_pushboolean(L, bool_value);
158 break;
160 case PREF_ENUM:
162 const enum_val_t *enums;
163 int enum_value = prefs_get_enum_value(pref, pref_current);
165 for (enums = prefs_get_enumvals(pref); enums->name; enums++) {
166 if (enums->value == enum_value) {
167 lua_pushstring(L,enums->name);
168 break;
172 if (!enums || !enums->name) {
173 /* Enum preference has an unknown value. */
174 lua_pushstring(L,"");
176 break;
178 case PREF_STRING:
179 case PREF_SAVE_FILENAME:
180 case PREF_OPEN_FILENAME:
181 case PREF_DIRNAME:
182 case PREF_DISSECTOR:
184 const char *string_value = prefs_get_string_value(pref, pref_current);
185 lua_pushstring(L,string_value);
186 break;
188 case PREF_RANGE:
190 char *range_value = range_convert_range(NULL, prefs_get_range_value_real(pref, pref_current));
191 lua_pushstring(L,range_value);
192 wmem_free(NULL, range_value);
193 break;
195 default:
196 /* Get not supported for this type. */
197 return luaL_error(L, "preference type %d is not supported.", prefs_get_type(pref));
199 } else {
200 /* No such preference. */
201 lua_pushnil(L);
204 WSLUA_RETURN(1); /* The preference value, or nil if not found. */
207 WSLUA_FUNCTION wslua_set_preference(lua_State *L) {
208 /* Set a preference value. */
209 #define WSLUA_ARG_set_preference_PREFERENCE 1 /* The name of the preference. */
210 #define WSLUA_ARG_set_preference_VALUE 2 /* The preference value to set. */
211 const char* preference = luaL_checkstring(L,WSLUA_ARG_set_preference_PREFERENCE);
213 /* Split preference from module.preference */
214 char *module_name = g_strdup(preference);
215 char *preference_name = strchr(module_name, '.');
216 module_t *module = NULL;
217 pref_t *pref = NULL;
219 if (preference_name) {
220 *preference_name = '\0';
221 preference_name++;
223 module = prefs_find_module(module_name);
224 pref = prefs_find_preference(module, preference_name);
226 g_free (module_name);
228 if (pref) {
229 unsigned int changed = 0;
230 switch (prefs_get_type(pref)) {
231 case PREF_UINT:
233 unsigned uint_value = (unsigned)luaL_checkinteger(L,WSLUA_ARG_set_preference_VALUE);
234 changed = prefs_set_uint_value(pref, uint_value, pref_current);
235 module->prefs_changed_flags |= changed;
236 lua_pushboolean(L, changed);
237 break;
239 case PREF_BOOL:
241 bool bool_value = wslua_checkboolean(L, WSLUA_ARG_set_preference_VALUE);
242 changed = prefs_set_bool_value(pref, bool_value, pref_current);
243 module->prefs_changed_flags |= changed;
244 lua_pushboolean(L, changed);
245 break;
247 case PREF_ENUM:
249 const char *enum_value = luaL_checkstring(L,WSLUA_ARG_set_preference_VALUE);
250 changed = prefs_set_enum_string_value(pref, enum_value, pref_current);
251 module->prefs_changed_flags |= changed;
252 lua_pushboolean(L, changed);
253 break;
255 case PREF_STRING:
256 case PREF_SAVE_FILENAME:
257 case PREF_OPEN_FILENAME:
258 case PREF_DIRNAME:
259 case PREF_DISSECTOR:
261 const char *string_value = luaL_checkstring(L,WSLUA_ARG_set_preference_VALUE);
262 changed = prefs_set_string_value(pref, string_value, pref_current);
263 module->prefs_changed_flags |= changed;
264 lua_pushboolean(L, changed);
265 break;
267 case PREF_RANGE:
269 const char *range_value = luaL_checkstring(L,WSLUA_ARG_set_preference_VALUE);
270 range_t *range = NULL;
271 convert_ret_t ret = range_convert_str(NULL, &range, range_value, prefs_get_max_value(pref));
272 if (ret == CVT_NUMBER_TOO_BIG) {
273 return luaL_error(L, "illegal range (number too big)");
274 } else if (ret != CVT_NO_ERROR) {
275 return luaL_error(L, "illegal range (syntax error)");
277 changed = prefs_set_range_value(pref, range, pref_current);
278 wmem_free(NULL, range);
279 module->prefs_changed_flags |= changed;
280 lua_pushboolean(L, changed);
281 break;
283 default:
284 /* Set not supported for this type. */
285 return luaL_error(L, "preference type %d is not supported.", prefs_get_type(pref));
287 } else {
288 /* No such preference. */
289 lua_pushnil(L);
292 WSLUA_RETURN(1); /* true if changed, false if unchanged or nil if not found. */
295 WSLUA_FUNCTION wslua_reset_preference(lua_State *L) {
296 /* Reset a preference to default value. */
297 #define WSLUA_ARG_reset_preference_PREFERENCE 1 /* The name of the preference. */
298 const char* preference = luaL_checkstring(L,WSLUA_ARG_reset_preference_PREFERENCE);
300 // Split preference from module.preference
301 char *module_name = g_strdup(preference);
302 char *preference_name = strchr(module_name, '.');
303 pref_t *pref = NULL;
305 if (preference_name) {
306 *preference_name = '\0';
307 preference_name++;
309 module_t *module = prefs_find_module(module_name);
310 pref = prefs_find_preference(module, preference_name);
313 if (pref) {
314 reset_pref(pref);
315 lua_pushboolean(L, true);
316 } else {
317 /* No such preference. */
318 lua_pushnil(L);
321 g_free(module_name);
322 WSLUA_RETURN(1); /* true if valid preference */
325 WSLUA_FUNCTION wslua_apply_preferences(lua_State *L) {
326 /* Write preferences to file and apply changes. */
327 char *pf_path = NULL;
328 int err = write_prefs(&pf_path);
330 if (err) {
331 /* Make a copy of pf_path because luaL_error() will return */
332 char pf_path_copy[256];
333 (void) g_strlcpy(pf_path_copy, pf_path, sizeof pf_path_copy);
334 g_free(pf_path);
336 return luaL_error(L, "can't open preferences file\n\"%s\": %s.",
337 pf_path_copy, g_strerror(err));
338 } else {
339 prefs_apply_all();
342 return 0;
345 WSLUA_FUNCTION wslua_report_failure(lua_State* LS) { /* Reports a failure to the user. */
346 #define WSLUA_ARG_report_failure_TEXT 1 /* Message text to report. */
347 const char* s = luaL_checkstring(LS,WSLUA_ARG_report_failure_TEXT);
348 report_failure("%s",s);
349 return 0;
352 /* The returned filename is g_malloc()'d so the caller must free it */
353 /* except when NULL is returned if file doesn't exist */
354 char* wslua_get_actual_filename(const char* fname) {
355 char fname_clean[256];
356 char* f;
357 char* filename;
359 (void) g_strlcpy(fname_clean,fname,255);
360 fname_clean[255] = '\0';
362 for(f = fname_clean; *f; f++) {
363 switch(*f) {
364 case '/': case '\\':
365 *f = *(G_DIR_SEPARATOR_S);
366 break;
367 default:
368 break;
372 if ( file_exists(fname_clean) ) {
373 return g_strdup(fname_clean);
376 filename = get_persconffile_path(fname_clean,false);
378 if ( file_exists(filename) ) {
379 return filename;
381 g_free(filename);
384 * Try to look in global data directory, nothing extraordinary for normal
385 * installations. For executions from the build dir, it will look for files
386 * copied to DATAFILE_DIR.
388 filename = get_datafile_path(fname_clean);
389 if ( file_exists(filename) ) {
390 return filename;
392 g_free(filename);
394 return NULL;
397 WSLUA_FUNCTION wslua_dofile(lua_State* L) {
399 Loads a Lua file and executes it as a Lua chunk, similar to the standard
400 https://www.lua.org/manual/5.4/manual.html#pdf-dofile[dofile]
401 but searches additional directories.
402 The search order is the current directory, followed by the user's
403 https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[personal configuration]
404 directory, and finally the
405 https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[global configuration]
406 directory.
408 [TIP]
409 .The configuration directories are not the plugin directories.
410 ====
411 The configuration directories searched are not the global and personal plugin
412 directories. All Lua files in the plugin directories are loaded at startup;
413 `dofile` is for loading files from additional locations.
414 The file path can be absolute or relative to one of the search directories.
415 ====
418 #define WSLUA_ARG_dofile_FILENAME 1 /* Name of the file to be run. If the file does not exist in the current directory, the user and system directories are searched. */
419 const char *given_fname = luaL_checkstring(L, WSLUA_ARG_dofile_FILENAME);
420 char* filename = wslua_get_actual_filename(given_fname);
421 int n;
423 if (!filename) {
424 WSLUA_ARG_ERROR(dofile,FILENAME,"file does not exist");
425 return 0;
428 n = lua_gettop(L);
429 if (luaL_loadfile(L, filename) != 0) lua_error(L);
430 g_free(filename);
431 lua_call(L, 0, LUA_MULTRET);
432 return lua_gettop(L) - n;
435 WSLUA_FUNCTION wslua_loadfile(lua_State* L) {
437 Loads a Lua file and compiles it into a Lua chunk, similar to the standard
438 https://www.lua.org/manual/5.4/manual.html#pdf-loadfile[loadfile]
439 but searches additional directories.
440 The search order is the current directory, followed by the user's
441 https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[personal configuration]
442 directory, and finally the
443 https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[global configuration]
444 directory.
446 ===== Example
448 [source,lua]
449 ----
450 -- Assume foo.lua contains definition for foo(a,b). Load the chunk
451 -- from the file and execute it to add foo(a,b) to the global table.
452 -- These two lines are effectively the same as dofile('foo.lua').
453 local loaded_chunk = assert(loadfile('foo.lua'))
454 loaded_chunk()
456 -- ok to call foo at this point
457 foo(1,2)
458 ----
460 #define WSLUA_ARG_loadfile_FILENAME 1 /* Name of the file to be loaded. If the file does not exist in the current directory, the user and system directories are searched. */
461 const char *given_fname = luaL_checkstring(L, WSLUA_ARG_loadfile_FILENAME);
462 char* filename;
464 filename = wslua_get_actual_filename(given_fname);
466 if (!filename) {
467 WSLUA_ARG_ERROR(loadfile,FILENAME,"file does not exist");
468 return 0;
471 if (luaL_loadfile(L, filename) == 0) {
472 g_free(filename);
473 return 1;
474 } else {
475 g_free(filename);
476 lua_pushnil(L);
477 lua_insert(L, -2);
478 return 2;
482 typedef struct _statcmd_t {
483 lua_State* L;
484 int func_ref;
485 } statcmd_t;
487 static int statcmd_init_cb_error_handler(lua_State* L _U_) {
488 return 0;
491 static void statcmd_init(const char *opt_arg, void* userdata) {
492 statcmd_t* sc = (statcmd_t *)userdata;
493 lua_State* L = sc->L;
495 lua_settop(L,0);
496 lua_pushcfunction(L,statcmd_init_cb_error_handler);
497 lua_rawgeti(L, LUA_REGISTRYINDEX, sc->func_ref);
499 lua_pushstring(L,opt_arg);
501 switch ( lua_pcall(L,1,0,1) ) {
502 case 0:
503 break;
504 case LUA_ERRRUN:
505 ws_warning("Runtime error while calling statcmd callback");
506 break;
507 case LUA_ERRMEM:
508 ws_warning("Memory alloc error while calling statcmd callback");
509 break;
510 case LUA_ERRERR:
511 ws_warning("Error while running the error handler function for statcmd callback");
512 break;
513 default:
514 ws_assert_not_reached();
515 break;
520 WSLUA_FUNCTION wslua_register_stat_cmd_arg(lua_State* L) {
521 /* Register a function to handle a `-z` option */
522 #define WSLUA_ARG_register_stat_cmd_arg_ARGUMENT 1 /* The name of the option argument. */
523 #define WSLUA_OPTARG_register_stat_cmd_arg_ACTION 2 /* The function to be called when the command is invoked. */
524 const char* arg = luaL_checkstring(L,WSLUA_ARG_register_stat_cmd_arg_ARGUMENT);
525 statcmd_t* sc = g_new0(statcmd_t, 1); /* XXX leaked */
526 stat_tap_ui ui_info;
528 sc->L = L;
529 lua_pushvalue(L, WSLUA_OPTARG_register_stat_cmd_arg_ACTION);
530 sc->func_ref = luaL_ref(L, LUA_REGISTRYINDEX);
531 lua_remove(L,1);
533 ui_info.group = REGISTER_PACKET_STAT_GROUP_UNSORTED; /* XXX - need an argument? */
534 ui_info.title = NULL;
535 ui_info.cli_string = arg;
536 ui_info.tap_init_cb = statcmd_init;
537 ui_info.nparams = 0;
538 ui_info.params = NULL;
539 register_stat_tap_ui(&ui_info, sc);
540 return 0;
544 * Editor modelines - https://www.wireshark.org/tools/modelines.html
546 * Local variables:
547 * c-basic-offset: 4
548 * tab-width: 8
549 * indent-tabs-mode: nil
550 * End:
552 * vi: set shiftwidth=4 tabstop=8 expandtab:
553 * :indentSize=4:tabSize=8:noTabs=true: