diff options
author | Anders Broman <anders.broman@ericsson.com> | 2011-11-02 06:30:25 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2011-11-02 06:30:25 +0000 |
commit | e1bdf00529333a51ccaa0c7d6612d9cabeb984dd (patch) | |
tree | 9b85d03dbb7c5924d81be1f495a333b0bcbe6c76 /epan/dissectors/packet-spice.c | |
parent | 4e2c6d9986b81f0965b83625425324d0b7b2ae66 (diff) |
From Yaniv Kaul:
Many enhancements, and some fixes, to the Spice dissector:
- SASL authentication support
- indention, tab fixes
- LZ image dissection (fixing at least one TODO item)
- dissect Spice client agent data
- fix some proto_tree_add_item() offsets
- probably some more that I forgot.
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6535#attach_7355
svn path=/trunk/; revision=39710
Diffstat (limited to 'epan/dissectors/packet-spice.c')
-rw-r--r-- | epan/dissectors/packet-spice.c | 590 |
1 files changed, 435 insertions, 155 deletions
diff --git a/epan/dissectors/packet-spice.c b/epan/dissectors/packet-spice.c index 3e7684aa83..e48efd3d38 100644 --- a/epan/dissectors/packet-spice.c +++ b/epan/dissectors/packet-spice.c @@ -57,6 +57,10 @@ typedef enum { SPICE_TICKET_CLIENT, SPICE_TICKET_SERVER, + SPICE_CLIENT_AUTH_SELECT, + SPICE_SASL_AUTH_LIST, + SPICE_SASL_AUTH, + SPICE_SASL_DATA, SPICE_DATA } spice_session_state_e; @@ -484,13 +488,6 @@ static const value_string spice_error_codes_vs[] = { { 0, NULL } }; -static const value_string spice_common_caps_vs[] = { - { 0, "SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION" }, - { 1, "SPICE_COMMON_CAP_AUTH_SPICE" }, - { 2, "SPICE_COMMON_CAP_AUTH_SASL" }, - { 0, NULL } -}; - /* Inputs channel */ #define SPICEC_INPUTS_KEY_DOWN 101 #define SPICEC_INPUTS_KEY_UP 102 @@ -538,6 +535,9 @@ typedef struct { guint32 connection_id; guint32 num_channel_caps; guint32 destport; + guint32 client_auth; + guint32 server_auth; + guint32 auth_selected; spice_session_state_e next_state; guint8 channel_type; guint8 channel_id; @@ -774,6 +774,22 @@ static const value_string Pixmap_types_vs[] = { { 0, NULL } }; + +#define SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION 0 +#define SPICE_COMMON_CAP_AUTH_SPICE 1 +#define SPICE_COMMON_CAP_AUTH_SASL 2 + +#define SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION_MASK (1 << SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION) /* 0x1 */ +#define SPICE_COMMON_CAP_AUTH_SPICE_MASK (1 << SPICE_COMMON_CAP_AUTH_SPICE) /* 0x2 */ +#define SPICE_COMMON_CAP_AUTH_SASL_MASK (1 << SPICE_COMMON_CAP_AUTH_SASL) /*0x4 */ + +static const value_string spice_auth_select_vs[] = { + { SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION, "Auth Selection" }, + { SPICE_COMMON_CAP_AUTH_SPICE, "Spice" }, + { SPICE_COMMON_CAP_AUTH_SASL, "SASL" }, + { 0, NULL } +}; + /* desegmentation of spice protocol */ static gboolean spice_desegment = TRUE; @@ -784,6 +800,7 @@ static gint ett_link_caps = -1; static gint ett_data = -1; static gint ett_message = -1; static gint ett_ticket_client = -1; +static gint ett_auth_select_client = -1; static gint ett_ticket_server = -1; static gint ett_playback = -1; static gint ett_display_client = -1; @@ -837,13 +854,17 @@ static int hf_data_sublist = -1; static int hf_link_client = -1; static int hf_link_server = -1; static int hf_ticket_client = -1; +static gint hf_auth_select_client = -1; static int hf_ticket_server = -1; static int hf_main_cap = -1; static int hf_display_cap = -1; static int hf_inputs_cap = -1; static int hf_cursor_cap = -1; static int hf_record_cap = -1; -static int hf_common_cap = -1; +static int hf_common_cap_auth = -1; +static int hf_common_cap_auth_select = -1; +static int hf_common_cap_auth_spice = -1; +static int hf_common_cap_auth_sasl = -1; static int hf_playback_cap = -1; static int hf_playback_record_mode_timstamp = -1; static int hf_playback_record_mode = -1; @@ -877,13 +898,14 @@ static int hf_quic_height = -1; static int hf_quic_major_version = -1; static int hf_quic_minor_version = -1; static int hf_quic_type = -1; -static int hf_GLZ_RGB_width = -1; -static int hf_GLZ_RGB_height = -1; +static int hf_LZ_width = -1; +static int hf_LZ_height = -1; static int hf_LZ_major_version = -1; static int hf_LZ_minor_version = -1; -static int hf_GLZ_RGB_type = -1; -static int hf_GLZ_RGB_stride = -1; -static int hf_GLZ_RGB_dict_id = -1; +static int hf_LZ_PLT_type = -1; +static int hf_LZ_RGB_type = -1; +static int hf_LZ_stride = -1; +static int hf_LZ_RGB_dict_id = -1; static int hf_cursor_trail_len = -1; static int hf_cursor_trail_freq = -1; static int hf_cursor_trail_visible = -1; @@ -953,7 +975,7 @@ dissect_Pixmap(tvbuff_t *tvb, proto_tree *tree, guint32 offset) proto_item *ti=NULL; proto_tree *Pixmap_tree; guint32 PixmapSize; - guint32 strides, height/**, pallete_ptr**/; + guint32 strides, height, pallete_ptr; ti = proto_tree_add_text(tree, tvb, offset, 0, "Pixmap"); /* size is fixed later */ Pixmap_tree = proto_item_add_subtree(ti, ett_Pixmap); @@ -969,12 +991,15 @@ dissect_Pixmap(tvbuff_t *tvb, proto_tree *tree, guint32 offset) strides = tvb_get_letohl(tvb, offset); proto_tree_add_item(Pixmap_tree, hf_pixmap_stride, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; - /** pallete_ptr = tvb_get_letohl(tvb, offset); **/ + pallete_ptr = tvb_get_letohl(tvb, offset); proto_tree_add_item(Pixmap_tree, hf_pixmap_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; PixmapSize = height * strides; proto_item_set_len(ti, 18 + PixmapSize); proto_tree_add_text(Pixmap_tree, tvb, offset, PixmapSize, "Pixmap pixels (%d bytes)", PixmapSize); + offset += PixmapSize; + /* FIXME: compute pallete size */ + proto_tree_add_text(Pixmap_tree, tvb, offset, 0, "Pallete (offset from message start - %u)", pallete_ptr); /*TODO: complete pixmap dissection */ return PixmapSize + 18; @@ -1113,19 +1138,20 @@ dissect_ImageQuic(tvbuff_t *tvb, proto_tree *tree, guint32 offset) offset += 2; proto_tree_add_item(ImageQuic_tree, hf_quic_minor_version, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; - proto_tree_add_item(ImageQuic_tree, hf_quic_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(ImageQuic_tree, hf_quic_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; - proto_tree_add_item(ImageQuic_tree, hf_quic_width, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(ImageQuic_tree, hf_quic_width, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; - proto_tree_add_item(ImageQuic_tree, hf_quic_height, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(ImageQuic_tree, hf_quic_height, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; - proto_tree_add_text(ImageQuic_tree, tvb, offset , QuicSize - 20, "QUIC compressed image data (%u bytes)", QuicSize); + proto_tree_add_text(ImageQuic_tree, tvb, offset, QuicSize - 20, "QUIC compressed image data (%u bytes)", QuicSize); } return QuicSize + 4; } + static void -dissect_ImageLZ_common(tvbuff_t *tvb, proto_tree *tree, const guint32 offset) +dissect_ImageLZ_common_header(tvbuff_t *tvb, proto_tree *tree, const guint32 offset) { proto_tree_add_text(tree, tvb, offset, 4, "LZ magic (\" ZL\")"); @@ -1133,6 +1159,52 @@ dissect_ImageLZ_common(tvbuff_t *tvb, proto_tree *tree, const guint32 offset) proto_tree_add_item(tree, hf_LZ_minor_version, tvb, offset + 6, 2, ENC_BIG_ENDIAN); } +static void +dissect_ImageLZ_common(tvbuff_t *tvb, proto_tree *tree, guint32 offset, const gboolean IsLZ, const guint32 size) +{ + + guint8 type; + + dissect_ImageLZ_common_header(tvb, tree, offset); + offset += 8; + + if (IsLZ) + offset +=3; /* alignment in LZ? Does not exist in GLZ?*/ + + proto_tree_add_item(tree, hf_LZ_RGB_type, tvb, offset, 1, ENC_NA); + type = tvb_get_guint8(tvb, offset); + offset += 1; + switch (type & 0xf) { /* 0xf is the MASK */ + case LZ_IMAGE_TYPE_RGB16: + case LZ_IMAGE_TYPE_RGB32: + proto_tree_add_item(tree, hf_LZ_width, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_LZ_height, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_LZ_stride, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_LZ_RGB_dict_id, tvb, offset, 8, ENC_BIG_ENDIAN); + offset += 8; + proto_tree_add_text(tree, tvb, offset , size - 29, "LZ_RGB compressed image data (%u bytes)", size - 29); + break; + case LZ_IMAGE_TYPE_RGBA: + offset += 2; + break; + default: + g_warning("dissecting default LZ image"); + proto_tree_add_item(tree, hf_LZ_width, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_LZ_height, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_LZ_stride, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_LZ_RGB_dict_id, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + proto_tree_add_text(tree, tvb, offset , size - 30, "LZ_RGB compressed image data (%u bytes)", size - 30); + break; + } +} + static guint32 dissect_ImageLZ_JPEG(tvbuff_t *tvb, proto_tree *tree, const guint32 offset) { @@ -1144,14 +1216,14 @@ dissect_ImageLZ_JPEG(tvbuff_t *tvb, proto_tree *tree, const guint32 offset) ti = proto_tree_add_text(tree, tvb, offset, LZ_JPEGSize + 4, "LZ_JPEG Image"); LZ_JPEG_tree = proto_item_add_subtree(ti, ett_LZ_JPEG); proto_tree_add_text(LZ_JPEG_tree, tvb, offset, 4, "LZ JPEG image size: %u bytes", LZ_JPEGSize); - dissect_ImageLZ_common(tvb, LZ_JPEG_tree, offset + 4); + dissect_ImageLZ_common_header(tvb, LZ_JPEG_tree, offset + 4); } return offset + 12 ; } static guint32 -dissect_ImageGLZ_RGB(tvbuff_t *tvb, proto_tree *tree, guint32 offset, const guint32 size, gboolean zlib_compressed) +dissect_ImageGLZ_RGB(tvbuff_t *tvb, proto_tree *tree, guint32 offset, const guint32 size) { proto_item *ti=NULL; proto_tree *GLZ_RGB_tree; @@ -1168,32 +1240,8 @@ dissect_ImageGLZ_RGB(tvbuff_t *tvb, proto_tree *tree, guint32 offset, const guin ti = proto_tree_add_text(tree, tvb, offset, GLZ_RGBSize, "GLZ_RGB Image"); GLZ_RGB_tree = proto_item_add_subtree(ti, ett_GLZ_RGB); } - if (tree) { - dissect_ImageLZ_common(tvb, GLZ_RGB_tree, offset); - offset += 8; - -/* FIXME: this disregards the possible encoding within the type, so currently the type is sometimes wrong. From server/glz_encoder.c: - if (top_down) { - encode(encoder, (type & LZ_IMAGE_TYPE_MASK) | (1 << LZ_IMAGE_TYPE_LOG)); - } else { - encode(encoder, (type & LZ_IMAGE_TYPE_MASK)); - } -*/ - proto_tree_add_item(GLZ_RGB_tree, hf_GLZ_RGB_type, tvb, offset, 2, ENC_LITTLE_ENDIAN); - offset += 2; - if (!zlib_compressed) - offset += 2; /* TODO: in ZLIB_GLZ_RGB, there are two extra bytes here! Understand why, but for the time being, hop over them. */ - proto_tree_add_item(GLZ_RGB_tree, hf_GLZ_RGB_width, tvb, offset, 4, ENC_LITTLE_ENDIAN); - offset += 4; - proto_tree_add_item(GLZ_RGB_tree, hf_GLZ_RGB_height, tvb, offset, 4, ENC_LITTLE_ENDIAN); - offset += 4; - proto_tree_add_item(GLZ_RGB_tree, hf_GLZ_RGB_stride, tvb, offset, 4, ENC_LITTLE_ENDIAN); - offset += 4; - proto_tree_add_item(GLZ_RGB_tree, hf_GLZ_RGB_dict_id, tvb, offset, 8, ENC_LITTLE_ENDIAN); - offset += 8; - proto_tree_add_text(GLZ_RGB_tree, tvb, offset , GLZ_RGBSize - 30, "GLZ_RGB compressed image data (%u bytes)", GLZ_RGBSize - 30); - } + dissect_ImageLZ_common(tvb, GLZ_RGB_tree, offset, FALSE, GLZ_RGBSize); return GLZ_RGBSize + 4; } @@ -1205,40 +1253,12 @@ dissect_ImageLZ_RGB(tvbuff_t *tvb, proto_tree *tree, guint32 offset) proto_tree *LZ_RGB_tree; const guint32 LZ_RGBSize = tvb_get_letohl(tvb, offset); - if (tree) { - ti = proto_tree_add_text(tree, tvb, offset, LZ_RGBSize + 4, "LZ_RGB Image"); - LZ_RGB_tree = proto_item_add_subtree(ti, ett_LZ_RGB); - proto_tree_add_text(LZ_RGB_tree, tvb, offset, 4, "LZ RGB image size: %u bytes", LZ_RGBSize); - offset += 4; - dissect_ImageLZ_common(tvb, LZ_RGB_tree, offset); - offset += 8; - -/* FIXME: this disregards the possible encoding within the type, so currently the type is sometimes wrong. From server/glz_encoder.c: - if (top_down) { - encode(encoder, (type & LZ_IMAGE_TYPE_MASK) | (1 << LZ_IMAGE_TYPE_LOG)); - } else { - encode(encoder, (type & LZ_IMAGE_TYPE_MASK)); - } -*/ - offset += 2; /* TODO: not sure we need this! Understand what this is */ - proto_tree_add_item(LZ_RGB_tree, hf_GLZ_RGB_type, tvb, offset, 2, ENC_BIG_ENDIAN); - offset += 2; - /*FIXME: sometimes width is incorrect (bitmask?) */ - proto_tree_add_item(LZ_RGB_tree, hf_GLZ_RGB_width, tvb, offset, 4, ENC_BIG_ENDIAN); - offset += 4; - proto_tree_add_item(LZ_RGB_tree, hf_GLZ_RGB_height, tvb, offset, 4, ENC_BIG_ENDIAN); - offset += 4; - proto_tree_add_item(LZ_RGB_tree, hf_GLZ_RGB_stride, tvb, offset, 4, ENC_BIG_ENDIAN); - offset += 4; - proto_tree_add_item(LZ_RGB_tree, hf_GLZ_RGB_dict_id, tvb, offset, 8, ENC_LITTLE_ENDIAN); - offset += 8; + ti = proto_tree_add_text(tree, tvb, offset, LZ_RGBSize + 4, "LZ_RGB Image"); + LZ_RGB_tree = proto_item_add_subtree(ti, ett_LZ_RGB); + proto_tree_add_text(LZ_RGB_tree, tvb, offset, 4, "LZ RGB image size: %u bytes", LZ_RGBSize); + offset += 4; - /*TODO: show win_head_image_dist - not sure what it stands for though - * proto_tree_add_item(LZ_RGB_tree, hf_GLZ_RGB_win_head_image_dist, tvb, offset, 4, ENC_LITTLE_ENDIAN); - * offset +=4; - * */ - proto_tree_add_text(LZ_RGB_tree, tvb, offset , LZ_RGBSize - 30, "LZ_RGB compressed image data (%u bytes)", LZ_RGBSize); - } + dissect_ImageLZ_common(tvb, LZ_RGB_tree, offset, TRUE, LZ_RGBSize); return LZ_RGBSize + 4; } @@ -1248,26 +1268,43 @@ dissect_ImageLZ_PLT(tvbuff_t *tvb, proto_tree *tree, guint32 offset) { proto_item *ti=NULL; proto_tree *LZ_PLT_tree; - guint32 LZ_PLTSize, somesize; + guint32 LZ_PLTSize, pal_size; - /* TODO: const guint8 flags = tvb_get_guint8(tvb, offset); dissect and present */ + const guint32 current_offset = offset; - LZ_PLTSize = tvb_get_letohl(tvb, offset + 1); - ti = proto_tree_add_text(tree, tvb, offset, LZ_PLTSize + 5, "LZ_PLT Image"); + LZ_PLTSize = tvb_get_letohl(tvb, offset + 1); /* for some reason, it reports two extra bytes */ + ti = proto_tree_add_text(tree, tvb, offset, (LZ_PLTSize - 2)+ 1 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 4, "LZ_PLT Image"); LZ_PLT_tree = proto_item_add_subtree(ti, ett_LZ_PLT); - proto_tree_add_text(LZ_PLT_tree, tvb, offset, 1, "Flag"); + proto_tree_add_text(LZ_PLT_tree, tvb, offset, 1, "LZ_PLT Flag"); /* TODO: dissect */ offset += 1; - proto_tree_add_text(LZ_PLT_tree, tvb, offset, 4, "LZ PLT image size: %u bytes", LZ_PLTSize); + proto_tree_add_text(LZ_PLT_tree, tvb, offset, 4, "LZ PLT image size: %u bytes (2 extra bytes?)", LZ_PLTSize); + offset += 4; + + pal_size = tvb_get_letohl(tvb, offset); + proto_tree_add_text(LZ_PLT_tree, tvb, offset, 4, "pallete offset: %u bytes (current offset: %u)", pal_size, offset); /* TODO: not sure it's correct */ offset += 4; - somesize = tvb_get_letohl(tvb, offset); - proto_tree_add_text(LZ_PLT_tree, tvb, offset, 4, "Some other size: %u", somesize); - offset += 4; /* FIXME - pal pallete value? offset? */ - dissect_ImageLZ_common(tvb, LZ_PLT_tree, offset); + + dissect_ImageLZ_common_header(tvb, LZ_PLT_tree, offset); offset += 8; - /* TODO - complete dissection */ - return 1 + 4 + 4 + 8 + 8 + LZ_PLTSize; + proto_tree_add_item(LZ_PLT_tree, hf_LZ_PLT_type, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(LZ_PLT_tree, hf_LZ_width, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(LZ_PLT_tree, hf_LZ_height, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_item(LZ_PLT_tree, hf_LZ_stride, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + proto_tree_add_text(LZ_PLT_tree, tvb, offset, 4, "topdown flag: %d", tvb_get_ntohl(tvb, offset)); + offset += 4; + proto_tree_add_text(LZ_PLT_tree, tvb, offset, (LZ_PLTSize - 2), "LZ_PLT data (%u bytes)", (LZ_PLTSize - 2)); + offset += (LZ_PLTSize - 2); + /* TODO: + * proto_tree_add_text(LZ_PLT_tree, tvb, offset, pal_size, "palette (%u bytes)" , pal_size); + * offset += pal_size; + */ + return offset - current_offset; } @@ -1332,7 +1369,7 @@ dissect_ImageZLIB_GLZ_stream(tvbuff_t *tvb, proto_tree *ZLIB_GLZ_tree, packet_in if (uncompressed_tvb != NULL) { add_new_data_source(pinfo, uncompressed_tvb, "Uncompressed GLZ stream"); Uncomp_tree = proto_item_add_subtree(ti, ett_Uncomp_tree); - dissect_ImageGLZ_RGB(uncompressed_tvb, Uncomp_tree, 0, ZLIB_uncompSize, TRUE); + dissect_ImageGLZ_RGB(uncompressed_tvb, Uncomp_tree, 0, ZLIB_uncompSize); } else { proto_tree_add_text(ZLIB_GLZ_tree, tvb, offset, -1, "Error: Unable to decompress content"); } @@ -1383,7 +1420,7 @@ dissect_Image(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, guint32 offse ImageSize = dissect_ImageQuic(tvb, tree, offset); break; case IMAGE_TYPE_GLZ_RGB: - ImageSize = dissect_ImageGLZ_RGB(tvb, tree, offset, 0, FALSE); + ImageSize = dissect_ImageGLZ_RGB(tvb, tree, offset, 0); break; case IMAGE_TYPE_LZ_RGB: ImageSize = dissect_ImageLZ_RGB(tvb, tree, offset); @@ -1693,11 +1730,11 @@ dissect_spice_data_header(tvbuff_t *tvb, proto_tree *tree, const spice_conversat *sublist_size = tvb_get_letohl(tvb, offset + 14); if (tree) { - proto_tree_add_item(tree, hf_serial, tvb, offset, 8, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_serial, tvb, offset, 8, ENC_LITTLE_ENDIAN); offset += 8; proto_tree_add_text(tree, tvb, offset, 2, "Message type: %s (%d)", get_message_type_string(message_type, spice_info, client_message), message_type); offset += 2; - proto_tree_add_item(tree, hf_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(tree, hf_data_sublist, tvb, offset, 4, ENC_LITTLE_ENDIAN); } @@ -1958,7 +1995,7 @@ dissect_spice_display_server(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo proto_tree_add_item(tree, hf_display_rop_descriptor, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; - proto_tree_add_item(tree, hf_display_scale_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_display_scale_mode, tvb, offset, 1, ENC_NA); offset += 1; offset += dissect_Mask(tvb, tree, offset); @@ -2033,7 +2070,6 @@ dissect_spice_display_server(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo if (clip_type == CLIP_TYPE_RECTS) { offset += dissect_RectList(tvb, tree, offset); } - break; case SPICE_DISPLAY_STREAM_DATA: data_size = tvb_get_letohl(tvb, offset + 8); @@ -2075,7 +2111,6 @@ dissect_spice_display_server(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo proto_tree_add_text(tree, tvb, offset, 0, "Unknown display server message - cannot dissect"); break; } - return offset; } @@ -2188,35 +2223,35 @@ dissect_spice_agent_message(tvbuff_t *tvb, proto_tree *tree, const guint32 messa switch (message_type) { case VD_AGENT_MOUSE_STATE: ti = proto_tree_add_text(tree, tvb, offset, 4, "VD_AGENT_MOUSE_STATE message"); - agent_tree = proto_item_add_subtree(ti, ett_spice_agent); offset += 4; break; case VD_AGENT_MONITORS_CONFIG: ti = proto_tree_add_text(tree, tvb, offset, 4, "VD_AGENT_MONITORS_CONFIG message"); - agent_tree = proto_item_add_subtree(ti, ett_spice_agent); offset += 4; break; case VD_AGENT_REPLY: ti = proto_tree_add_text(tree, tvb, offset, 8, "VD_AGENT_REPLY message"); + /* TODO: complete dissection agent_tree = proto_item_add_subtree(ti, ett_spice_agent); - /* TODO: complete dissection */ + */ offset += 8; break; case VD_AGENT_CLIPBOARD: ti = proto_tree_add_text(tree, tvb, offset, message_len, "VD_AGENT_CLIPBOARD message"); + /* TODO: display string agent_tree = proto_item_add_subtree(ti, ett_spice_agent); - /*TODO: display string */ + */ offset += message_len; break; case VD_AGENT_DISPLAY_CONFIG: ti = proto_tree_add_text(tree, tvb, offset, 4, "VD_AGENT_DISPLAY_CONFIG message"); - agent_tree = proto_item_add_subtree(ti, ett_spice_agent); offset += 4; break; case VD_AGENT_ANNOUNCE_CAPABILITIES: ti = proto_tree_add_text(tree, tvb, offset, 8, "VD_AGENT_ANNOUNCE_CAPABILITIES message"); + /* TODO: complete dissection agent_tree = proto_item_add_subtree(ti, ett_spice_agent); - /* TODO: complete dissection */ + */ offset += 8; break; case VD_AGENT_CLIPBOARD_GRAB: @@ -2239,10 +2274,9 @@ dissect_spice_agent_message(tvbuff_t *tvb, proto_tree *tree, const guint32 messa break; case VD_AGENT_CLIPBOARD_RELEASE: ti = proto_tree_add_text(tree, tvb, offset, 0, "VD_AGENT_CLIPBOARD_RELEASE message"); - agent_tree = proto_item_add_subtree(ti, ett_spice_agent); break; default: - proto_tree_add_text(tree, tvb, offset, 0, "Unknown agent message - cannot dissect"); + proto_tree_add_text(tree, tvb, offset, 0, "Unknown agent message (%u) - cannot dissect", message_type); break; } return offset; @@ -2326,17 +2360,21 @@ dissect_spice_main_client(tvbuff_t *tvb, proto_tree *tree, const guint16 message { proto_item *ti=NULL; proto_tree *main_tree; + guint32 agent_msg_type, agent_msg_len; switch(message_type) { case SPICEC_MAIN_MOUSE_MODE_REQUEST: ti = proto_tree_add_text(tree, tvb, offset, 4, "Client MOUSE_MODE_REQUEST message"); + /* TODO: complete dissection - mouse_mode, 2 bytes main_tree = proto_item_add_subtree(ti, ett_main_client); - /* TODO: mouse_mode , 2 bytes. */ + */ offset += 2; break; case SPICEC_MAIN_ATTACH_CHANNELS: ti = proto_tree_add_text(tree, tvb, offset, 4, "Client MAIN_ATTACH_CHANNEL message"); + /* TODO: complete dissection main_tree = proto_item_add_subtree(ti, ett_main_client); + */ break; case SPICEC_MAIN_AGENT_START: ti = proto_tree_add_text(tree, tvb, offset, 4, "Client AGENT_START message"); @@ -2344,6 +2382,19 @@ dissect_spice_main_client(tvbuff_t *tvb, proto_tree *tree, const guint16 message proto_tree_add_item(main_tree, hf_main_client_agent_tokens, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; break; + case SPICEC_MAIN_AGENT_DATA: + proto_tree_add_item(tree, hf_agent_protocol, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(tree, hf_agent_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); + agent_msg_type = tvb_get_letohl(tvb, offset); + offset += 4; + proto_tree_add_item(tree, hf_agent_opaque, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; + proto_tree_add_item(tree, hf_agent_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); + agent_msg_len = tvb_get_letohl(tvb, offset); + offset += 4; + offset = dissect_spice_agent_message(tvb, tree, agent_msg_type, agent_msg_len, offset); + break; default: proto_tree_add_text(tree, tvb, offset, 0, "Unknown main client message - cannot dissect"); break; @@ -2358,14 +2409,18 @@ dissect_spice_inputs_client(tvbuff_t *tvb, proto_tree *tree, const guint16 messa proto_tree *inputs_tree; switch(message_type) { - case SPICEC_INPUTS_KEY_DOWN: /*TODO: complete dissection*/ + case SPICEC_INPUTS_KEY_DOWN: ti = proto_tree_add_text(tree, tvb, offset, 4, "Client KEY_DOWN message"); + /* TODO: complete dissection inputs_tree = proto_item_add_subtree(ti, ett_inputs_client); + */ offset += 4; break; case SPICEC_INPUTS_KEY_UP: ti = proto_tree_add_text(tree, tvb, offset, 4, "Client KEY_UP message"); + /* TODO: complete dissection inputs_tree = proto_item_add_subtree(ti, ett_inputs_client); + */ offset += 4; break; case SPICEC_INPUTS_KEY_MODIFIERS: @@ -2397,7 +2452,7 @@ dissect_spice_inputs_client(tvbuff_t *tvb, proto_tree *tree, const guint16 messa inputs_tree = proto_item_add_subtree(ti, ett_inputs_client); proto_tree_add_item(inputs_tree, hf_button_state, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; - proto_tree_add_item(inputs_tree, hf_mouse_display_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(inputs_tree, hf_mouse_display_id, tvb, offset, 1, ENC_NA); offset += 1; break; case SPICEC_INPUTS_MOUSE_RELEASE: @@ -2405,7 +2460,7 @@ dissect_spice_inputs_client(tvbuff_t *tvb, proto_tree *tree, const guint16 messa inputs_tree = proto_item_add_subtree(ti, ett_inputs_client); proto_tree_add_item(inputs_tree, hf_button_state, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; - proto_tree_add_item(inputs_tree, hf_mouse_display_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(inputs_tree, hf_mouse_display_id, tvb, offset, 1, ENC_NA); offset += 1; break; default: @@ -2451,7 +2506,7 @@ dissect_spice_data_server_pdu(tvbuff_t *tvb, proto_tree *tree, packet_info *pinf msg_ti = proto_tree_add_text(tree, tvb, offset, 0, "%s (%d bytes)", get_message_type_string(message_type, spice_info, FALSE), message_size + sizeof_SpiceDataHeader); message_tree = proto_item_add_subtree(msg_ti, ett_message); - ti = proto_tree_add_item(message_tree, hf_data, tvb, 0, sizeof_SpiceDataHeader, ENC_NA); + ti = proto_tree_add_item(message_tree, hf_data, tvb, offset, sizeof_SpiceDataHeader, ENC_NA); data_header_tree = proto_item_add_subtree(ti, ett_data); dissect_spice_data_header(tvb, data_header_tree, spice_info, FALSE, message_type, &sublist_size, offset); @@ -2459,7 +2514,7 @@ dissect_spice_data_server_pdu(tvbuff_t *tvb, proto_tree *tree, packet_info *pinf offset += sizeof_SpiceDataHeader; old_offset = offset; - col_append_fstr(pinfo->cinfo, COL_INFO, "%s", get_message_type_string(message_type, spice_info, FALSE)); + col_append_str(pinfo->cinfo, COL_INFO, get_message_type_string(message_type, spice_info, FALSE)); if (message_type < SPICE_FIRST_AVAIL_MESSAGE) { /* this is a common message */ offset = dissect_spice_common_server_messages(tvb, message_tree, message_type, offset, total_message_size - sizeof_SpiceDataHeader); return offset; @@ -2493,8 +2548,7 @@ dissect_spice_data_server_pdu(tvbuff_t *tvb, proto_tree *tree, packet_info *pinf } if((offset - old_offset) != message_size) { - /* This means we have not dissected the complete message. Would be nice to fix */ - /* DBG3("dissect_spice_data_server_pdu() - FIXME:message %u in packet %d was not fully dissected (offset 0x%x).\r\n", message_type, pinfo->fd->num, offset); */ + g_warning("dissect_spice_data_server_pdu() - FIXME:message type %s (%u) in packet %d was not fully dissected - dissected %d (offset %d [0x%x], total message size: %d).\r\n", get_message_type_string(message_type, spice_info, FALSE), message_type, pinfo->fd->num, offset - old_offset, offset, offset, message_size + sizeof_SpiceDataHeader); offset = old_offset + message_size; } @@ -2509,14 +2563,14 @@ dissect_spice_data_client_pdu(tvbuff_t *tvb, proto_tree *tree, packet_info *pinf guint16 message_type; guint32 /** message_size,**/ sublist_size; - ti = proto_tree_add_item(tree, hf_data, tvb, 0, sizeof_SpiceDataHeader, ENC_NA); + ti = proto_tree_add_item(tree, hf_data, tvb, offset, sizeof_SpiceDataHeader, ENC_NA); data_header_tree = proto_item_add_subtree(ti, ett_data); message_type = tvb_get_letohs(tvb, offset + 8); /** message_size = tvb_get_letohl(tvb, offset + 10); **/ dissect_spice_data_header(tvb, data_header_tree, spice_info, TRUE, message_type, &sublist_size, offset); - col_append_fstr(pinfo->cinfo, COL_INFO, "%s", get_message_type_string(message_type, spice_info, TRUE)); + col_append_str(pinfo->cinfo, COL_INFO, get_message_type_string(message_type, spice_info, TRUE)); offset += sizeof_SpiceDataHeader; /* TODO: deal with sub-messages list first. As implementation does not uses sub-messsages list yet, it cannot be implemented in the dissector yet.*/ @@ -2561,13 +2615,31 @@ dissect_spice_link_common_header(tvbuff_t *tvb, proto_tree *tree) } static void -dissect_spice_common_capabilities(tvbuff_t *tvb, proto_tree *tree, guint32 offset, const int caps_len) +dissect_spice_common_capabilities(tvbuff_t *tvb, proto_tree *tree, guint32 offset, const int caps_len, spice_conversation_t *spice_info, gboolean is_client) { /* TODO: save common and per-channel capabilities in spice_info ? */ int i; + guint32 val; for(i = 0; i != caps_len ; i++) { - proto_tree_add_item(tree, hf_common_cap, tvb, offset, 4, ENC_LITTLE_ENDIAN); - offset += 4; + val = tvb_get_letohl(tvb, offset); + switch (i) { + case 0: /* Authentication */ + if (is_client) { + spice_info->client_auth = val; + } else { + spice_info->server_auth = val; + } + proto_tree_add_item(tree, hf_common_cap_auth, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_boolean(tree, hf_common_cap_auth_select, tvb, offset, 4, val); + proto_tree_add_boolean(tree, hf_common_cap_auth_spice, tvb, offset, 4, val); + proto_tree_add_boolean(tree, hf_common_cap_auth_sasl, tvb, offset, 4, val); + offset += 4; + break; + default: + proto_tree_add_text(tree, tvb, offset, 4, "Unknown common capability"); + offset += 4; + break; + } } } @@ -2623,14 +2695,14 @@ dissect_spice_link_client_pdu(tvbuff_t *tvb, proto_tree *tree, spice_conversatio offset = sizeof_SpiceLinkHeader; if (tree) { - proto_tree_add_item(tree, hf_conn_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); - proto_tree_add_item(tree, hf_channel_type, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(tree, hf_channel_id, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_conn_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_channel_type, tvb, offset + 4, 1, ENC_NA); + proto_tree_add_item(tree, hf_channel_id, tvb, offset + 5, 1, ENC_NA); - proto_tree_add_item(tree, hf_num_common_caps, tvb, offset + 6, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_num_common_caps, tvb, offset + 6, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(tree, hf_num_channel_caps, tvb, offset + 10, 4, ENC_LITTLE_ENDIAN); - proto_tree_add_item(tree, hf_caps_offset, tvb, offset + 14, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_caps_offset, tvb, offset + 14, 4, ENC_LITTLE_ENDIAN); } common_caps_len = tvb_get_letohl(tvb, offset + 6); @@ -2644,7 +2716,8 @@ dissect_spice_link_client_pdu(tvbuff_t *tvb, proto_tree *tree, spice_conversatio if (common_caps_len > 0) { ti = proto_tree_add_text(tree, tvb, offset, common_caps_len * 4, "Common Capabilities (%d bytes)", common_caps_len * 4); /* caps_len multiplied by 4 as length is in UINT32 units */ caps_tree = proto_item_add_subtree(ti, ett_link_caps); - /* TODO: dissect common capabilities */ + caps_tree = proto_item_add_subtree(ti, ett_link_caps); + dissect_spice_common_capabilities(tvb, caps_tree, offset, common_caps_len, spice_info, TRUE); offset += (common_caps_len * 4); } if (channel_caps_len > 0) { @@ -2673,12 +2746,12 @@ dissect_spice_link_server_pdu(tvbuff_t *tvb, proto_tree *tree, spice_conversatio offset = sizeof_SpiceLinkHeader; if (tree) { - proto_tree_add_item(tree, hf_error_code, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_error_code, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_text(tree, tvb, offset + 4, SPICE_TICKET_PUBKEY_BYTES, "X.509 SubjectPublicKeyInfo (ASN.1)"); - proto_tree_add_item(tree, hf_num_common_caps, tvb, offset + 4 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN); - proto_tree_add_item(tree, hf_num_channel_caps, tvb, offset + 8 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_num_common_caps, tvb, offset + 4 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_num_channel_caps, tvb, offset + 8 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN); - proto_tree_add_item(tree, hf_caps_offset, tvb, offset + 12 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_caps_offset, tvb, offset + 12 + SPICE_TICKET_PUBKEY_BYTES, 4, ENC_LITTLE_ENDIAN); } common_caps_len = tvb_get_letohl(tvb, offset + 4 + SPICE_TICKET_PUBKEY_BYTES); @@ -2688,8 +2761,8 @@ dissect_spice_link_server_pdu(tvbuff_t *tvb, proto_tree *tree, spice_conversatio if (common_caps_len > 0) { ti = proto_tree_add_text(tree, tvb, offset, common_caps_len * 4, "Common Capabilities (%d bytes)", common_caps_len * 4); /* caps_len multiplied by 4 as length is in UINT32 units */ caps_tree = proto_item_add_subtree(ti, ett_link_caps); - dissect_spice_common_capabilities(tvb, caps_tree, offset, common_caps_len); - offset += (common_caps_len *4); + dissect_spice_common_capabilities(tvb, caps_tree, offset, common_caps_len, spice_info, FALSE); + offset += (common_caps_len * 4); } if (channel_caps_len > 0) { ti = proto_tree_add_text(tree, tvb, offset, channel_caps_len * 4, "Channel Capabilities (%d bytes)", channel_caps_len * 4); /* caps_len multiplied by 4 as length is in UINT32 units */ @@ -2708,10 +2781,11 @@ dissect_spice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) guint32 avail; guint32 pdu_len = 0; guint32 offset; + guint8 sasl_result; proto_item *ti=NULL; proto_tree *spice_tree=NULL; proto_tree *spice_data_tree=NULL; - + gboolean server_sasl_list=FALSE, client_sasl_list=FALSE, client_out_list=FALSE; gboolean first_record_in_frame; conversation = find_or_create_conversation(pinfo); @@ -2722,6 +2796,8 @@ dissect_spice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) spice_info->destport = pinfo->destport; spice_info->channel_type = SPICE_CHANNEL_NONE; spice_info->next_state = SPICE_LINK_CLIENT; + spice_info->client_auth = 0; + spice_info->server_auth = 0; conversation_add_proto_data(conversation, proto_spice, spice_info); } @@ -2751,7 +2827,7 @@ dissect_spice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } col_set_str(pinfo->cinfo, COL_INFO, "Client link message"); if (tree) { - ti = proto_tree_add_item(tree, proto_spice, tvb, 0, -1, ENC_NA); + ti = proto_tree_add_item(tree, proto_spice, tvb, 0, pdu_len, ENC_NA); spice_tree = proto_item_add_subtree(ti, ett_spice); } dissect_spice_link_client_pdu(tvb, spice_tree, spice_info); @@ -2775,11 +2851,185 @@ dissect_spice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) col_set_str(pinfo->cinfo, COL_INFO, "Server link message"); col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown")); if (tree) { - ti = proto_tree_add_item(tree, proto_spice, tvb, 0, -1, ENC_NA); + ti = proto_tree_add_item(tree, proto_spice, tvb, 0, pdu_len, ENC_NA); spice_tree = proto_item_add_subtree(ti, ett_spice); } dissect_spice_link_server_pdu(tvb, spice_tree, spice_info); - spice_info->next_state = SPICE_TICKET_CLIENT; + if (!(spice_info->server_auth & SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION_MASK) || !(spice_info->client_auth & SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION_MASK)) { /* Server or clients support spice ticket auth only */ + spice_info->next_state = SPICE_TICKET_CLIENT; + } else { /* Protocol selection between client and server */ + spice_info->next_state = SPICE_CLIENT_AUTH_SELECT; + } + return pdu_len; + break; + case SPICE_CLIENT_AUTH_SELECT: + if (spice_info->destport != pinfo->destport) /* ignore anything from the server, wait for data from client */ + break; + avail = tvb_reported_length(tvb); + pdu_len = 4; + if (avail < pdu_len) { + pinfo->desegment_offset = 0; + pinfo->desegment_len = pdu_len - avail; + return avail; + } + col_set_str(pinfo->cinfo, COL_INFO, "Authentication Selection"); + col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown")); + if (tree) { + ti = proto_tree_add_item(tree, proto_spice, tvb, 0, 4, ENC_NA); + spice_tree = proto_item_add_subtree(ti, ett_auth_select_client); + proto_tree_add_item(spice_tree, hf_auth_select_client, tvb, 0, 4, ENC_LITTLE_ENDIAN); + } + spice_info->auth_selected = tvb_get_letohl(tvb, 0); + switch(spice_info->auth_selected) { + case SPICE_COMMON_CAP_AUTH_SPICE: + spice_info->next_state = SPICE_TICKET_CLIENT; + break; + case SPICE_COMMON_CAP_AUTH_SASL: + spice_info->next_state = SPICE_SASL_AUTH_LIST; + break; + default: + g_warning("unknown authentication selected"); + break; + } + return 4; + break; + case SPICE_SASL_AUTH_LIST: + offset = 0; + avail = tvb_reported_length(tvb); + pdu_len = 4; + if (avail < pdu_len) { + pinfo->desegment_offset = 0; + pinfo->desegment_len = pdu_len - avail; + return offset; + } + pdu_len = tvb_get_letohl(tvb, offset); /* the length of the following messages */ + if (tree && spice_tree == NULL) { + ti = proto_tree_add_item(tree, proto_spice, tvb, offset, pdu_len, ENC_NA); + spice_tree = proto_item_add_subtree(ti, ett_spice); + } + proto_tree_add_text(spice_tree, tvb, offset, 4, "SASL message length: %u", pdu_len); + if (pdu_len == 0) { /* meaning, empty PDU - probably the client_out_list, which may be empty*/ + spice_info->next_state = SPICE_SASL_AUTH; + client_out_list = TRUE; + return 4; /* only the size field.*/ + } else { + pdu_len += 4; + proto_item_set_len(ti, pdu_len); + } + if (avail < pdu_len) { /* didn't get the complete PDU, returning */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = pdu_len - avail; + return offset; + } + col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown")); + + if (spice_info->destport == pinfo->destport) { + if (client_sasl_list == FALSE) { + client_sasl_list = TRUE; + col_set_str(pinfo->cinfo, COL_INFO, "Selected mechanism by client"); + proto_tree_add_text(spice_tree, tvb, offset, 4, "Selected mechanism length: %u", pdu_len - 4); + offset += 4; + proto_tree_add_text(spice_tree, tvb, offset, pdu_len - 4, "Selected mechanism: %s", tvb_format_text(tvb, offset, pdu_len - 4)); + } else { /* this is the client out list */ + client_out_list = TRUE; + col_set_str(pinfo->cinfo, COL_INFO, "Client out mechanism by client"); + proto_tree_add_text(spice_tree, tvb, offset, 4, "Client out mechanism length: %u", pdu_len - 4); + offset += 4; + proto_tree_add_text(spice_tree, tvb, offset, pdu_len - 4, "Client out mechanism"); + } + } else { /* server side */ + server_sasl_list = TRUE; + col_set_str(pinfo->cinfo, COL_INFO, "Supported mechanisms"); + proto_tree_add_text(spice_tree, tvb, offset, 4, "Supported mechanisms list length: %u", pdu_len - 4); + offset += 4; + proto_tree_add_text(spice_tree, tvb, offset, pdu_len - 4, "Supported mechanisms list: %s", tvb_format_text(tvb, offset, pdu_len -4)); + } + if (client_sasl_list && server_sasl_list && client_out_list) {/* if we've seen client response, move to the next state. */ + spice_info->next_state = SPICE_SASL_AUTH; + } + return pdu_len; + break; + case SPICE_SASL_AUTH: + offset = 0; + avail = tvb_reported_length(tvb); + if (avail == 1) { + sasl_result = tvb_get_guint8(tvb, offset); + if (tree && spice_tree == NULL) { + ti = proto_tree_add_item(tree, proto_spice, tvb, offset, 1, ENC_NA); + spice_tree = proto_item_add_subtree(ti, ett_spice); + } + col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown")); + col_set_str(pinfo->cinfo, COL_INFO, "SASL authentication - result"); + proto_tree_add_text(spice_tree, tvb, offset, 1, "SASL result: %u", sasl_result); + return 1; + } + pdu_len = 4; + if (avail < pdu_len) { + pinfo->desegment_offset = 0; + pinfo->desegment_len = pdu_len - avail; + return offset; + } + + pdu_len = tvb_get_letohl(tvb, offset); /* the length of the following messages */ + if (tree && spice_tree == NULL) { + ti = proto_tree_add_item(tree, proto_spice, tvb, offset, pdu_len + 4, ENC_NA); + spice_tree = proto_item_add_subtree(ti, ett_spice); + } + col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown")); + col_set_str(pinfo->cinfo, COL_INFO, "SASL authentication"); + proto_tree_add_text(spice_tree, tvb, offset, 4, "SASL message length: %u", pdu_len); + if (pdu_len == 0) { /* meaning, empty PDU */ + spice_info->next_state = SPICE_SASL_DATA; + return 4; /* only the size field.*/ + } else { + pdu_len += 4; + } + + if (avail < pdu_len) { /* didn't get the complete PDU, returning */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = pdu_len - avail; + return offset; + } + offset += 4; + proto_tree_add_text(spice_tree, tvb, offset, pdu_len - 4, "SASL authentication data (%u bytes): %s", pdu_len - 4, tvb_format_text(tvb, offset, pdu_len - 4)); + return pdu_len; + break; + case SPICE_SASL_DATA: + offset = 0; + while (offset < tvb_reported_length(tvb)) { + avail = tvb_length_remaining(tvb, offset); + pdu_len = 4; + if (avail < pdu_len) { + pinfo->desegment_offset = 0; + pinfo->desegment_len = pdu_len - avail; + return offset; + } + pdu_len = tvb_get_ntohl(tvb, offset); /* the length of the following messages */ + if (tree && spice_tree == NULL) { + ti = proto_tree_add_item(tree, proto_spice, tvb, offset, pdu_len, ENC_NA); + spice_tree = proto_item_add_subtree(ti, ett_spice); + } + proto_tree_add_text(spice_tree, tvb, offset, 4, "SASL message length: %u", pdu_len); + if (pdu_len == 0) { /* meaning, empty PDU - probably the client_out_list, which may be empty*/ + spice_info->next_state = SPICE_SASL_AUTH; + client_out_list = TRUE; + return 4; /* only the size field.*/ + } else { + pdu_len += 4; + proto_item_set_len(ti, pdu_len); + } + if (avail < pdu_len) { /* didn't get the complete PDU, returning */ + pinfo->desegment_offset = offset; + pinfo->desegment_len = pdu_len - avail; + return offset; + } + col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s (SASL wrapped)", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown")); + col_set_str(pinfo->cinfo, COL_INFO, "SASL wrapped Spice message"); + + offset += 4; + proto_tree_add_text(spice_tree, tvb, offset, pdu_len - 4, "SASL data (%u bytes)", pdu_len - 4); + offset += (pdu_len - 4); + } return pdu_len; break; case SPICE_DATA: @@ -2823,6 +3073,8 @@ dissect_spice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) return offset; break; case SPICE_TICKET_CLIENT: + if (spice_info->destport != pinfo->destport) /* ignore anything from the server, wait for ticket from client */ + break; avail = tvb_reported_length(tvb); pdu_len = 128; if (avail < pdu_len) { @@ -2833,14 +3085,16 @@ dissect_spice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) col_set_str(pinfo->cinfo, COL_INFO, "Client ticket"); col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown")); if (tree) { - ti = proto_tree_add_item(tree, proto_spice, tvb, 0, -1, ENC_NA); + ti = proto_tree_add_item(tree, proto_spice, tvb, 0, 128, ENC_NA); spice_tree = proto_item_add_subtree(ti, ett_ticket_client); - proto_tree_add_item(spice_tree, hf_ticket_client, tvb, 0, -1, ENC_NA); + proto_tree_add_item(spice_tree, hf_ticket_client, tvb, 0, 128, ENC_NA); } spice_info->next_state = SPICE_TICKET_SERVER; return 128; break; case SPICE_TICKET_SERVER: + if (spice_info->destport != pinfo->srcport) /* ignore anything from the client, wait for ticket from server */ + break; avail = tvb_reported_length(tvb); pdu_len = 4; if (avail < pdu_len) { @@ -2851,7 +3105,7 @@ dissect_spice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) col_set_str(pinfo->cinfo, COL_INFO, "Server ticket"); col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "Spice %s", val_to_str_const(spice_info->channel_type,channel_types_vs, "Unknown")); if (tree) { - ti = proto_tree_add_item(tree, proto_spice, tvb, 0, -1, ENC_NA); + ti = proto_tree_add_item(tree, proto_spice, tvb, 0, 4, ENC_NA); spice_tree = proto_item_add_subtree(ti, ett_ticket_server); proto_tree_add_item(spice_tree, hf_ticket_server, tvb, 0, 4, ENC_LITTLE_ENDIAN); } @@ -2892,7 +3146,7 @@ proto_register_spice(void) NULL, HFILL } }, { &hf_link_server, - { "LINK server header", "spice.link_server", + { "Link server header", "spice.link_server", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, @@ -2981,9 +3235,29 @@ proto_register_spice(void) FT_UINT32, BASE_DEC, VALS(spice_error_codes_vs), 0x0, NULL, HFILL } }, - { &hf_common_cap, - { "Common channels capabilitity", "spice.common_cap", - FT_UINT32, BASE_DEC, NULL, 0x0, + { &hf_auth_select_client, + { "Authentication selected by client", "spice.auth_select_client", + FT_UINT32, BASE_DEC, VALS(spice_auth_select_vs), 0x0, + NULL, HFILL } + }, + { &hf_common_cap_auth, + { "Authentication capabilitity", "spice.common_cap_auth", + FT_UINT32, BASE_HEX_DEC, 0, 0, + NULL, HFILL } + }, + { &hf_common_cap_auth_select, + { "Auth Selection", "spice.common_cap_auth_select", + FT_BOOLEAN, 3, TFS(&tfs_set_notset), SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION_MASK, + NULL, HFILL } + }, + { &hf_common_cap_auth_spice, + { "Auth Spice", "spice.common_cap_auth_spice", + FT_BOOLEAN, 3, TFS(&tfs_set_notset), SPICE_COMMON_CAP_AUTH_SPICE_MASK, + NULL, HFILL } + }, + { &hf_common_cap_auth_sasl, + { "Auth SASL", "spice.common_cap_auth_sasl", + FT_BOOLEAN, 3, TFS(&tfs_set_notset), SPICE_COMMON_CAP_AUTH_SASL_MASK, NULL, HFILL } }, { &hf_playback_cap, @@ -3136,19 +3410,19 @@ proto_register_spice(void) FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_GLZ_RGB_width, - { "Width", "spice.GLZ_RGB_width", + { &hf_LZ_width, + { "Width", "spice.LZ_width", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_GLZ_RGB_height, - { "Height", "spice.GLZ_RGB_height", + { &hf_LZ_height, + { "Height", "spice.LZ_height", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_GLZ_RGB_type, - { "(G)LZ_RGB image type", "spice.GLZ_RGB_type", - FT_UINT16, BASE_DEC, VALS(LzImage_type_vs), 0xf, + { &hf_LZ_RGB_type, + { "LZ_RGB image type", "spice.LZ_RGB_type", + FT_UINT8, BASE_DEC, VALS(LzImage_type_vs), 0xf, NULL, HFILL } }, { &hf_LZ_major_version, @@ -3161,13 +3435,13 @@ proto_register_spice(void) FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_GLZ_RGB_stride, - { "Stride", "spice.GLZ_RGB_stride", + { &hf_LZ_stride, + { "Stride", "spice.LZ_stride", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_GLZ_RGB_dict_id, - { "(G)LZ RGB Dictionary ID", "spice.GLZ_RGB_dict_id", + { &hf_LZ_RGB_dict_id, + { "LZ RGB Dictionary ID", "spice.LZ_RGB_dict_id", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, @@ -3471,6 +3745,11 @@ proto_register_spice(void) FT_UINT32, BASE_DEC, VALS(agent_clipboard_type), 0x0, NULL, HFILL } }, + { &hf_LZ_PLT_type, + { "LZ_PLT image type", "spice.LZ_PLT_type", + FT_UINT32, BASE_DEC, VALS(LzImage_type_vs), 0x0, + NULL, HFILL } + }, }; /* Setup protocol subtree arrays */ @@ -3480,6 +3759,7 @@ proto_register_spice(void) &ett_link_server, &ett_link_caps, &ett_ticket_client, + &ett_auth_select_client, &ett_ticket_server, &ett_data, &ett_message, @@ -3522,7 +3802,7 @@ proto_register_spice(void) proto_spice = proto_register_protocol("Spice protocol", "Spice", "spice"); - /* Requispice function calls to register the header fields and subtrees */ + /* Required function calls to register the header fields and subtrees */ proto_register_field_array(proto_spice, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); |