diff options
author | Simon Holesch <simon@holesch.de> | 2020-11-29 00:22:24 +0100 |
---|---|---|
committer | Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org> | 2020-12-01 10:54:45 +0000 |
commit | 6a0feb8d0a51fcb950591b1cfa0cb00cf83f3394 (patch) | |
tree | a1110c32f8f782336dc3de14fef5c5401ba9d55b /epan/dissectors/packet-dbus.c | |
parent | 2158ff241f4d7930bf626c5d52f55ddf93604ebf (diff) |
D-Bus: Dissect complete messages
Improve the D-Bus dissector to support all types, including containers
(arrays, structs, dict entries, variants). Add new protocol fields for
D-Bus header fields like `dbus.destination` or `dbus.path` to make
filtering for specific messages possible. Add lots of expert infos for
possible errors. Update Info column to include method / signal name and
path.
Diffstat (limited to 'epan/dissectors/packet-dbus.c')
-rw-r--r-- | epan/dissectors/packet-dbus.c | 1622 |
1 files changed, 1137 insertions, 485 deletions
diff --git a/epan/dissectors/packet-dbus.c b/epan/dissectors/packet-dbus.c index 4c6b1149c5..4fd951c90f 100644 --- a/epan/dissectors/packet-dbus.c +++ b/epan/dissectors/packet-dbus.c @@ -1,6 +1,7 @@ /* packet-dbus.c * Routines for D-Bus dissection * Copyright 2012, Jakub Zawadzki <darkjames-ws@darkjames.pl> + * Copyright 2020, Simon Holesch <simon@holesch.de> * * Protocol specification available at http://dbus.freedesktop.org/doc/dbus-specification.html * @@ -11,18 +12,44 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#define NEW_PROTO_TREE_API - #include "config.h" #include <epan/packet.h> #include <wiretap/wtap.h> #include <epan/expert.h> +#include <epan/ptvcursor.h> #include "packet-tcp.h" +#define DBUS_MAX_ARRAY_LEN (64 * 1024 * 1024) +#define DBUS_MAX_NAME_LENGTH 255 +#define DBUS_MAX_SIGNATURE_LENGTH 255 +#define DBUS_MAX_TYPE_NESTING_LEVEL 32 +#define DBUS_MAX_TOTAL_NESTING_LEVEL (2 * DBUS_MAX_TYPE_NESTING_LEVEL) + +#define SIG_CODE_BYTE ('y') +#define SIG_CODE_BOOLEAN ('b') +#define SIG_CODE_INT16 ('n') +#define SIG_CODE_UINT16 ('q') +#define SIG_CODE_INT32 ('i') +#define SIG_CODE_UINT32 ('u') +#define SIG_CODE_INT64 ('x') +#define SIG_CODE_UINT64 ('t') +#define SIG_CODE_DOUBLE ('d') +#define SIG_CODE_STRING ('s') +#define SIG_CODE_OBJECT_PATH ('o') +#define SIG_CODE_SIGNATURE ('g') +#define SIG_CODE_ARRAY ('a') +#define SIG_CODE_STRUCT_OPEN ('(') +#define SIG_CODE_STRUCT_CLOSE (')') +#define SIG_CODE_VARIANT ('v') +#define SIG_CODE_DICT_ENTRY_OPEN ('{') +#define SIG_CODE_DICT_ENTRY_CLOSE ('}') +#define SIG_CODE_UNIX_FD ('h') + void proto_register_dbus(void); void proto_reg_handoff_dbus(void); +static int proto_dbus = -1; static gboolean dbus_desegment = TRUE; static dissector_handle_t dbus_handle; @@ -55,550 +82,1080 @@ static const value_string message_type_vals[] = { #define DBUS_HEADER_FIELD_UNIX_FDS 9 static const value_string field_code_vals[] = { - { DBUS_HEADER_FIELD_INVALID, "INVALID" }, - { DBUS_HEADER_FIELD_PATH, "PATH" }, - { DBUS_HEADER_FIELD_INTERFACE, "INTERFACE" }, - { DBUS_HEADER_FIELD_MEMBER, "MEMBER" }, - { DBUS_HEADER_FIELD_ERROR_NAME, "ERROR_NAME" }, - { DBUS_HEADER_FIELD_REPLY_SERIAL, "REPLY_SERIAL" }, - { DBUS_HEADER_FIELD_DESTINATION, "DESTINATION" }, - { DBUS_HEADER_FIELD_SENDER, "SENDER" }, - { DBUS_HEADER_FIELD_SIGNATURE, "SIGNATURE" }, - { DBUS_HEADER_FIELD_UNIX_FDS, "UNIX_FDS" }, + { DBUS_HEADER_FIELD_INVALID, "Invalid" }, + { DBUS_HEADER_FIELD_PATH, "Path" }, + { DBUS_HEADER_FIELD_INTERFACE, "Interface" }, + { DBUS_HEADER_FIELD_MEMBER, "Member" }, + { DBUS_HEADER_FIELD_ERROR_NAME, "Error name" }, + { DBUS_HEADER_FIELD_REPLY_SERIAL, "Reply serial" }, + { DBUS_HEADER_FIELD_DESTINATION, "Destination" }, + { DBUS_HEADER_FIELD_SENDER, "Sender" }, + { DBUS_HEADER_FIELD_SIGNATURE, "Signature" }, + { DBUS_HEADER_FIELD_UNIX_FDS, "Unix FDs" }, { 0, NULL } }; -static header_field_info *hfi_dbus = NULL; - -#define DBUS_HFI_INIT HFI_INIT(proto_dbus) - -/* XXX, FT_NONE -> FT_BYTES? */ - -/* Header */ -static header_field_info hfi_dbus_hdr DBUS_HFI_INIT = - { "Header", "dbus.header", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }; +static const value_string endianness_vals[] = { + { 'l', "little-endian" }, + { 'B', "big-endian" }, + { 0, NULL } +}; +const true_false_string allow_vals = { "Allow", "Don't allow" }; +const true_false_string no_start_vals = { "Don't start", "Start" }; +const true_false_string not_expected_vals = { "Not expected", "Expected" }; + +static int hf_dbus_endianness = -1; +static int hf_dbus_message_type = -1; +static int hf_dbus_flags = -1; +static int hf_dbus_flags_no_reply_expected = -1; +static int hf_dbus_flags_no_auto_start = -1; +static int hf_dbus_flags_allow_interactive_authorization = -1; +static int hf_dbus_version = -1; +static int hf_dbus_body_length = -1; +static int hf_dbus_serial = -1; +static int hf_dbus_field_code = -1; +static int hf_dbus_padding = -1; +static int hf_dbus_path = -1; +static int hf_dbus_interface = -1; +static int hf_dbus_member = -1; +static int hf_dbus_error_name = -1; +static int hf_dbus_reply_serial = -1; +static int hf_dbus_destination = -1; +static int hf_dbus_sender = -1; +static int hf_dbus_signature = -1; +static int hf_dbus_unix_fds = -1; +static int hf_dbus_body = -1; +static int hf_dbus_type_byte = -1; +static int hf_dbus_type_boolean = -1; +static int hf_dbus_type_int16 = -1; +static int hf_dbus_type_uint16 = -1; +static int hf_dbus_type_int32 = -1; +static int hf_dbus_type_uint32 = -1; +static int hf_dbus_type_int64 = -1; +static int hf_dbus_type_uint64 = -1; +static int hf_dbus_type_double = -1; +static int hf_dbus_type_string = -1; +static int hf_dbus_type_object_path = -1; +static int hf_dbus_type_signature = -1; +static int hf_dbus_type_array = -1; +static int hf_dbus_type_array_length = -1; +static int hf_dbus_type_struct = -1; +static int hf_dbus_type_variant = -1; +static int hf_dbus_type_variant_signature = -1; +static int hf_dbus_type_dict_entry = -1; +static int hf_dbus_type_dict_entry_key = -1; +static int hf_dbus_type_unix_fd = -1; -static header_field_info hfi_dbus_hdr_endianness DBUS_HFI_INIT = - { "Endianness Flag", "dbus.endianness", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }; +static int ett_dbus = -1; +static int ett_dbus_flags = -1; +static int ett_dbus_header_field_array = -1; +static int ett_dbus_header_field = -1; +static int ett_dbus_body = -1; +static int ett_dbus_type_array = -1; +static int ett_dbus_type_struct = -1; +static int ett_dbus_type_variant = -1; +static int ett_dbus_type_dict_entry = -1; + +static expert_field ei_dbus_endianness_invalid = EI_INIT; +static expert_field ei_dbus_message_type_invalid = EI_INIT; +static expert_field ei_dbus_message_type_unknown = EI_INIT; +static expert_field ei_dbus_version_invalid = EI_INIT; +static expert_field ei_dbus_serial_invalid = EI_INIT; +static expert_field ei_dbus_field_code_invalid = EI_INIT; +static expert_field ei_dbus_required_header_field_missing = EI_INIT; +static expert_field ei_dbus_padding_invalid = EI_INIT; +static expert_field ei_dbus_field_signature_wrong = EI_INIT; +static expert_field ei_dbus_interface_invalid = EI_INIT; +static expert_field ei_dbus_member_invalid = EI_INIT; +static expert_field ei_dbus_error_name_invalid = EI_INIT; +static expert_field ei_dbus_bus_name_invalid = EI_INIT; +static expert_field ei_dbus_type_boolean_invalid = EI_INIT; +static expert_field ei_dbus_string_invalid = EI_INIT; +static expert_field ei_dbus_type_signature_invalid = EI_INIT; +static expert_field ei_dbus_type_array_too_long = EI_INIT; +static expert_field ei_dbus_type_array_content_out_of_bounds = EI_INIT; +static expert_field ei_dbus_type_object_path_invalid = EI_INIT; +static expert_field ei_dbus_type_variant_signature_invalid = EI_INIT; +static expert_field ei_dbus_nested_too_deeply = EI_INIT; -static header_field_info hfi_dbus_hdr_type DBUS_HFI_INIT = - { "Message Type", "dbus.type", FT_UINT8, BASE_DEC, VALS(message_type_vals), 0x00, NULL, HFILL }; +typedef struct { + ptvcursor_t *cursor; + packet_info *pinfo; + guint enc; + guint32 message_type; + guint32 body_len; + guint32 serial; + + proto_item *current_pi; + const char *path; + const char *interface; + const char *member; + const char *error_name; + guint32 reply_serial; + const char *destination; + const char *sender; + const char *signature; + guint32 unix_fds; +} dbus_packet_t; + +typedef struct _dbus_type_reader_t { + dbus_packet_t *packet; + const char *signature; + guint32 level; + guint32 array_level; + guint32 struct_level; + guint32 dict_entry_level; + const char *array_type_start; + int array_end_offset; + gboolean is_in_variant; + gboolean is_basic_variant; + gboolean is_in_dict_entry; + gboolean is_basic_dict_entry; + proto_item *container; + struct _dbus_type_reader_t *parent; +} dbus_type_reader_t; -static header_field_info hfi_dbus_hdr_flags DBUS_HFI_INIT = - { "Message Flags", "dbus.flags", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }; +typedef union { + gboolean bool_; + guint32 uint; + gint32 int_; + guint64 uint64; + gint64 int64; + double double_; + const char *string; +} dbus_val_t; -static header_field_info hfi_dbus_hdr_version DBUS_HFI_INIT = - { "Protocol Version", "dbus.version", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }; +static gboolean +is_ascii_digit(char c) { + return (guint)c - '0' < 10; +} -static header_field_info hfi_dbus_hdr_body_length DBUS_HFI_INIT = - { "Message body Length", "dbus.length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }; +static gboolean +is_ascii_alpha(char c) { + return ((guint)c | 0x20) - 'a' <= 'z' - 'a'; +} -static header_field_info hfi_dbus_hdr_serial DBUS_HFI_INIT = - { "Message Serial (cookie)", "dbus.serial", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }; +static gboolean +is_dbus_object_path_valid(const char *path) { + // - The path may be of any length. + // - The path must begin with an ASCII '/' (integer 47) character, and must consist of elements separated by + // slash characters. + // - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_" + // - No element may be the empty string. + // - Multiple '/' characters cannot occur in sequence. + // - A trailing '/' character is not allowed unless the path is the root path (a single '/' character). + if (*path == '/' && *(path + 1) == '\0') { + return TRUE; + } -static header_field_info hfi_dbus_hdr_fields_length DBUS_HFI_INIT = - { "Header fields Length", "dbus.fields_length", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }; + while (*path == '/') { + path++; -/* Header field */ -static header_field_info hfi_dbus_hdr_field DBUS_HFI_INIT = - { "Header Field", "dbus.field", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }; + if (*path == '/') { + return FALSE; + } -static header_field_info hfi_dbus_hdr_field_code DBUS_HFI_INIT = - { "Field code", "dbus.field.code", FT_UINT8, BASE_DEC, VALS(field_code_vals), 0x00, NULL, HFILL }; + while (is_ascii_alpha(*path) || is_ascii_digit(*path) || *path == '_') { + path++; + } -static header_field_info hfi_dbus_type_signature DBUS_HFI_INIT = - { "Type signature", "dbus.type_signature", FT_STRINGZ, BASE_NONE, NULL, 0x00, NULL, HFILL }; + if (*path == '\0') { + return *(path - 1) != '/'; + } + } -static header_field_info hfi_dbus_body DBUS_HFI_INIT = - { "Body", "dbus.body", FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }; + return FALSE; +} -/* Values */ -static header_field_info hfi_dbus_value_bool DBUS_HFI_INIT = - { "Value", "dbus.value.bool", FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }; +static gboolean +is_dbus_interface_valid(const char *interface) { + // - Interface names are composed of 2 or more elements separated by a period ('.') character. All elements + // must contain at least one character. + // - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_" and must not begin with a digit. + // - Interface names must not exceed the maximum name length. + gint elements = 0; + const char *p = interface; + do { + if (!(is_ascii_alpha(*p) || *p == '_')) { + return FALSE; + } + p++; + elements++; -static header_field_info hfi_dbus_value_int DBUS_HFI_INIT = - { "Value", "dbus.value.int", FT_INT32, BASE_DEC, NULL, 0x00, NULL, HFILL }; + while (is_ascii_alpha(*p) || is_ascii_digit(*p) || *p == '_') { + p++; + } -static header_field_info hfi_dbus_value_uint DBUS_HFI_INIT = - { "Value", "dbus.value.uint", FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }; + if (*p == '\0') { + size_t length = p - interface; + return elements >= 2 && length <= DBUS_MAX_NAME_LENGTH; + } + } while (*p++ == '.'); -static header_field_info hfi_dbus_value_str DBUS_HFI_INIT = - { "Value", "dbus.value.str", FT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }; + return FALSE; +} -static header_field_info hfi_dbus_value_double DBUS_HFI_INIT = - { "DOUBLE", "dbus.value.double", FT_DOUBLE, BASE_NONE, NULL, 0x00, NULL, HFILL }; +static gboolean +is_dbus_member_name_valid(const char *member_name) { + // - Must only contain the ASCII characters "[A-Z][a-z][0-9]_" and may not begin with a digit. + // - Must not contain the '.' (period) character. + // - Must not exceed the maximum name length. + // - Must be at least 1 byte in length. + const char *p = member_name; + + if (!(is_ascii_alpha(*p) || *p == '_')) { + return FALSE; + } + do { + p++; + } while (is_ascii_alpha(*p) || is_ascii_digit(*p) || *p == '_'); -static int ett_dbus = -1; -static int ett_dbus_hdr = -1; -static int ett_dbus_body = -1; -static int ett_dbus_field = -1; + if (*p == '\0') { + size_t length = p - member_name; + return length <= DBUS_MAX_NAME_LENGTH; + } -static expert_field ei_dbus_value_bool_invalid = EI_INIT; -static expert_field ei_dbus_value_str_invalid = EI_INIT; -static expert_field ei_dbus_invalid_object_path = EI_INIT; -static expert_field ei_dbus_invalid_signature = EI_INIT; + return FALSE; +} -typedef struct { - packet_info *pinfo; +static gboolean +is_dbus_bus_name_valid(const char *bus_name) { + // - Bus names that start with a colon (':') character are unique connection names. Other bus names are called + // well-known bus names. + // - Bus names are composed of 1 or more elements separated by a period ('.') character. All elements must + // contain at least one character. + // - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_-", with "-" discouraged in new bus + // names. Only elements that are part of a unique connection name may begin with a digit, elements in other + // bus names must not begin with a digit. + // - Bus names must contain at least one '.' (period) character (and thus at least two elements). + // - Bus names must not begin with a '.' (period) character. + // - Bus names must not exceed the maximum name length. + gint elements = 0; + const char *p = bus_name; + gboolean is_unique_name = FALSE; + + if (*p == ':') { + is_unique_name = TRUE; + p++; + } - guint16 (*get16)(tvbuff_t *, const gint); - guint32 (*get32)(tvbuff_t *, const gint); - gdouble (*getdouble)(tvbuff_t *, const gint); - int enc; + do { + if (!(is_ascii_alpha(*p) || *p == '_' || *p == '-' || (is_unique_name && is_ascii_digit(*p)))) { + return FALSE; + } + p++; + elements++; - guint32 body_len; - guint32 fields_len; - const char *body_sig; -} dbus_info_t; + while (is_ascii_alpha(*p) || is_ascii_digit(*p) || *p == '_' || *p == '-') { + p++; + } -typedef union { - char *str; - guint uint; + if (*p == '\0') { + size_t length = p - bus_name; + return elements >= 2 && length <= DBUS_MAX_NAME_LENGTH; + } + } while (*p++ == '.'); -} dbus_val_t; + return FALSE; +} static gboolean -dbus_validate_object_path(const char *path) -{ - /* XXX check */ - if (*path != '/') +is_basic_type(char sig_code) { + switch (sig_code) { + case SIG_CODE_BYTE: + case SIG_CODE_BOOLEAN: + case SIG_CODE_INT16: + case SIG_CODE_UINT16: + case SIG_CODE_INT32: + case SIG_CODE_UINT32: + case SIG_CODE_INT64: + case SIG_CODE_UINT64: + case SIG_CODE_DOUBLE: + case SIG_CODE_STRING: + case SIG_CODE_OBJECT_PATH: + case SIG_CODE_SIGNATURE: + case SIG_CODE_UNIX_FD: + return TRUE; + default: return FALSE; + } +} - do { - path++; +static gboolean +is_dbus_signature_valid(const char *signature) { + char sig_code; + size_t length = 0; + wmem_stack_t *expected_chars = wmem_stack_new(wmem_packet_scope()); - if (*path == '/') + while ((sig_code = *signature++) != '\0') { + if (++length >= DBUS_MAX_SIGNATURE_LENGTH) { return FALSE; + } - while ((*path >= 'A' && *path <= 'Z') || (*path >= 'a' && *path <= 'z') || (*path >= '0' && *path <= '9') || *path == '_') - path++; - - if (*path == '\0') - return TRUE; + switch (sig_code) { + case SIG_CODE_BYTE: + case SIG_CODE_SIGNATURE: + case SIG_CODE_VARIANT: + case SIG_CODE_INT16: + case SIG_CODE_UINT16: + case SIG_CODE_INT32: + case SIG_CODE_UINT32: + case SIG_CODE_BOOLEAN: + case SIG_CODE_OBJECT_PATH: + case SIG_CODE_STRING: + case SIG_CODE_UNIX_FD: + case SIG_CODE_INT64: + case SIG_CODE_UINT64: + case SIG_CODE_DOUBLE: + break; + case SIG_CODE_ARRAY: + if (*signature == '\0') { + // arrays must be followed by a single complete type + return FALSE; + } + break; + case SIG_CODE_STRUCT_OPEN: + wmem_stack_push(expected_chars, (void *)SIG_CODE_STRUCT_CLOSE); + break; + case SIG_CODE_DICT_ENTRY_OPEN: + if (!is_basic_type(*signature)) { + // key of dict entry must be a basic type + return FALSE; + } + wmem_stack_push(expected_chars, (void *)SIG_CODE_DICT_ENTRY_CLOSE); + break; + case SIG_CODE_STRUCT_CLOSE: + case SIG_CODE_DICT_ENTRY_CLOSE: + if (wmem_stack_count(expected_chars) == 0 || + (char)(guintptr)wmem_stack_pop(expected_chars) != sig_code) { + return FALSE; + } + break; + default: + return FALSE; + } + } + return wmem_stack_count(expected_chars) == 0; +} - } while (*path == '/'); +static void +add_expert(dbus_packet_t *packet, expert_field *ei) { + expert_add_info(packet->pinfo, packet->current_pi, ei); +} - return FALSE; +static guint32 +add_uint(dbus_packet_t *packet, gint hf) { + header_field_info *info = proto_registrar_get_nth(hf); + gint length; + guint32 value; + switch (info->type) { + case FT_UINT8: + length = 1; + break; + case FT_UINT32: + length = 4; + break; + default: + DISSECTOR_ASSERT_NOT_REACHED(); + } + packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, hf, length, packet->enc, &value); + return value; } -static gboolean -dbus_validate_signature(const char *sig _U_) -{ - /* XXX implement */ - return TRUE; +static const guint8 * +add_dbus_string(dbus_packet_t *packet, int hf, gint uint_length) { + const guint8 *string; + gint start_offset = ptvcursor_current_offset(packet->cursor); + proto_item *pi = ptvcursor_add_ret_string(packet->cursor, hf, uint_length, + packet->enc | ENC_UTF_8, wmem_packet_scope(), &string); + gint item_length = ptvcursor_current_offset(packet->cursor) - start_offset; + guint8 term_byte = tvb_get_guint8(ptvcursor_tvbuff(packet->cursor), ptvcursor_current_offset(packet->cursor)); + proto_item_set_len(pi, item_length + 1); + ptvcursor_advance(packet->cursor, 1); + packet->current_pi = pi; + + if ((strlen(string) != (size_t)(item_length - uint_length)) || (term_byte != '\0')) { + col_add_fstr(packet->pinfo->cinfo, COL_INFO, "%zu %zu %s", strlen(string), (size_t)(item_length - uint_length), string); + return NULL; + } + return string; } static int -dbus_type_alignment(char sig) -{ +calculate_padding_len(gint offset, char sig) { + int alignment; switch (sig) { - case 'y': - case 'g': - return 1; - case 'n': - case 'q': - return 2; - case 'i': - case 'u': - case 'b': - case 'o': - case 'a': - case 's': - return 4; - case 'x': - case 't': - case 'd': - return 8; - /* ... */ - default: - return 1; + case SIG_CODE_BYTE: + case SIG_CODE_SIGNATURE: + case SIG_CODE_VARIANT: + default: + alignment = 1; + break; + case SIG_CODE_INT16: + case SIG_CODE_UINT16: + alignment = 2; + break; + case SIG_CODE_INT32: + case SIG_CODE_UINT32: + case SIG_CODE_BOOLEAN: + case SIG_CODE_OBJECT_PATH: + case SIG_CODE_ARRAY: + case SIG_CODE_STRING: + case SIG_CODE_UNIX_FD: + alignment = 4; + break; + case SIG_CODE_INT64: + case SIG_CODE_UINT64: + case SIG_CODE_DOUBLE: + case SIG_CODE_STRUCT_OPEN: + case SIG_CODE_DICT_ENTRY_OPEN: + alignment = 8; + break; } + return (alignment - (offset % alignment)) % alignment; } static int -dissect_dbus_sig(tvbuff_t *tvb, dbus_info_t *dinfo, proto_tree *tree, int offset, char sig, dbus_val_t *ret) -{ - proto_item *ti; - const int align = dbus_type_alignment(sig); - const int org_offset = (offset + align - 1) / align * align; - offset = org_offset; - - switch (sig) { - case 'y': /* BYTE */ - { - guint8 val; - - val = tvb_get_guint8(tvb, offset); - offset += 1; - - proto_tree_add_uint_format(tree, &hfi_dbus_value_uint, tvb, org_offset, offset - org_offset, val, "BYTE: %u", val); - ret->uint = val; - return offset; +add_padding(dbus_packet_t *packet, char sig) { + guint8 value; + tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); + gint offset = ptvcursor_current_offset(packet->cursor); + gint padding_len = calculate_padding_len(offset, sig); + + if (padding_len != 0) { + packet->current_pi = ptvcursor_add(packet->cursor, hf_dbus_padding, padding_len, packet->enc); + for (gint i = offset; i < (offset + padding_len); i++) { + value = tvb_get_guint8(tvb, i); + if (value != 0) { + add_expert(packet, &ei_dbus_padding_invalid); + return 1; + } } + proto_item_set_hidden(packet->current_pi); + } + return 0; +} - case 'b': /* BOOLEAN */ - { - guint32 val; - - val = dinfo->get32(tvb, offset); - offset += 4; - - ti = proto_tree_add_boolean_format(tree, &hfi_dbus_value_bool, tvb, org_offset, offset - org_offset, val, "BOOLEAN: %s", val ? "True" : "False"); - if (val != 0 && val != 1) { - expert_add_info_format(dinfo->pinfo, ti, &ei_dbus_value_bool_invalid, "Invalid boolean value (must be 0 or 1 is: %u)", val); - return -1; +static const char * +skip_enclosed_container(const char *signature, char open_bracket, char closed_bracket) { + int nested = 0; + for (char sig_code = *signature++; sig_code != '\0'; sig_code = *signature++) { + if (sig_code == closed_bracket) { + if (nested == 0) { + return signature; } - ret->uint = val; - return offset; + nested--; + } else if (sig_code == open_bracket) { + nested++; } + } + return NULL; +} - case 'n': /* INT16 */ - { - gint16 val; - - val = (gint16 )dinfo->get16(tvb, offset); - offset += 2; - - proto_tree_add_uint_format(tree, &hfi_dbus_value_int, tvb, org_offset, offset - org_offset, val, "INT16: %d", val); - /* XXX ret */ - return offset; +static const char * +skip_single_complete_type(const char *signature) { + char sig_code; + while (1) { + sig_code = *signature++; + switch (sig_code) { + case SIG_CODE_BYTE: + case SIG_CODE_BOOLEAN: + case SIG_CODE_INT16: + case SIG_CODE_UINT16: + case SIG_CODE_INT32: + case SIG_CODE_UINT32: + case SIG_CODE_INT64: + case SIG_CODE_UINT64: + case SIG_CODE_DOUBLE: + case SIG_CODE_STRING: + case SIG_CODE_OBJECT_PATH: + case SIG_CODE_SIGNATURE: + case SIG_CODE_VARIANT: + case SIG_CODE_UNIX_FD: + return signature; + case SIG_CODE_ARRAY: + continue; + case SIG_CODE_STRUCT_OPEN: + return skip_enclosed_container(signature, SIG_CODE_STRUCT_OPEN, SIG_CODE_STRUCT_CLOSE); + case SIG_CODE_DICT_ENTRY_OPEN: + return skip_enclosed_container(signature, SIG_CODE_DICT_ENTRY_OPEN, SIG_CODE_DICT_ENTRY_CLOSE); + default: + return NULL; } + } +} - case 'q': /* UINT16 */ - { - guint16 val; - - val = dinfo->get16(tvb, offset); - offset += 2; - - proto_tree_add_uint_format(tree, &hfi_dbus_value_uint, tvb, org_offset, offset - org_offset, val, "UINT16: %u", val); - ret->uint = val; - return offset; +static dbus_type_reader_t * +reader_next(dbus_type_reader_t *reader, int hf, int ett, dbus_val_t *value) { + int err = 0; + char sig_code = *reader->signature++; + dbus_packet_t *packet = reader->packet; + gboolean is_single_complete_type = TRUE; + add_padding(packet, sig_code); + + switch (sig_code) { + case SIG_CODE_BYTE: + packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, + hf != -1 ? hf : hf_dbus_type_byte, 1, packet->enc, &value->uint); + break; + case SIG_CODE_BOOLEAN: { + gint offset = ptvcursor_current_offset(packet->cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); + guint8 val = tvb_get_guint8(tvb, offset); + packet->current_pi = ptvcursor_add_ret_boolean(packet->cursor, + hf != -1 ? hf : hf_dbus_type_boolean, 4, packet->enc, &value->bool_); + if (val >= 2) { + add_expert(packet, &ei_dbus_type_boolean_invalid); + err = 1; } - - case 'i': /* INT32 */ - { - gint32 val; - - val = (gint32) dinfo->get32(tvb, offset); - offset += 4; - - proto_tree_add_int_format(tree, &hfi_dbus_value_int, tvb, org_offset, offset - org_offset, val, "INT32: %d", val); - /* XXX ret */ - return offset; + break; + } + case SIG_CODE_INT16: + packet->current_pi = ptvcursor_add_ret_int(packet->cursor, + hf != -1 ? hf : hf_dbus_type_int16, 2, packet->enc, &value->int_); + break; + case SIG_CODE_UINT16: + packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, + hf != -1 ? hf : hf_dbus_type_uint16, 2, packet->enc, &value->uint); + break; + case SIG_CODE_INT32: + packet->current_pi = ptvcursor_add_ret_int(packet->cursor, + hf != -1 ? hf : hf_dbus_type_int32, 4, packet->enc, &value->int_); + break; + case SIG_CODE_UINT32: + packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, + hf != -1 ? hf : hf_dbus_type_uint32, 4, packet->enc, &value->uint); + break; + case SIG_CODE_INT64: { + gint offset = ptvcursor_current_offset(packet->cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); + value->int64 = tvb_get_gint64(tvb, offset, packet->enc); + packet->current_pi = ptvcursor_add(packet->cursor, + hf != -1 ? hf : hf_dbus_type_int64, 8, packet->enc); + break; + } + case SIG_CODE_UINT64: { + gint offset = ptvcursor_current_offset(packet->cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); + value->uint64 = tvb_get_guint64(tvb, offset, packet->enc); + packet->current_pi = ptvcursor_add(packet->cursor, + hf != -1 ? hf : hf_dbus_type_uint64, 8, packet->enc); + break; + } + case SIG_CODE_DOUBLE: { + gint offset = ptvcursor_current_offset(packet->cursor); + tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); + value->double_ = tvb_get_ieee_double(tvb, offset, packet->enc); + packet->current_pi = ptvcursor_add(packet->cursor, + hf != -1 ? hf : hf_dbus_type_double, 8, packet->enc); + break; + } + case SIG_CODE_STRING: { + const char *val = add_dbus_string(packet, + hf != -1 ? hf : hf_dbus_type_string, 4); + if (!val || !g_utf8_validate(val, -1, NULL)) { + add_expert(packet, &ei_dbus_string_invalid); + err = 1; } - - case 'u': /* UINT32 */ - { - guint32 val; - - val = dinfo->get32(tvb, offset); - offset += 4; - - proto_tree_add_uint_format(tree, &hfi_dbus_value_uint, tvb, org_offset, offset - org_offset, val, "UINT32: %u", val); - ret->uint = val; - return offset; + value->string = val; + break; + } + case SIG_CODE_OBJECT_PATH: { + const char *val = add_dbus_string(packet, hf != -1 ? hf : hf_dbus_type_object_path, 4); + if (!val || !is_dbus_object_path_valid(val)) { + add_expert(packet, &ei_dbus_type_object_path_invalid); + err = 1; } - - case 'x': /* INT64 */ - case 't': /* UINT64 */ - return -1; - - case 'd': /* DOUBLE */ - { - gdouble val; - - val = dinfo->getdouble(tvb, offset); - offset += 8; - - proto_tree_add_double(tree, &hfi_dbus_value_double, tvb, org_offset, offset - org_offset, val); - /* XXX ret */ - return offset; + value->string = val; + break; + } + case SIG_CODE_SIGNATURE: { + const char *val = add_dbus_string(packet, hf != -1 ? hf : hf_dbus_type_signature, 1); + if (!val || !is_dbus_signature_valid(val)) { + add_expert(packet, &ei_dbus_type_signature_invalid); + err = 1; } + value->string = val; + break; + } + case SIG_CODE_ARRAY: { + is_single_complete_type = FALSE; + proto_item *array = ptvcursor_add_with_subtree(packet->cursor, hf != -1 ? hf : hf_dbus_type_array, + SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett != -1 ? ett : ett_dbus_type_array); + if (*reader->signature == SIG_CODE_DICT_ENTRY_OPEN) { + proto_item_append_text(array, " (Dict)"); + } + guint32 array_len = add_uint(packet, hf_dbus_type_array_length); + value->uint = array_len; + add_padding(packet, *reader->signature); + if (array_len == 0) { + reader->signature = skip_single_complete_type(reader->signature); + if (reader->signature == NULL) { + err = 1; + } + ptvcursor_pop_subtree(packet->cursor); + is_single_complete_type = TRUE; + } else if (array_len <= DBUS_MAX_ARRAY_LEN) { + int end_offset = ptvcursor_current_offset(packet->cursor) + array_len; + dbus_type_reader_t *child = (dbus_type_reader_t *)wmem_alloc( + wmem_packet_scope(), sizeof(dbus_type_reader_t)); + *child = (dbus_type_reader_t){ + .packet = reader->packet, + .signature = reader->signature, + .level = reader->level + 1, + .array_level = reader->array_level + 1, + .array_type_start = reader->signature, + .array_end_offset = end_offset, + .container = array, + .parent = reader, + }; + reader = child; + } else { + add_expert(packet, &ei_dbus_type_array_too_long); + err = 1; + ptvcursor_pop_subtree(packet->cursor); + } + break; + } + case SIG_CODE_STRUCT_OPEN: { + is_single_complete_type = FALSE; + ptvcursor_add_with_subtree(packet->cursor, hf != -1 ? hf : hf_dbus_type_struct, + SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett != -1 ? ett : ett_dbus_type_struct); + dbus_type_reader_t *child = (dbus_type_reader_t *)wmem_alloc( + wmem_packet_scope(), sizeof(dbus_type_reader_t)); + *child = (dbus_type_reader_t){ + .packet = reader->packet, + .signature = reader->signature, + .level = reader->level + 1, + .struct_level = reader->struct_level + 1, + .parent = reader, + }; + reader = child; + break; + } + case SIG_CODE_VARIANT: { + is_single_complete_type = FALSE; + proto_item *variant = ptvcursor_add_with_subtree(packet->cursor, + hf != -1 ? hf : hf_dbus_type_variant, + SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett != -1 ? ett : ett_dbus_type_variant); + const char *variant_signature = add_dbus_string(packet, hf_dbus_type_variant_signature, 1); + value->string = variant_signature; + if (variant_signature && is_dbus_signature_valid(variant_signature)) { + dbus_type_reader_t *child = (dbus_type_reader_t *)wmem_alloc( + wmem_packet_scope(), sizeof(dbus_type_reader_t)); + *child = (dbus_type_reader_t){ + .packet = reader->packet, + .signature = variant_signature, + .level = reader->level + 1, + .is_in_variant = TRUE, + .is_basic_variant = is_basic_type(*variant_signature) + && *(variant_signature + 1) == '\0', + .container = variant, + .parent = reader, + }; + if (reader->is_in_dict_entry && child->is_basic_variant) { + reader->is_basic_dict_entry = TRUE; + } + reader = child; + } else { + add_expert(packet, &ei_dbus_type_variant_signature_invalid); + err = 1; + ptvcursor_pop_subtree(packet->cursor); + } + break; + } + case SIG_CODE_DICT_ENTRY_OPEN: { + is_single_complete_type = FALSE; + proto_item *dict_entry = ptvcursor_add_with_subtree(packet->cursor, + hf != -1 ? hf : hf_dbus_type_dict_entry, + SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett != -1 ? ett : ett_dbus_type_dict_entry); + dbus_type_reader_t *child = (dbus_type_reader_t *)wmem_alloc( + wmem_packet_scope(), sizeof(dbus_type_reader_t)); + *child = (dbus_type_reader_t){ + .packet = reader->packet, + .signature = reader->signature, + .level = reader->level + 1, + .dict_entry_level = reader->dict_entry_level + 1, + .is_in_dict_entry = TRUE, + .is_basic_dict_entry = is_basic_type(*(reader->signature + 1)), + .container = dict_entry, + .parent = reader, + }; + reader = child; + break; + } + case SIG_CODE_STRUCT_CLOSE: + case SIG_CODE_DICT_ENTRY_CLOSE: + ptvcursor_pop_subtree(packet->cursor); + reader->parent->signature = reader->signature; + reader = reader->parent; + break; + case SIG_CODE_UNIX_FD: + packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, + hf != -1 ? hf : hf_dbus_type_unix_fd, 4, packet->enc, &value->uint); + break; + default: + // all signatures are validated + DISSECTOR_ASSERT_NOT_REACHED(); + } - case 's': /* STRING */ - case 'o': /* OBJECT_PATH */ - { - guint32 len; - char *val; - - len = dinfo->get32(tvb, offset); - offset += 4; - - val = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, len, ENC_ASCII); - offset += (len + 1 /* NUL-byte */); - - if (sig == 's') { - ti = proto_tree_add_string_format(tree, &hfi_dbus_value_str, tvb, org_offset, offset - org_offset, val, "STRING: %s", val); - if (!g_utf8_validate(val, -1, NULL)) { - expert_add_info(dinfo->pinfo, ti, &ei_dbus_value_str_invalid); - return -1; + if (reader->level > DBUS_MAX_TOTAL_NESTING_LEVEL || + reader->array_level > DBUS_MAX_TYPE_NESTING_LEVEL || + reader->struct_level > DBUS_MAX_TYPE_NESTING_LEVEL || + reader->dict_entry_level > DBUS_MAX_TYPE_NESTING_LEVEL) { + add_expert(packet, &ei_dbus_nested_too_deeply); + err= 1; + } else if (is_single_complete_type) { + // Arrays and variants don't have a closing signature code, but they end after a single complete type. + // Close them here recursively, e.g. "aav" + while (1) { + if (reader->array_type_start) { // inside array + gint offset = ptvcursor_current_offset(packet->cursor); + + if (offset < reader->array_end_offset) { + // parse next array element -> reset signature + reader->signature = reader->array_type_start; + break; + } else if (offset == reader->array_end_offset) { + // all array elements parsed + ptvcursor_pop_subtree(packet->cursor); + reader->parent->signature = reader->signature; + reader = reader->parent; + } else { + // array elements don't fit into array + expert_add_info(packet->pinfo, reader->container, + &ei_dbus_type_array_content_out_of_bounds); + err = 1; + break; } - } else { - ti = proto_tree_add_string_format(tree, &hfi_dbus_value_str, tvb, org_offset, offset - org_offset, val, "OBJECT_PATH: %s", val); - if (!dbus_validate_object_path(val)) { - expert_add_info(dinfo->pinfo, ti, &ei_dbus_invalid_object_path); - return -1; + } else if (reader->is_in_variant) { + if (reader->is_basic_variant) { + proto_item_append_text(reader->container, ": %s", + proto_item_get_display_repr(wmem_packet_scope(), packet->current_pi)); } + ptvcursor_pop_subtree(packet->cursor); + reader = reader->parent; + } else { + break; } - ret->str = val; - return offset; } - - case 'g': /* SIGNATURE */ - { - guint8 len; - char *val; - - len = tvb_get_guint8(tvb, offset); - offset += 1; - - val = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, len, ENC_ASCII); - offset += (len + 1); - - ti = proto_tree_add_string_format(tree, &hfi_dbus_value_str, tvb, org_offset, offset - org_offset, val, "SIGNATURE: %s", val); - if (!dbus_validate_signature(val)) { - expert_add_info(dinfo->pinfo, ti, &ei_dbus_invalid_signature); - return -1; + if (reader->is_in_dict_entry) { + // add "key: value" to dict entry item to make it readable without expanding the tree + if (*(reader->signature - 2) == SIG_CODE_DICT_ENTRY_OPEN) { // == key + // key is always a basic type + proto_item_append_text(reader->container, ", %s", + proto_item_get_display_repr(wmem_packet_scope(), packet->current_pi)); + } else if (reader->is_basic_dict_entry) { // == value + proto_item_append_text(reader->container, ": %s", + proto_item_get_display_repr(wmem_packet_scope(), packet->current_pi)); } - ret->str = val; - return offset; } + } - /* ... */ + if (err) { + for (dbus_type_reader_t *r = reader; r->parent; r = r->parent) { + ptvcursor_pop_subtree(packet->cursor); + } } - return -1; + return !err ? reader : NULL; } -static int -dissect_dbus_field_signature(tvbuff_t *tvb, packet_info *pinfo, dbus_info_t *dinfo, proto_tree *tree, int offset, int field_code) -{ - const int org_offset = offset; - - proto_item *ti; - guint sig_len; - char *sig; +static gboolean reader_is_finished(dbus_type_reader_t *reader) { + return *reader->signature == '\0' && reader->parent == NULL; +} - sig_len = tvb_get_guint8(tvb, offset); - offset += 1; +static int +dissect_dbus_signature(dbus_packet_t *packet, const char *signature) { + dbus_type_reader_t root_reader = { + .packet = packet, + .signature = signature, + }; + dbus_type_reader_t *reader = &root_reader; + dbus_val_t value; + while (!reader_is_finished(reader)) { + reader = reader_next(reader, -1, -1, &value); + if (!reader) { + return 1; + } + } + return 0; +} - /* sig_len = tvb_strsize(tvb, offset); */ +static int +dissect_dbus_body(dbus_packet_t *packet) { + int err = 0; + if (packet->signature[0]) { + ptvcursor_add_with_subtree(packet->cursor, hf_dbus_body, + SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_dbus_body); + err = dissect_dbus_signature(packet, packet->signature); + ptvcursor_pop_subtree(packet->cursor); + } + return err; +} - sig = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, sig_len, ENC_ASCII); - offset += (sig_len + 1); +static int +dissect_dbus_header_fields(dbus_packet_t *packet) { + dbus_type_reader_t root_reader = { + .packet = packet, + .signature = "a{yv}", + }; + dbus_type_reader_t *reader = &root_reader; + dbus_val_t value; +#define NEXT_OR_RETURN(hf, ett) if (!(reader = reader_next(reader, hf, ett, &value))) return 1; + + // Header Field Array + NEXT_OR_RETURN(-1, ett_dbus_header_field_array); + proto_item *header_field_array_pi = reader->container; + proto_item_set_text(header_field_array_pi, "Header Field Array"); + while (reader->level > 0) { + // Header Field (Dict) + NEXT_OR_RETURN(-1, ett_dbus_header_field); + // Field Code + NEXT_OR_RETURN(hf_dbus_field_code, -1); + guint32 field_code = value.uint; + const gchar *field_code_str = val_to_str_const(field_code, field_code_vals, "Unknown field code"); + proto_item_append_text(reader->container, ", %s", field_code_str); + if (field_code == DBUS_HEADER_FIELD_INVALID) { + add_expert(packet, &ei_dbus_field_code_invalid); + return 1; + } - ti = proto_tree_add_string(tree, &hfi_dbus_type_signature, tvb, org_offset, offset - org_offset, sig); - if (!dbus_validate_signature(sig)) { - expert_add_info(dinfo->pinfo, ti, &ei_dbus_invalid_signature); - return -1; - } + // Header Field Value (Variant) + NEXT_OR_RETURN(-1, -1); + const char *header_field_signature = value.string; - switch (field_code) { + const char *expected_signature; + switch (field_code) { + case DBUS_HEADER_FIELD_PATH: + expected_signature = "o"; + break; + case DBUS_HEADER_FIELD_INTERFACE: + case DBUS_HEADER_FIELD_MEMBER: + case DBUS_HEADER_FIELD_ERROR_NAME: + case DBUS_HEADER_FIELD_DESTINATION: + case DBUS_HEADER_FIELD_SENDER: + expected_signature = "s"; + break; case DBUS_HEADER_FIELD_REPLY_SERIAL: - if (!strcmp(sig, "u")) { /* UINT32 */ - dbus_val_t serial_val; + expected_signature = "u"; + break; + case DBUS_HEADER_FIELD_UNIX_FDS: + expected_signature = "u"; + break; + case DBUS_HEADER_FIELD_SIGNATURE: + expected_signature = "g"; + break; + default: + expected_signature = NULL; + } - offset = dissect_dbus_sig(tvb, dinfo, tree, offset, 'u', &serial_val); - if (offset != -1) - { /* XXX link with sending frame (serial_val.uint) */ } - return offset; + if (expected_signature && strcmp(header_field_signature, expected_signature) != 0) { + add_expert(packet, &ei_dbus_field_signature_wrong); + return 1; + } + + // Variant Value + switch (field_code) { + case DBUS_HEADER_FIELD_PATH: + NEXT_OR_RETURN(hf_dbus_path, -1); + packet->path = value.string; + break; + case DBUS_HEADER_FIELD_INTERFACE: + NEXT_OR_RETURN(hf_dbus_interface, -1); + packet->interface = value.string; + if (!is_dbus_interface_valid(packet->interface)) { + add_expert(packet, &ei_dbus_interface_invalid); + return 1; + } + break; + case DBUS_HEADER_FIELD_MEMBER: + NEXT_OR_RETURN(hf_dbus_member, -1); + packet->member = value.string; + if (!is_dbus_member_name_valid(packet->member)) { + add_expert(packet, &ei_dbus_member_invalid); + return 1; + } + break; + case DBUS_HEADER_FIELD_ERROR_NAME: + NEXT_OR_RETURN(hf_dbus_error_name, -1); + packet->error_name = value.string; + if (!is_dbus_interface_valid(packet->error_name)) { + add_expert(packet, &ei_dbus_error_name_invalid); + return 1; } break; - case DBUS_HEADER_FIELD_DESTINATION: + NEXT_OR_RETURN(hf_dbus_destination, -1); + packet->destination = value.string; + if (!is_dbus_bus_name_valid(packet->destination)) { + add_expert(packet, &ei_dbus_bus_name_invalid); + return 1; + } + set_address(&packet->pinfo->dst, AT_STRINGZ, (int)strlen(packet->destination)+1, + wmem_strdup(packet->pinfo->pool, packet->destination)); + break; case DBUS_HEADER_FIELD_SENDER: - if (!strcmp(sig, "s")) { /* STRING */ - dbus_val_t addr_val; - - offset = dissect_dbus_sig(tvb, dinfo, tree, offset, 's', &addr_val); - if (offset != -1) - set_address((field_code == DBUS_HEADER_FIELD_DESTINATION) ? &dinfo->pinfo->dst : &dinfo->pinfo->src, - AT_STRINGZ, (int)strlen(addr_val.str)+1, wmem_strdup(pinfo->pool, addr_val.str)); - return offset; + NEXT_OR_RETURN(hf_dbus_sender, -1); + packet->sender = value.string; + if (!is_dbus_bus_name_valid(packet->sender)) { + add_expert(packet, &ei_dbus_bus_name_invalid); + return 1; } + set_address(&packet->pinfo->src, AT_STRINGZ, (int)strlen(packet->sender)+1, + wmem_strdup(packet->pinfo->pool, packet->sender)); break; - case DBUS_HEADER_FIELD_SIGNATURE: - if (!strcmp(sig, "g")) { /* SIGNATURE */ - dbus_val_t sig_val; - - offset = dissect_dbus_sig(tvb, dinfo, tree, offset, 'g', &sig_val); - if (offset != -1) - dinfo->body_sig = sig_val.str; - return offset; + NEXT_OR_RETURN(hf_dbus_signature, -1); + packet->signature = value.string; + break; + case DBUS_HEADER_FIELD_REPLY_SERIAL: + NEXT_OR_RETURN(hf_dbus_reply_serial, -1); + packet->reply_serial = value.uint; + if (packet->reply_serial == 0) { + add_expert(packet, &ei_dbus_serial_invalid); + return 1; } break; + case DBUS_HEADER_FIELD_UNIX_FDS: + NEXT_OR_RETURN(hf_dbus_unix_fds, -1); + packet->unix_fds = value.uint; + break; + default: + // Unknown Field code must be skipped without error + do { + NEXT_OR_RETURN(-1, -1); + // Skip while inside Header Field Array -> Header Field Dict -> Variant + } while (reader->level >= 3); + } + // end of dict + NEXT_OR_RETURN(-1, -1); } - while (*sig) { - dbus_val_t val; - - offset = dissect_dbus_sig(tvb, dinfo, tree, offset, *sig, &val); - if (offset == -1) - return -1; - sig++; + gboolean is_field_missing = FALSE; + switch (packet->message_type) { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + is_field_missing = !packet->path || !packet->member; + break; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + is_field_missing = !packet->reply_serial; + break; + case DBUS_MESSAGE_TYPE_ERROR: + is_field_missing = !packet->error_name || !packet->reply_serial; + break; + case DBUS_MESSAGE_TYPE_SIGNAL: + is_field_missing = !packet->path || !packet->interface || !packet->member; + break; + default: + DISSECTOR_ASSERT_NOT_REACHED(); + break; } - return offset; -} - -static int -dissect_dbus_hdr_fields(tvbuff_t *tvb, packet_info *pinfo, dbus_info_t *dinfo, proto_tree *tree, int offset) -{ - int end_offset; - - end_offset = offset + dinfo->fields_len; - - while (offset < end_offset) { - proto_tree *field_tree; - proto_item *ti; - - guint8 field_code; - - ti = proto_tree_add_item(tree, &hfi_dbus_hdr_field, tvb, offset, 0, ENC_NA); - field_tree = proto_item_add_subtree(ti, ett_dbus_field); - - field_code = tvb_get_guint8(tvb, offset); - proto_tree_add_item(field_tree, &hfi_dbus_hdr_field_code, tvb, offset, 1, dinfo->enc); - proto_item_append_text(ti, ": %s", val_to_str(field_code, field_code_vals, "Unknown: %d")); - offset += 1; - - offset = dissect_dbus_field_signature(tvb, pinfo, dinfo, field_tree, offset, field_code); - if (offset == -1) - break; - - offset = (offset + 7) & ~7; /* XXX ? */ - - proto_item_set_end(ti, tvb, offset); + if (is_field_missing) { + expert_add_info(packet->pinfo, header_field_array_pi, &ei_dbus_required_header_field_missing); + return 1; } - /* XXX, verify if all required fields are preset */ - - if (offset >= end_offset) { - /* XXX expert */ + switch(packet->message_type) { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + col_add_fstr(packet->pinfo->cinfo, COL_INFO, "%s() @ %s", packet->member, packet->path); + break; + case DBUS_MESSAGE_TYPE_SIGNAL: + col_add_fstr(packet->pinfo->cinfo, COL_INFO, "* %s() @ %s", packet->member, packet->path); + break; + case DBUS_MESSAGE_TYPE_ERROR: + col_add_fstr(packet->pinfo->cinfo, COL_INFO, "-> %s", packet->error_name); + break; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + col_add_fstr(packet->pinfo->cinfo, COL_INFO, "-> '%s'", packet->signature); + break; + default: + DISSECTOR_ASSERT_NOT_REACHED(); + break; } - return end_offset; + // Header length must be a multiple of 8 bytes + return add_padding(packet, SIG_CODE_STRUCT_OPEN); } static int -dissect_dbus_hdr(tvbuff_t *tvb, dbus_info_t *dinfo, proto_tree *tree, int offset) -{ - proto_tree *hdr_tree; - proto_item *ti; - - guint8 type; - - ti = proto_tree_add_item(tree, &hfi_dbus_hdr, tvb, offset, 0, ENC_NA); - hdr_tree = proto_item_add_subtree(ti, ett_dbus_hdr); - - proto_tree_add_item(hdr_tree, &hfi_dbus_hdr_endianness, tvb, offset, 1, ENC_ASCII | ENC_NA); - offset += 1; - - type = tvb_get_guint8(tvb, offset); - col_set_str(dinfo->pinfo->cinfo, COL_INFO, val_to_str_const(type, message_type_vals, "")); - proto_tree_add_item(hdr_tree, &hfi_dbus_hdr_type, tvb, offset, 1, dinfo->enc); - offset += 1; - - proto_tree_add_item(hdr_tree, &hfi_dbus_hdr_flags, tvb, offset, 1, dinfo->enc); - offset += 1; - - proto_tree_add_item(hdr_tree, &hfi_dbus_hdr_version, tvb, offset, 1, dinfo->enc); - offset += 1; - - dinfo->body_len = dinfo->get32(tvb, offset); - proto_tree_add_item(hdr_tree, &hfi_dbus_hdr_body_length, tvb, offset, 4, dinfo->enc); - offset += 4; - - proto_tree_add_item(hdr_tree, &hfi_dbus_hdr_serial, tvb, offset, 4, dinfo->enc); - offset += 4; - - dinfo->fields_len = dinfo->get32(tvb, offset); - proto_tree_add_item(hdr_tree, &hfi_dbus_hdr_fields_length, tvb, offset, 4, dinfo->enc); - offset += 4; +dissect_dbus_header(dbus_packet_t *packet) { + guint32 val; - return offset; -} - -static int -dissect_dbus_body(tvbuff_t *tvb, dbus_info_t *dinfo, proto_tree *tree, int offset) -{ - proto_tree *body_tree; - proto_item *ti; - - if (dinfo->body_len && dinfo->body_sig[0]) { - const char *sig = dinfo->body_sig; - - ti = proto_tree_add_item(tree, &hfi_dbus_body, tvb, offset, 0, ENC_NA); - body_tree = proto_item_add_subtree(ti, ett_dbus_body); - - while (*sig) { - dbus_val_t val; + // Endianness + packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, hf_dbus_endianness, 1, ENC_NA, &val); + switch (val) { + case 'l': + packet->enc = ENC_LITTLE_ENDIAN; + break; + case 'B': + packet->enc = ENC_BIG_ENDIAN; + break; + default: + add_expert(packet, &ei_dbus_endianness_invalid); + return 1; + } - offset = dissect_dbus_sig(tvb, dinfo, body_tree, offset, *sig, &val); - if (offset == -1) - return -1; - sig++; - } + // Message Type + packet->message_type = add_uint(packet, hf_dbus_message_type); + const gchar *info = try_val_to_str(packet->message_type, message_type_vals); + if (packet->message_type == DBUS_MESSAGE_TYPE_INVALID) { + col_set_str(packet->pinfo->cinfo, COL_INFO, info); + add_expert(packet, &ei_dbus_message_type_invalid); + return 1; + } else if (!info) { + col_set_str(packet->pinfo->cinfo, COL_INFO, "Unknown message type"); + add_expert(packet, &ei_dbus_message_type_unknown); + return 1; + } + col_set_str(packet->pinfo->cinfo, COL_INFO, info); + + // Flags + ptvcursor_add_with_subtree(packet->cursor, hf_dbus_flags, 1, packet->enc, ett_dbus_flags); + ptvcursor_add_no_advance(packet->cursor, hf_dbus_flags_no_reply_expected, 1, packet->enc); + ptvcursor_add_no_advance(packet->cursor, hf_dbus_flags_no_auto_start, 1, packet->enc); + ptvcursor_add_no_advance(packet->cursor, hf_dbus_flags_allow_interactive_authorization, 1, packet->enc); + ptvcursor_advance(packet->cursor, 1); + ptvcursor_pop_subtree(packet->cursor); + + // Version + if (add_uint(packet, hf_dbus_version) != 1) { + add_expert(packet, &ei_dbus_version_invalid); + return 1; + } - proto_item_set_end(ti, tvb, offset); + // Body Length + packet->body_len = add_uint(packet, hf_dbus_body_length); - } else if (dinfo->body_len || dinfo->body_sig[0]) { - /* XXX smth wrong */ + // Serial + packet->serial = add_uint(packet, hf_dbus_serial); + if (packet->serial == 0) { + add_expert(packet, &ei_dbus_serial_invalid); + return 1; } - return offset; + + return 0; } static int -dissect_dbus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) -{ - proto_tree *dbus_tree = NULL; - dbus_info_t dinfo; +dissect_dbus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { + dbus_packet_t packet = { .pinfo = pinfo, .signature = "" }; - int offset; + col_set_str(pinfo->cinfo, COL_PROTOCOL, "D-Bus"); + col_set_str(pinfo->cinfo, COL_INFO, "D-Bus"); - col_set_str(pinfo->cinfo, COL_PROTOCOL, "D-BUS"); - col_clear(pinfo->cinfo, COL_INFO); + proto_item *pi = proto_tree_add_protocol_format(tree, proto_dbus, tvb, 0, -1, "D-Bus"); + proto_tree *dbus_tree = proto_item_add_subtree(pi, ett_dbus); - memset(&dinfo, 0, sizeof(dinfo)); - dinfo.pinfo = pinfo; - switch (tvb_get_guint8(tvb, 0)) { - case 'l': - dinfo.enc = ENC_LITTLE_ENDIAN; - dinfo.get16 = tvb_get_letohs; - dinfo.get32 = tvb_get_letohl; - dinfo.getdouble = tvb_get_letohieee_double; - break; - case 'B': - dinfo.enc = ENC_BIG_ENDIAN; - dinfo.get16 = tvb_get_ntohs; - dinfo.get32 = tvb_get_ntohl; - dinfo.getdouble = tvb_get_ntohieee_double; - break; - default: /* same as BIG_ENDIAN */ - /* XXX we should probably return 0; */ - dinfo.enc = ENC_NA; - dinfo.get16 = tvb_get_ntohs; - dinfo.get32 = tvb_get_ntohl; - dinfo.getdouble = tvb_get_ntohieee_double; - } - - if (tree) { - proto_item *ti = proto_tree_add_item(tree, hfi_dbus, tvb, 0, -1, ENC_NA); - dbus_tree = proto_item_add_subtree(ti, ett_dbus); - } - - offset = 0; - offset = dissect_dbus_hdr(tvb, &dinfo, dbus_tree, offset); - offset = dissect_dbus_hdr_fields(tvb, pinfo, &dinfo, dbus_tree, offset); - /* header aligned to 8B */ - offset = (offset + 7) & ~7; + gint offset = 0; + packet.cursor = ptvcursor_new(dbus_tree, tvb, offset); - if (!dinfo.body_sig) - dinfo.body_sig = ""; - - offset = dissect_dbus_body(tvb, &dinfo, dbus_tree, offset); + (void)(dissect_dbus_header(&packet) || + dissect_dbus_header_fields(&packet) || + dissect_dbus_body(&packet)); + offset = ptvcursor_current_offset(packet.cursor); + proto_item_set_end(pi, tvb, offset); + ptvcursor_free(packet.cursor); return offset; } @@ -606,8 +1163,7 @@ dissect_dbus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ static guint get_dbus_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, - int offset, void *data _U_) -{ + int offset, void *data _U_) { guint32 (*get_guint32)(tvbuff_t *, const gint); guint32 len_body, len_hdr; @@ -630,68 +1186,165 @@ get_dbus_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, } static int -dissect_dbus_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) -{ +dissect_dbus_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { return dissect_dbus(tvb, pinfo, tree, data); } static int -dissect_dbus_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) -{ - tcp_dissect_pdus(tvb, pinfo, tree, dbus_desegment, DBUS_HEADER_LEN, get_dbus_message_len, dissect_dbus_pdu, data); +dissect_dbus_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { + tcp_dissect_pdus(tvb, pinfo, tree, dbus_desegment, DBUS_HEADER_LEN, + get_dbus_message_len, dissect_dbus_pdu, data); return tvb_reported_length(tvb); } void -proto_register_dbus(void) -{ -#ifndef HAVE_HFI_SECTION_INIT - static header_field_info *hfi[] = { - /* Header */ - &hfi_dbus_hdr, - &hfi_dbus_hdr_endianness, - &hfi_dbus_hdr_type, - &hfi_dbus_hdr_flags, - &hfi_dbus_hdr_version, - &hfi_dbus_hdr_body_length, - &hfi_dbus_hdr_serial, - &hfi_dbus_hdr_fields_length, - /* Header field */ - &hfi_dbus_hdr_field, - &hfi_dbus_hdr_field_code, - &hfi_dbus_type_signature, - &hfi_dbus_body, - /* Values */ - &hfi_dbus_value_bool, - &hfi_dbus_value_int, - &hfi_dbus_value_uint, - &hfi_dbus_value_str, - &hfi_dbus_value_double, +proto_register_dbus(void) { + static hf_register_info hf[] = { + { &hf_dbus_endianness, { "Endianness", "dbus.endianness", + FT_UINT8, BASE_NONE, VALS(endianness_vals), 0x00, NULL, HFILL }}, + { &hf_dbus_message_type, { "Message Type", "dbus.message_type", + FT_UINT8, BASE_NONE, VALS(message_type_vals), 0x00, NULL, HFILL }}, + { &hf_dbus_flags, { "Message Flags", "dbus.flags", + FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_flags_no_reply_expected, { "No Reply Expected", "dbus.flags.no_reply_expected", + FT_BOOLEAN, 8, TFS(¬_expected_vals), 0x01, NULL, HFILL }}, + { &hf_dbus_flags_no_auto_start, { "No Auto Start", "dbus.flags.no_auto_start", + FT_BOOLEAN, 8, TFS(&no_start_vals), 0x02, NULL, HFILL }}, + { &hf_dbus_flags_allow_interactive_authorization, { "Allow Interactive Authorization", "dbus.flags.allow_interactive_authorization", + FT_BOOLEAN, 8, TFS(&allow_vals), 0x04, NULL, HFILL }}, + { &hf_dbus_version, { "Protocol Version", "dbus.version", + FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_body_length, { "Message Body Length", "dbus.body_length", + FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_serial, { "Message Serial", "dbus.serial", + FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_field_code, { "Field Code", "dbus.field_code", + FT_UINT8, BASE_DEC, VALS(field_code_vals), 0x00, NULL, HFILL }}, + { &hf_dbus_padding, { "Padding", "dbus.padding", + FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_path, { "Path", "dbus.path", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_interface, { "Interface", "dbus.interface", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_member, { "Member", "dbus.member", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_error_name, { "Error name", "dbus.error_name", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_reply_serial, { "Reply serial", "dbus.reply_serial", + FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_destination, { "Destination", "dbus.destination", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_sender, { "Sender", "dbus.sender", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_signature, { "Signature", "dbus.signature", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_unix_fds, { "Unix FDs", "dbus.unix_fds", + FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_body, { "Body", "dbus.body", + FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_byte, { "Byte", "dbus.type.byte", + FT_UINT8, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_boolean, { "Boolean", "dbus.type.boolean", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_int16, { "Int16", "dbus.type.int16", + FT_INT16, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_uint16, { "Uint16", "dbus.type.uint16", + FT_UINT16, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_int32, { "Int32", "dbus.type.int32", + FT_INT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_uint32, { "Uint32", "dbus.type.uint32", + FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_int64, { "Int64", "dbus.type.int64", + FT_INT64, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_uint64, { "Uint64", "dbus.type.uint64", + FT_UINT64, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_double, { "Double", "dbus.type.double", + FT_DOUBLE, BASE_NONE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_string, { "String", "dbus.type.string", + FT_UINT_STRING, STR_UNICODE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_object_path, { "Object Path", "dbus.type.object_path", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_signature, { "Signature", "dbus.type.signature", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_array, { "Array", "dbus.type.array", + FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_array_length, { "Array Length", "dbus.type.array.length", + FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_struct, { "Struct", "dbus.type.struct", + FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_variant, { "Variant", "dbus.type.variant", + FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_variant_signature, { "Variant Signature", "dbus.type.variant.signature", + FT_UINT_STRING, STR_ASCII, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_dict_entry, { "Dict Entry", "dbus.type.dict_entry", + FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_dict_entry_key, { "Key", "dbus.type.dict_entry.key", + FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, + { &hf_dbus_type_unix_fd, { "Unix FD", "dbus.type.unix_fd", + FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, }; -#endif static gint *ett[] = { &ett_dbus, - &ett_dbus_hdr, + &ett_dbus_flags, + &ett_dbus_header_field_array, + &ett_dbus_header_field, &ett_dbus_body, - &ett_dbus_field + &ett_dbus_type_array, + &ett_dbus_type_struct, + &ett_dbus_type_variant, + &ett_dbus_type_dict_entry, }; static ei_register_info ei[] = { - { &ei_dbus_value_bool_invalid, { "dbus.value.bool.invalid", PI_PROTOCOL, PI_WARN, "Invalid boolean value", EXPFILL }}, - { &ei_dbus_value_str_invalid, { "dbus.value.str.invalid", PI_PROTOCOL, PI_WARN, "Invalid string (not UTF-8)", EXPFILL }}, - { &ei_dbus_invalid_object_path, { "dbus.invalid_object_path", PI_PROTOCOL, PI_WARN, "Invalid object_path", EXPFILL }}, - { &ei_dbus_invalid_signature, { "dbus.invalid_signature", PI_PROTOCOL, PI_WARN, "Invalid signature", EXPFILL }}, + { &ei_dbus_endianness_invalid, { "dbus.endianness.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid endianness flag", EXPFILL }}, + { &ei_dbus_message_type_invalid, { "dbus.message_type.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid message type", EXPFILL }}, + { &ei_dbus_message_type_unknown, { "dbus.message_type.unknown", + PI_PROTOCOL, PI_WARN, "Unknown message type", EXPFILL }}, + { &ei_dbus_version_invalid, { "dbus.version.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid version", EXPFILL }}, + { &ei_dbus_serial_invalid, { "dbus.serial.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid serial", EXPFILL }}, + { &ei_dbus_field_code_invalid, { "dbus.field_code.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid field code", EXPFILL }}, + { &ei_dbus_required_header_field_missing, { "dbus.required_header_field_missing", + PI_PROTOCOL, PI_ERROR, "Required header field is missing", EXPFILL }}, + { &ei_dbus_padding_invalid, { "dbus.padding.invalid", + PI_PROTOCOL, PI_ERROR, "Padding bytes must be zero", EXPFILL }}, + { &ei_dbus_field_signature_wrong, { "dbus.field_signature_wrong", + PI_PROTOCOL, PI_ERROR, "Wrong header field variant signature", EXPFILL }}, + { &ei_dbus_interface_invalid, { "dbus.interface.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid interface name", EXPFILL }}, + { &ei_dbus_member_invalid, { "dbus.member.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid member name", EXPFILL }}, + { &ei_dbus_error_name_invalid, { "dbus.error_name.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid error name", EXPFILL }}, + { &ei_dbus_bus_name_invalid, { "dbus.bus_name.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid bus name", EXPFILL }}, + { &ei_dbus_type_boolean_invalid, { "dbus.type.boolean.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid boolean value", EXPFILL }}, + { &ei_dbus_string_invalid, { "dbus.type.string.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid string value", EXPFILL }}, + { &ei_dbus_type_signature_invalid, { "dbus.type.signature.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid signature", EXPFILL }}, + { &ei_dbus_type_array_too_long, { "dbus.type.array.too_long", + PI_PROTOCOL, PI_ERROR, "Array too long", EXPFILL }}, + { &ei_dbus_type_array_content_out_of_bounds, { "dbus.type.array.content_out_of_bounds", + PI_PROTOCOL, PI_ERROR, "Array content is out of bounds", EXPFILL }}, + { &ei_dbus_type_object_path_invalid, { "dbus.type.object_path.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid object path", EXPFILL }}, + { &ei_dbus_type_variant_signature_invalid, { "dbus.type.variant.signature.invalid", + PI_PROTOCOL, PI_ERROR, "Invalid variant signature", EXPFILL }}, + { &ei_dbus_nested_too_deeply, { "dbus.nested_too_deeply", + PI_PROTOCOL, PI_ERROR, "Containers nested too deeply", EXPFILL }}, }; expert_module_t *expert_dbus; - int proto_dbus; - - proto_dbus = proto_register_protocol("D-Bus", "D-BUS", "dbus"); - hfi_dbus = proto_registrar_get_nth(proto_dbus); - - proto_register_fields(proto_dbus, hfi, array_length(hfi)); + proto_dbus = proto_register_protocol("D-Bus", "D-Bus", "dbus"); + proto_register_field_array(proto_dbus, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_dbus = expert_register_protocol(proto_dbus); expert_register_field_array(expert_dbus, ei, array_length(ei)); @@ -701,8 +1354,7 @@ proto_register_dbus(void) } void -proto_reg_handoff_dbus(void) -{ +proto_reg_handoff_dbus(void) { dissector_add_uint("wtap_encap", WTAP_ENCAP_DBUS, dbus_handle); dissector_add_for_decode_as_with_preference("tcp.port", dbus_handle_tcp); } |