/* tap-exportobject.c * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "tap-exportobject.h" /* XXX - This is effectively a copy of eo_save_entry with the "GUI alerts" * removed to accomodate tshark */ static gboolean local_eo_save_entry(const gchar *save_as_filename, export_object_entry_t *entry) { int to_fd; gint64 bytes_left; int bytes_to_write; ssize_t bytes_written; guint8 *ptr; to_fd = ws_open(save_as_filename, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0644); if(to_fd == -1) { /* An error occurred */ return FALSE; } /* * The third argument to _write() on Windows is an unsigned int, * so, on Windows, that's the size of the third argument to * ws_write(). * * The third argument to write() on UN*X is a size_t, although * the return value is an ssize_t, so one probably shouldn't * write more than the max value of an ssize_t. * * In either case, there's no guarantee that a gint64 such as * payload_len can be passed to ws_write(), so we write in * chunks of, at most 2^31 bytes. */ ptr = entry->payload_data; bytes_left = entry->payload_len; while (bytes_left != 0) { if (bytes_left > 0x40000000) bytes_to_write = 0x40000000; else bytes_to_write = (int)bytes_left; bytes_written = ws_write(to_fd, ptr, bytes_to_write); if(bytes_written <= 0) { ws_close(to_fd); return FALSE; } bytes_left -= bytes_written; ptr += bytes_written; } if (ws_close(to_fd) < 0) { return FALSE; } return TRUE; } typedef struct _export_object_list_gui_t { GSList *entries; register_eo_t* eo; } export_object_list_gui_t; static GHashTable* eo_opts = NULL; static gboolean list_exportobject_protocol(const void *key, void *value _U_, void *userdata _U_) { fprintf(stderr, " %s\n", (const gchar*)key); return FALSE; } void eo_list_object_types(void) { eo_iterate_tables(list_exportobject_protocol, NULL); } gboolean eo_tap_opt_add(const char *option_string) { gchar** splitted; if (!eo_opts) eo_opts = g_hash_table_new(g_str_hash,g_str_equal); splitted = g_strsplit(option_string, ",", 2); if ((splitted[0] == NULL) || (splitted[1] == NULL) || (get_eo_by_name(splitted[0]) == NULL)) { fprintf(stderr, "tshark: \"--export-objects\" are specified as: ,\n"); fprintf(stderr, "tshark: The available export object types for the \"--export-objects\" option are:\n"); eo_list_object_types(); } else { gchar* dir = (gchar*)g_hash_table_lookup(eo_opts, splitted[0]); /* Since we're saving all objects from a protocol, it can only be listed once */ if (dir == NULL) { g_hash_table_insert(eo_opts, splitted[0], splitted[1]); g_free(splitted); return TRUE; } else { cmdarg_err("\"--export-objects\" already specified protocol '%s'", splitted[0]); } } g_strfreev(splitted); return FALSE; } static void object_list_add_entry(void *gui_data, export_object_entry_t *entry) { export_object_list_gui_t *object_list = (export_object_list_gui_t*)gui_data; object_list->entries = g_slist_append(object_list->entries, entry); } static export_object_entry_t* object_list_get_entry(void *gui_data, int row) { export_object_list_gui_t *object_list = (export_object_list_gui_t*)gui_data; return (export_object_entry_t *)g_slist_nth_data(object_list->entries, row); } /* This is just for writing Exported Objects to a file */ static void eo_draw(void *tapdata) { export_object_list_t *tap_object = (export_object_list_t *)tapdata; export_object_list_gui_t *object_list = (export_object_list_gui_t*)tap_object->gui_data; GSList *slist = object_list->entries; export_object_entry_t *entry; gboolean all_saved = TRUE; gchar* save_in_path = (gchar*)g_hash_table_lookup(eo_opts, proto_get_protocol_filter_name(get_eo_proto_id(object_list->eo))); GString *safe_filename = NULL; gchar *save_as_fullpath = NULL; int count = 0; if (!g_file_test(save_in_path, G_FILE_TEST_IS_DIR)) { /* If the destination directory (or its parents) do not exist, create them. */ if (g_mkdir_with_parents(save_in_path, 0755) == -1) { fprintf(stderr, "Failed to create export objects output directory \"%s\": %s\n", save_in_path, g_strerror(errno)); return; } } if ((strlen(save_in_path) < EXPORT_OBJECT_MAXFILELEN)) { while (slist) { entry = (export_object_entry_t *)slist->data; do { g_free(save_as_fullpath); if (entry->filename) { safe_filename = eo_massage_str(entry->filename, EXPORT_OBJECT_MAXFILELEN - strlen(save_in_path), count); } else { char generic_name[EXPORT_OBJECT_MAXFILELEN+1]; const char *ext; ext = eo_ct2ext(entry->content_type); g_snprintf(generic_name, sizeof(generic_name), "object%u%s%s", entry->pkt_num, ext ? "." : "", ext ? ext : ""); safe_filename = eo_massage_str(generic_name, EXPORT_OBJECT_MAXFILELEN - strlen(save_in_path), count); } save_as_fullpath = g_build_filename(save_in_path, safe_filename->str, NULL); g_string_free(safe_filename, TRUE); } while (g_file_test(save_as_fullpath, G_FILE_TEST_EXISTS) && ++count < 1000); count = 0; if (!local_eo_save_entry(save_as_fullpath, entry)) all_saved = FALSE; g_free(save_as_fullpath); save_as_fullpath = NULL; slist = slist->next; } } else { all_saved = FALSE; } if (!all_saved) fprintf(stderr, "Export objects (%s): Some files could not be saved.\n", proto_get_protocol_filter_name(get_eo_proto_id(object_list->eo))); } static void exportobject_handler(gpointer key, gpointer value _U_, gpointer user_data _U_) { GString *error_msg; export_object_list_t *tap_data; export_object_list_gui_t *object_list; register_eo_t* eo; eo = get_eo_by_name((const char*)key); if (eo == NULL) { cmdarg_err("\"--export-objects\" INTERNAL ERROR '%s' protocol not found", (const char*)key); return; } tap_data = g_new0(export_object_list_t,1); object_list = g_new0(export_object_list_gui_t,1); tap_data->add_entry = object_list_add_entry; tap_data->get_entry = object_list_get_entry; tap_data->gui_data = (void*)object_list; object_list->eo = eo; /* Data will be gathered via a tap callback */ error_msg = register_tap_listener(get_eo_tap_listener_name(eo), tap_data, NULL, 0, NULL, get_eo_packet_func(eo), eo_draw, NULL); if (error_msg) { cmdarg_err("Can't register %s tap: %s", (const char*)key, error_msg->str); g_string_free(error_msg, TRUE); g_free(tap_data); g_free(object_list); return; } } void start_exportobjects(void) { if (eo_opts != NULL) g_hash_table_foreach(eo_opts, exportobject_handler, NULL); } /* * 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: */