diff options
author | Craig Jackson <cejackson51@gmail.com> | 2018-05-10 12:52:22 -0400 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2018-07-30 10:33:59 +0000 |
commit | 0049a1afaedef13d13d479f5b860449a51ca0c7e (patch) | |
tree | 3acd430e16403a2ab16ff5034b268ab770b6dcb1 | |
parent | e7f7e04eff286557a86ff152b0faba02223aa070 (diff) |
Add basic support for TDS 5 (Sybase) cursors.
Change-Id: Ie04489b5445dc473d9bc6d772c1c33270da9b363
Reviewed-on: https://code.wireshark.org/review/28835
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r-- | epan/dissectors/packet-tds.c | 850 |
1 files changed, 839 insertions, 11 deletions
diff --git a/epan/dissectors/packet-tds.c b/epan/dissectors/packet-tds.c index 3ec7a42b99..61f70ab8bb 100644 --- a/epan/dissectors/packet-tds.c +++ b/epan/dissectors/packet-tds.c @@ -141,6 +141,7 @@ #include <epan/reassemble.h> #include <epan/prefs.h> #include <epan/expert.h> +#include <epan/proto_data.h> #include "packet-tcp.h" #define TDS_QUERY_PKT 1 /* SQLBatch in MS-TDS revision 18.0 */ @@ -229,6 +230,20 @@ #define TDS_CAP_REQUEST 1 #define TDS_CAP_RESPONSE 2 +/* TDS 5 Cursor fetch options */ +#define TDS_CUR_NEXT 1 +#define TDS_CUR_PREV 2 +#define TDS_CUR_FIRST 3 +#define TDS_CUR_LAST 4 +#define TDS_CUR_ABS 5 +#define TDS_CUR_REL 6 + +/* TDS 5 Cursor Info Commands */ +#define TDS_CURINFO_SET_FETCH_COUNT 1 +#define TDS_CURINFO_INQUIRE 2 +#define TDS_CURINFO_INFORM 3 +#define TDS_CURINFO_LISTALL 4 + /* TDS 7 Prelogin options */ #define TDS7_PRELOGIN_OPTION_VERSION 0x00 #define TDS7_PRELOGIN_OPTION_ENCRYPTION 0x01 @@ -867,6 +882,59 @@ static int hf_tds_control = -1; static int hf_tds_control_length = -1; static int hf_tds_control_fmt = -1; +/* CURCLOSE token (TDS_CURCLOSE_TOKEN) */ +static int hf_tds_curclose = -1; +static int hf_tds_curclose_length = -1; +static int hf_tds_curclose_cursorid = -1; +static int hf_tds_curclose_cursor_name = -1; +static int hf_tds_curclose_option_deallocate = -1; + +/* CURDECLARE token (TDS_CURDECLARE_TOKEN) */ +static int hf_tds_curdeclare = -1; +static int hf_tds_curdeclare_length = -1; +static int hf_tds_curdeclare_cursor_name = -1; +static int hf_tds_curdeclare_options = -1; +static int hf_tds_curdeclare_options_rdonly = -1; +static int hf_tds_curdeclare_options_updatable = -1; +static int hf_tds_curdeclare_options_sensitive = -1; +static int hf_tds_curdeclare_options_dynamic = -1; +static int hf_tds_curdeclare_options_implicit = -1; +static int hf_tds_curdeclare_status_parameterized = -1; +static int hf_tds_curdeclare_statement = -1; +static int hf_tds_curdeclare_update_columns_num = -1; +static int hf_tds_curdeclare_update_columns_name = -1; + +/* CURFETCH token (TDS_CURFETCH_TOKEN) */ +static int hf_tds_curfetch = -1; +static int hf_tds_curfetch_length = -1; +static int hf_tds_curfetch_cursorid = -1; +static int hf_tds_curfetch_cursor_name = -1; +static int hf_tds_curfetch_type = -1; +static int hf_tds_curfetch_rowcnt = -1; + +/* CURINFO token (TDS_CURINFO_TOKEN) */ +static int hf_tds_curinfo = -1; +static int hf_tds_curinfo_length = -1; +static int hf_tds_curinfo_cursorid = -1; +static int hf_tds_curinfo_cursor_name = -1; +static int hf_tds_curinfo_cursor_command = -1; +static int hf_tds_curinfo_cursor_status = -1; +static int hf_tds_curinfo_cursor_status_declared = -1; +static int hf_tds_curinfo_cursor_status_open = -1; +static int hf_tds_curinfo_cursor_status_closed = -1; +static int hf_tds_curinfo_cursor_status_rdonly = -1; +static int hf_tds_curinfo_cursor_status_updatable = -1; +static int hf_tds_curinfo_cursor_status_rowcnt = -1; +static int hf_tds_curinfo_cursor_status_dealloc = -1; +static int hf_tds_curinfo_cursor_rowcnt = -1; + +/* CUROPEN token (TDS_CUROPEN_TOKEN) */ +static int hf_tds_curopen = -1; +static int hf_tds_curopen_length = -1; +static int hf_tds_curopen_cursorid = -1; +static int hf_tds_curopen_cursor_name = -1; +static int hf_tds_curopen_status_parameterized = -1; + /* TDS5 DBRPC Token (TDS5_DBRPC_TOKEN) */ static int hf_tds_dbrpc = -1; static int hf_tds_dbrpc_length = -1; @@ -1200,6 +1268,8 @@ static gint ett_tds_prelogin_option = -1; static gint ett_tds7_featureextack = -1; static gint ett_tds7_featureextack_feature = -1; static gint ett_tds5_dbrpc_options = -1; +static gint ett_tds5_curdeclare_options = -1; +static gint ett_tds5_curinfo_status = -1; /* static expert_field ei_tds_type_info_type_undecoded = EI_INIT; */ static expert_field ei_tds_invalid_length = EI_INIT; @@ -1208,6 +1278,7 @@ static expert_field ei_tds_type_info_type = EI_INIT; static expert_field ei_tds_all_headers_header_type = EI_INIT; /* static expert_field ei_tds_token_stats = EI_INIT; */ static expert_field ei_tds_invalid_plp_type = EI_INIT; +static expert_field ei_tds_cursor_name_mismatch = EI_INIT; /* Desegmentation of Netlib buffers crossing TCP segment boundaries. */ static gboolean tds_desegment = TRUE; @@ -1241,12 +1312,31 @@ static dissector_handle_t ntlmssp_handle; static dissector_handle_t gssapi_handle; static dissector_handle_t smp_handle; +#define TDS_CURSOR_NAME_VALID 0x01 +#define TDS_CURSOR_ID_VALID 0x02 +#define TDS_CURSOR_ROWINFO_VALID 0x04 +#define TDS_CURSOR_IN_CONV_TABLE 0x08 +#define TDS_CURSOR_FETCH_PENDING 0x10 + +typedef struct { + const guint8 *tds_cursor_name; + guint tds_cursor_id; + struct _netlib_data *tds_cursor_rowinfo; + guint tds_cursor_flags; +} tds_cursor_info_t; + +typedef struct { + tds_cursor_info_t *tds_conv_cursor_current; + wmem_tree_t *tds_conv_cursor_table; +} tds_conv_cursor_info_t; + typedef struct { + tds_conv_cursor_info_t *tds_conv_cursor_info; gint tds_version; - gboolean tds_packets_in_order; guint tds_encoding_int2; guint tds_encoding_int4; guint tds_encoding_char; + gboolean tds_packets_in_order; } tds_conv_info_t; /* The actual TDS protocol values used on the wire. */ @@ -1553,6 +1643,24 @@ static const value_string tds_capability_type[] = { {0, NULL} }; +static const value_string tds_curfetch_types[] = { + {TDS_CUR_NEXT, "Next"}, + {TDS_CUR_PREV, "Previous"}, + {TDS_CUR_FIRST, "First"}, + {TDS_CUR_LAST, "Last"}, + {TDS_CUR_ABS, "Absolute"}, + {TDS_CUR_REL, "Relative"}, + {0, NULL} +}; + +static const value_string tds_curinfo_commands[] = { + {TDS_CURINFO_SET_FETCH_COUNT, "Set fetch count"}, + {TDS_CURINFO_INQUIRE, "Inquire cursor state"}, + {TDS_CURINFO_INFORM, "Report information about a cursor"}, + {TDS_CURINFO_LISTALL, "List all open cursors"}, + {0, NULL} +}; + static const value_string login_field_names[] = { {0, "Client Name"}, {1, "Username"}, @@ -1800,6 +1908,32 @@ get_size_by_coltype(int servertype) } } +static struct _netlib_data * +copy_nl_data(wmem_allocator_t *allocator, struct _netlib_data *nl_data) +{ + struct _netlib_data *new_nl_data; + guint col; + + + new_nl_data = wmem_new0(allocator, struct _netlib_data); + new_nl_data->num_cols = nl_data->num_cols; + for (col=0; col < nl_data->num_cols; col++) { + struct _tds_col *old_column = nl_data->columns[col]; + struct _tds_col *new_column = wmem_new0(allocator, struct _tds_col); + new_nl_data->columns[col] = new_column; + if (old_column->name) { + new_column->name = wmem_strdup(allocator, old_column->name); + } + new_column->csize = old_column->csize; + new_column->utype = old_column->utype; + new_column->ctype = old_column->ctype; + new_column->precision = old_column->precision; + new_column->scale = old_column->scale; + } + + return new_nl_data; +} + static void dissect_tds_all_headers(tvbuff_t *tvb, guint *offset, packet_info *pinfo, proto_tree *tree) { @@ -2469,8 +2603,410 @@ dissect_tds5_lang_token(tvbuff_t *tvb, guint offset, proto_tree *tree, tds_conv_ return cur - offset; } +static void +tds5_check_cursor_name(packet_info *pinfo, proto_item *pi, + tds_cursor_info_t *cursor_current, const guint8 *cursorname) +{ + if (cursorname && cursor_current && + ( cursor_current->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) { + if (g_strcmp0(cursorname, + cursor_current->tds_cursor_name) != 0) { + expert_add_info_format(pinfo, pi, &ei_tds_cursor_name_mismatch, + "Cursor name %s does not match current cursor name %s", + cursorname, cursor_current->tds_cursor_name); + } + } +} + +static void +tds_cursor_info_init(tds_conv_info_t *tds_info) +{ + tds_conv_cursor_info_t *conv_cursor_info = tds_info->tds_conv_cursor_info; + + if (!conv_cursor_info) { + conv_cursor_info = + wmem_new0(wmem_file_scope(), tds_conv_cursor_info_t); + conv_cursor_info->tds_conv_cursor_table = + wmem_tree_new(wmem_file_scope()); + tds_info->tds_conv_cursor_info = conv_cursor_info; + } +} + +static guint +dissect_tds5_curclose_token(tvbuff_t *tvb, packet_info *pinfo, guint offset, + proto_tree *tree, tds_conv_info_t *tds_info) +{ + guint len, cur = offset; + guint cursorid; + proto_item *cursor_id_pi; + tds_cursor_info_t *packet_cursor = + (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); + + proto_tree_add_item_ret_uint(tree, hf_tds_curclose_length, tvb, cur, 2, tds_get_int2_encoding(tds_info), &len); + cur += 2; + + cursor_id_pi = proto_tree_add_item_ret_uint(tree, hf_tds_curclose_cursorid, + tvb, cur, 4, tds_get_int4_encoding(tds_info), &cursorid); + cur += 4; + + if (cursorid == 0) { + guint cursorname_len; + const guint8 *cursorname; + proto_item *cursor_name_pi; + + cursor_name_pi = proto_tree_add_item_ret_string_and_length(tree, + hf_tds_curclose_cursor_name, + tvb, cur + 1, cursorname_len, tds_get_char_encoding(tds_info)|ENC_NA, + wmem_packet_scope(), &cursorname, &cursorname_len); + cur += cursorname_len; + tds5_check_cursor_name(pinfo, cursor_name_pi, packet_cursor, cursorname); + } + else if (packet_cursor && cursor_id_pi && + (packet_cursor->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) { + proto_item_append_text(cursor_id_pi, " (%s)", + packet_cursor->tds_cursor_name); + } + + proto_tree_add_item(tree, hf_tds_curclose_option_deallocate, tvb, cur, 1, ENC_NA); + cur += 1; + + if (!PINFO_FD_VISITED(pinfo) && !packet_cursor) { + tds_conv_cursor_info_t *conv_cursor_info; + + tds_cursor_info_init(tds_info); + conv_cursor_info = tds_info->tds_conv_cursor_info; + if (cursorid) { + tds_cursor_info_t *cursor_current; + cursor_current = + (tds_cursor_info_t *) wmem_tree_lookup32(conv_cursor_info->tds_conv_cursor_table, + cursorid); + if (cursor_current) { + p_add_proto_data(wmem_file_scope(), + pinfo, proto_tds, 0, cursor_current); + } + } + } + + return cur - offset; +} + +static const int *tds_curdeclare_hf_fields[] = { + &hf_tds_curdeclare_options_rdonly, + &hf_tds_curdeclare_options_updatable, + &hf_tds_curdeclare_options_sensitive, + &hf_tds_curdeclare_options_dynamic, + &hf_tds_curdeclare_options_implicit, + NULL +}; + +static guint +dissect_tds5_curdeclare_token(tvbuff_t *tvb, packet_info *pinfo, guint offset, + proto_tree *tree, tds_conv_info_t *tds_info) +{ + guint len, cur = offset, stmtlen, num_updatable_columns; + guint cursorname_len; + const guint8 *cursorname; + tds_cursor_info_t *packet_cursor = + (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); + + proto_tree_add_item_ret_uint(tree, hf_tds_curdeclare_length, tvb, cur, 2, + tds_get_int2_encoding(tds_info), &len); + cur += 2; + + proto_tree_add_item_ret_string_and_length(tree, hf_tds_curdeclare_cursor_name, + tvb, cur, 1, tds_get_char_encoding(tds_info)|ENC_NA, + wmem_packet_scope(), &cursorname, &cursorname_len); + cur += cursorname_len; + + /* Options is one byte, as is status. */ + proto_tree_add_bitmask(tree, tvb, cur, hf_tds_curdeclare_options, + ett_tds5_curdeclare_options, tds_curdeclare_hf_fields, ENC_NA); + proto_tree_add_item(tree, hf_tds_curdeclare_status_parameterized, tvb, + cur + 1, 1, ENC_NA); + cur += 2; + + proto_tree_add_item_ret_length(tree, hf_tds_curdeclare_statement, tvb, cur, 2, + tds_get_char_encoding(tds_info)|tds_get_int2_encoding(tds_info), &stmtlen); + cur += stmtlen; + + proto_tree_add_item_ret_uint(tree, hf_tds_curdeclare_update_columns_num, tvb, cur, 1, + ENC_NA, &num_updatable_columns); + cur += 1; + + if (num_updatable_columns > 0) { + guint column_name_len; + + proto_tree_add_item_ret_length(tree, hf_tds_curdeclare_update_columns_name, + tvb, cur, 1, tds_get_char_encoding(tds_info)|ENC_NA, &column_name_len); + cur += column_name_len; + } + + /* + * If being processed in order (first time through) prepare to correlate the + * curdeclare with the curinfo response. + */ + if (!PINFO_FD_VISITED(pinfo)) { + tds_conv_cursor_info_t *conv_cursor_info; + tds_cursor_info_t *cursor_current; + + tds_cursor_info_init(tds_info); + conv_cursor_info = tds_info->tds_conv_cursor_info; + + cursor_current = conv_cursor_info->tds_conv_cursor_current; + if (!cursor_current) { + cursor_current = wmem_new0(wmem_file_scope(), tds_cursor_info_t); + conv_cursor_info->tds_conv_cursor_current = cursor_current; + } + else if (!(cursor_current->tds_cursor_flags & TDS_CURSOR_IN_CONV_TABLE)) { + /* + * The cursor was allocated, but never entered into the table. + * This won't happen normally, but it could happen if the client were + * coded unusually and pending activity were to be aborted mid-sequence. + * Free possible existing values to avoid a file-level leak. + */ + wmem_free(wmem_file_scope(), (void *) cursor_current->tds_cursor_name); + wmem_free(wmem_file_scope(), (void *) cursor_current->tds_cursor_rowinfo); + (void) memset(cursor_current, 0, sizeof (tds_cursor_info_t)); + } + cursor_current->tds_cursor_name = wmem_strdup(wmem_file_scope(), cursorname); + cursor_current->tds_cursor_flags |= TDS_CURSOR_NAME_VALID; + if (packet_cursor && packet_cursor != cursor_current) { + p_remove_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); + packet_cursor = NULL; + } + if (!packet_cursor) { + p_add_proto_data(wmem_file_scope(), pinfo, proto_tds, 0, cursor_current); + } + + } + return cur - offset; +} + +static guint +dissect_tds5_curfetch_token(tvbuff_t *tvb, packet_info *pinfo, guint offset, + proto_tree *tree, tds_conv_info_t *tds_info) +{ + guint len, cur = offset; + guint cursorid; + gint curfetch_type; + const guint8 *cursorname; + proto_item *cursor_id_pi; + tds_cursor_info_t *packet_cursor = + (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); + + proto_tree_add_item_ret_uint(tree, hf_tds_curfetch_length, tvb, cur, 2, tds_get_int2_encoding(tds_info), &len); + cur += 2; + + cursor_id_pi = proto_tree_add_item_ret_uint(tree, hf_tds_curfetch_cursorid, + tvb, cur, 4, tds_get_int4_encoding(tds_info), &cursorid); + cur += 4; + + if (cursorid == 0) { + guint cursorname_len; + proto_item *cursor_name_pi; + + cursor_name_pi = proto_tree_add_item_ret_string_and_length(tree, hf_tds_curfetch_cursor_name, + tvb, cur, 1, tds_get_char_encoding(tds_info)|ENC_NA, + wmem_packet_scope(), &cursorname, &cursorname_len); + tds5_check_cursor_name(pinfo, cursor_name_pi, packet_cursor, cursorname); + cur += cursorname_len; + } + else if (packet_cursor && cursor_id_pi && + (packet_cursor->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) { + proto_item_append_text(cursor_id_pi, " (%s)", + packet_cursor->tds_cursor_name); + } + + proto_tree_add_item_ret_uint(tree, hf_tds_curfetch_type, tvb, cur, 1, + ENC_NA, &curfetch_type); + cur += 1; + + if (curfetch_type >= TDS_CUR_ABS) { + proto_tree_add_item(tree, hf_tds_curfetch_rowcnt, tvb, cur, 4, + tds_get_int4_encoding(tds_info)); + cur += 4; + } + + if (!PINFO_FD_VISITED(pinfo) && !packet_cursor) { + tds_conv_cursor_info_t *conv_cursor_info = tds_info->tds_conv_cursor_info; + tds_cursor_info_t *cursor_current; + + if (!conv_cursor_info) { + conv_cursor_info = + wmem_new0(wmem_file_scope(), tds_conv_cursor_info_t); + conv_cursor_info->tds_conv_cursor_table = + wmem_tree_new(wmem_file_scope()); + tds_info->tds_conv_cursor_info = conv_cursor_info; + } + if (cursorid) { + cursor_current = + (tds_cursor_info_t *) wmem_tree_lookup32(conv_cursor_info->tds_conv_cursor_table, + cursorid); + if (cursor_current) { + p_add_proto_data(wmem_file_scope(), + pinfo, proto_tds, 0, cursor_current); + cursor_current->tds_cursor_flags |= TDS_CURSOR_FETCH_PENDING; + conv_cursor_info->tds_conv_cursor_current = cursor_current; + } + } + } + + return cur - offset; +} + +static const int *tds_curinfo_hf_fields[] = { + &hf_tds_curinfo_cursor_status_declared, + &hf_tds_curinfo_cursor_status_open, + &hf_tds_curinfo_cursor_status_closed, + &hf_tds_curinfo_cursor_status_rdonly, + &hf_tds_curinfo_cursor_status_updatable, + &hf_tds_curinfo_cursor_status_rowcnt, + &hf_tds_curinfo_cursor_status_dealloc, + NULL +}; + +static guint +dissect_tds5_curinfo_token(tvbuff_t *tvb, packet_info *pinfo, guint offset, + proto_tree *tree, tds_conv_info_t *tds_info) +{ + guint len, cur = offset; + const guint8 *cursorname = NULL; + guint cursorid; + guint cursor_command; + tds_cursor_info_t *packet_cursor = + (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); + proto_item *cursor_id_pi; + + proto_tree_add_item_ret_uint(tree, hf_tds_curinfo_length, tvb, cur, 2, + tds_get_int2_encoding(tds_info), &len); + cur += 2; + + cursor_id_pi = proto_tree_add_item_ret_uint(tree, hf_tds_curinfo_cursorid, + tvb, cur, 4, tds_get_int4_encoding(tds_info), &cursorid); + cur += 4; + + if (cursorid == 0) { + guint cursorname_len; + proto_item *cursor_name_pi; + cursor_name_pi = proto_tree_add_item_ret_string_and_length(tree, + hf_tds_curinfo_cursor_name, tvb, cur, 1, + tds_get_char_encoding(tds_info)|ENC_NA, + wmem_packet_scope(), &cursorname, &cursorname_len); + cur += cursorname_len; + tds5_check_cursor_name(pinfo, cursor_name_pi, packet_cursor, cursorname); + } + else if (packet_cursor && cursor_id_pi && + (packet_cursor->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) { + proto_item_append_text(cursor_id_pi, " (%s)", + packet_cursor->tds_cursor_name); + } + + + proto_tree_add_item_ret_uint(tree, hf_tds_curinfo_cursor_command, + tvb, cur, 1, ENC_NA, &cursor_command); + cur += 1; + + proto_tree_add_bitmask(tree, tvb, cur, hf_tds_curinfo_cursor_status, + ett_tds5_curinfo_status, tds_curinfo_hf_fields, + tds_get_int2_encoding(tds_info)); + cur += 2; + + /* offset + 2 to skip past the length, which does not include itself. */ + if (len - (cur - (offset + 2)) == 4) { + proto_tree_add_item(tree, hf_tds_curinfo_cursor_rowcnt, tvb, cur, 4, + tds_get_int4_encoding(tds_info)); + cur += 4; + } + + /* + * If we're going through sequentially, and it's an INFORM response, + * try to correlate cursor names with cursor ids. + */ + if (!PINFO_FD_VISITED(pinfo) && + cursor_command == TDS_CURINFO_INFORM && + !packet_cursor) { + tds_conv_cursor_info_t *conv_cursor_info = tds_info->tds_conv_cursor_info; + tds_cursor_info_t *cursor_current; + + if (!conv_cursor_info) { + conv_cursor_info = + wmem_new0(wmem_file_scope(), tds_conv_cursor_info_t); + conv_cursor_info->tds_conv_cursor_table = + wmem_tree_new(wmem_file_scope()); + tds_info->tds_conv_cursor_info = conv_cursor_info; + } + cursor_current = conv_cursor_info->tds_conv_cursor_current; + if (!cursor_current) { + cursor_current = wmem_new0(wmem_file_scope(), tds_cursor_info_t); + conv_cursor_info->tds_conv_cursor_current = cursor_current; + } + p_add_proto_data(wmem_file_scope(), pinfo, proto_tds, 0, cursor_current); + packet_cursor = cursor_current; + if (cursorid != 0) { + if (!(cursor_current->tds_cursor_flags & TDS_CURSOR_ID_VALID)) { + cursor_current->tds_cursor_id = cursorid; + cursor_current->tds_cursor_flags |= TDS_CURSOR_ID_VALID; + wmem_tree_insert32(conv_cursor_info->tds_conv_cursor_table, + cursorid, cursor_current); + cursor_current->tds_cursor_flags |= TDS_CURSOR_IN_CONV_TABLE; + } else if (cursor_current->tds_cursor_id != cursorid) { + tds_cursor_info_t *temp_cursor = + (tds_cursor_info_t *) wmem_tree_lookup32(conv_cursor_info->tds_conv_cursor_table, + cursorid); + if (temp_cursor != cursor_current) { + cursor_current = temp_cursor; + conv_cursor_info->tds_conv_cursor_current = cursor_current; + p_remove_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); + p_add_proto_data(wmem_file_scope(), pinfo, proto_tds, 0, cursor_current); + + } + } + } + } + return cur - offset; +} + +static guint +dissect_tds5_curopen_token(tvbuff_t *tvb, packet_info *pinfo, guint offset, + proto_tree *tree, tds_conv_info_t *tds_info) +{ + guint len, cur = offset; + guint cursorid; + proto_item *cursor_id_pi; + tds_cursor_info_t *packet_cursor = + (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); + + proto_tree_add_item_ret_uint(tree, hf_tds_curopen_length, tvb, cur, 2, tds_get_int2_encoding(tds_info), &len); + cur += 2; + + cursor_id_pi = proto_tree_add_item_ret_uint(tree, hf_tds_curopen_cursorid, + tvb, cur, 4, tds_get_int4_encoding(tds_info), &cursorid); + cur += 4; + + if (cursorid == 0) { + guint cursorname_len; + const guint8 *cursorname; + proto_item *pi; + + pi = proto_tree_add_item_ret_string_and_length(tree, hf_tds_curopen_cursor_name, + tvb, cur, 1, tds_get_char_encoding(tds_info)|ENC_NA, + wmem_packet_scope(), &cursorname, &cursorname_len); + cur += cursorname_len; + tds5_check_cursor_name(pinfo, pi, packet_cursor, cursorname); + } + else if (packet_cursor && cursor_id_pi && + (packet_cursor->tds_cursor_flags & TDS_CURSOR_NAME_VALID)) { + proto_item_append_text(cursor_id_pi, " (%s)", + packet_cursor->tds_cursor_name); + } + + proto_tree_add_item(tree, hf_tds_curopen_status_parameterized, tvb, cur, 1, ENC_NA); + cur += 1; + + return cur - offset; +} static const int *hf_req_0[9] = { &hf_tds_capability_req_lang, @@ -2965,7 +3501,7 @@ dissect_tds5_params_token(tvbuff_t *tvb, packet_info *pinfo, { guint cur = offset, i; - /* TDS5 does not have the Paritially Length-Prefixed concept, so the "plp" + /* TDS5 does not have the Partially Length-Prefixed concept, so the "plp" * parameter is always FALSE. */ for (i = 0; i < nl_data->num_cols; i++) { dissect_tds_type_varbyte(tvb, &cur, pinfo, tree, hf_tds_params_field, tds_info, @@ -2998,6 +3534,11 @@ tds45_token_to_idx(guint8 token) case TDS_COLFMT_TOKEN: return hf_tds_colfmt; case TDS_COL_NAME_TOKEN: return hf_tds_colname; case TDS_CONTROL_TOKEN: return hf_tds_control; + case TDS_CURCLOSE_TOKEN: return hf_tds_curclose; + case TDS_CURDECLARE_TOKEN: return hf_tds_curdeclare; + case TDS_CURFETCH_TOKEN: return hf_tds_curfetch; + case TDS_CURINFO_TOKEN: return hf_tds_curinfo; + case TDS_CUROPEN_TOKEN: return hf_tds_curopen; case TDS5_DBRPC_TOKEN: return hf_tds_dbrpc; case TDS_DONE_TOKEN: return hf_tds_done; case TDS_DONEPROC_TOKEN: return hf_tds_doneproc; @@ -3072,6 +3613,21 @@ dissect_tds5_tokenized_request_packet(tvbuff_t *tvb, packet_info *pinfo, proto_t case TDS_LANG_TOKEN: token_sz = dissect_tds5_lang_token(tvb, pos + 1, token_tree, tds_info) + 1; break; + case TDS_CURCLOSE_TOKEN: + token_sz = dissect_tds5_curclose_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1; + break; + case TDS_CURDECLARE_TOKEN: + token_sz = dissect_tds5_curdeclare_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1; + break; + case TDS_CURFETCH_TOKEN: + token_sz = dissect_tds5_curfetch_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1; + break; + case TDS_CURINFO_TOKEN: + token_sz = dissect_tds5_curinfo_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1; + break; + case TDS_CUROPEN_TOKEN: + token_sz = dissect_tds5_curopen_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1; + break; case TDS5_LOGOUT_TOKEN: token_sz = dissect_tds5_logout_token(token_tree, tvb, pos + 1, tds_info) + 1; break; @@ -3904,11 +4460,13 @@ dissect_tds_colfmt_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv * */ static guint -dissect_tds_rowfmt_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv_info_t *tds_info, - struct _netlib_data *nl_data) +dissect_tds_rowfmt_token(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, + guint offset, tds_conv_info_t *tds_info, struct _netlib_data *nl_data) { guint next, cur; guint col, len, numcols; + tds_cursor_info_t *packet_cursor = + (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); proto_tree_add_item_ret_uint(tree, hf_tds_rowfmt_length, tvb, offset, 2, tds_get_int4_encoding(tds_info), &len); @@ -4020,6 +4578,17 @@ dissect_tds_rowfmt_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv } /* while */ nl_data->num_cols = col; + + /* + * If there is a packet cursor, we need to copy the struct _netlib_data into it + * for use by later packets referencing the same cursor. + */ + + if (packet_cursor && !(packet_cursor->tds_cursor_flags & TDS_CURSOR_ROWINFO_VALID)) { + packet_cursor->tds_cursor_rowinfo = copy_nl_data(wmem_file_scope(), nl_data); + packet_cursor->tds_cursor_flags |= TDS_CURSOR_ROWINFO_VALID; + } + return cur - offset; } @@ -4029,11 +4598,13 @@ dissect_tds_rowfmt_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv * */ static guint -dissect_tds_rowfmt2_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_conv_info_t *tds_info, - struct _netlib_data *nl_data) +dissect_tds_rowfmt2_token(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, + guint offset, tds_conv_info_t *tds_info, struct _netlib_data *nl_data) { guint next, cur; guint col, len, numcols; + tds_cursor_info_t *packet_cursor = + (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); proto_tree_add_item_ret_uint(tree, hf_tds_rowfmt2_length, tvb, offset, 4, tds_get_int4_encoding(tds_info), &len); @@ -4177,6 +4748,17 @@ dissect_tds_rowfmt2_token(proto_tree *tree, tvbuff_t *tvb, guint offset, tds_con } /* while */ nl_data->num_cols = col; + + /* + * If there is a packet cursor, we need to copy the struct _netlib_data into it + * for use by later packets referencing the same cursor. + */ + + if (packet_cursor && !(packet_cursor->tds_cursor_flags & TDS_CURSOR_ROWINFO_VALID)) { + packet_cursor->tds_cursor_rowinfo = copy_nl_data(wmem_file_scope(), nl_data); + packet_cursor->tds_cursor_flags |= TDS_CURSOR_ROWINFO_VALID; + } + return cur - offset; } @@ -4395,6 +4977,21 @@ dissect_tds_row_token(tvbuff_t *tvb, packet_info *pinfo, struct _netlib_data *nl { guint cur = offset, i, type; gboolean plp = FALSE; + tds_cursor_info_t *packet_cursor; + + if (!PINFO_FD_VISITED(pinfo)) { + if (tds_info->tds_conv_cursor_info && tds_info->tds_conv_cursor_info->tds_conv_cursor_current) { + tds_cursor_info_t *cursor_current = tds_info->tds_conv_cursor_info->tds_conv_cursor_current; + p_add_proto_data(wmem_file_scope(), pinfo, proto_tds, 0, + cursor_current); + } + } + + packet_cursor = (tds_cursor_info_t *) p_get_proto_data(wmem_file_scope(), pinfo, proto_tds, 0); + + if (packet_cursor && (packet_cursor->tds_cursor_flags & TDS_CURSOR_ROWINFO_VALID)) { + nl_data = packet_cursor->tds_cursor_rowinfo; + } for (i = 0; i < nl_data->num_cols; i++) { type = nl_data->columns[i]->ctype; @@ -5666,7 +6263,9 @@ dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tds_conv_i switch (token) { case TDS_CAPABILITY_TOKEN: token_sz = dissect_tds5_capability_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1; - + break; + case TDS_CURINFO_TOKEN: + token_sz = dissect_tds5_curinfo_token(tvb, pinfo, pos + 1, token_tree, tds_info) + 1; break; case TDS_DONE_TOKEN: token_sz = dissect_tds_done_token(tvb, pos + 1, token_tree, tds_info) + 1; @@ -5711,10 +6310,10 @@ dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tds_conv_i token_sz = dissect_tds_row_token(tvb, pinfo, &nl_data, pos + 1, token_tree, tds_info) + 1; break; case TDS5_ROWFMT_TOKEN: - token_sz = dissect_tds_rowfmt_token(token_tree, tvb, pos + 1, tds_info, &nl_data) + 1; + token_sz = dissect_tds_rowfmt_token(token_tree, tvb, pinfo, pos + 1, tds_info, &nl_data) + 1; break; case TDS5_ROWFMT2_TOKEN: - token_sz = dissect_tds_rowfmt2_token(token_tree, tvb, pos + 1, tds_info, &nl_data) + 1; + token_sz = dissect_tds_rowfmt2_token(token_tree, tvb, pinfo, pos + 1, tds_info, &nl_data) + 1; break; default: @@ -5807,6 +6406,7 @@ dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, tds_conv_i static void fill_tds_info_defaults(tds_conv_info_t *tds_info) { + tds_info->tds_conv_cursor_info = NULL; if (tds_little_endian) { tds_info->tds_encoding_int4 = TDS_INT4_LITTLE_ENDIAN; tds_info->tds_encoding_int2 = TDS_INT2_LITTLE_ENDIAN; @@ -7263,6 +7863,231 @@ proto_register_tds(void) NULL, HFILL } }, + /* CURCLOSE token (TDS_CURCLOSE_TOKEN) */ + { &hf_tds_curclose, + { "Token - CurClose", "tds.curclose", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curclose_length, + { "Token Length - CurClose", "tds.curclose.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curclose_cursorid, + { "CursorId", "tds.curclose.cursorid", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curclose_cursor_name, + { "Cursorname", "tds.curclose.cursor.name_len", + FT_UINT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curclose_option_deallocate, + { "Deallocate", "tds.curclose.option.deallocate", + FT_BOOLEAN, 8, NULL, 0x01, + NULL, HFILL } + }, + + /* CURDECLARE token (TDS_CURDECLARE_TOKEN) */ + { &hf_tds_curdeclare, + { "Token - CurDeclare", "tds.curdeclare", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curdeclare_length, + { "Token Length - CurDeclare", "tds.curdeclare.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curdeclare_cursor_name, + { "Cursorname", "tds.curdeclare.cursor.name_len", + FT_UINT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curdeclare_options, + { "Options", "tds.curdeclare.options", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curdeclare_options_rdonly, + { "Read Only", "tds.curdeclare.options.rdonly", + FT_BOOLEAN, 8, NULL, 0x01, + NULL, HFILL } + }, + { &hf_tds_curdeclare_options_updatable, + { "Updatable", "tds.curdeclare.options.updatable", + FT_BOOLEAN, 8, NULL, 0x02, + NULL, HFILL } + }, + { &hf_tds_curdeclare_options_sensitive, + { "Sensitive", "tds.curdeclare.options.sensitive", + FT_BOOLEAN, 8, NULL, 0x04, + NULL, HFILL } + }, + { &hf_tds_curdeclare_options_dynamic, + { "Dynamic", "tds.curdeclare.options.dynamic", + FT_BOOLEAN, 8, NULL, 0x08, + NULL, HFILL } + }, + { &hf_tds_curdeclare_options_implicit, + { "Implict", "tds.curdeclare.options.implicit", + FT_BOOLEAN, 8, NULL, 0x10, + NULL, HFILL } + }, + { &hf_tds_curdeclare_status_parameterized, + { "Status Parameterized", "tds.curdeclare.status.parameterized", + FT_BOOLEAN, 8, NULL, 0x01, + NULL, HFILL } + }, + { &hf_tds_curdeclare_statement, + { "Statement", "tds.curdeclare.statement", + FT_UINT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curdeclare_update_columns_num, + { "Number of updatable columns", "tds.curdeclare.update_columns_num", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curdeclare_update_columns_name, + { "Updatable Column Name", "tds.curdeclare.update_columns_name", + FT_UINT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + + /* CURFETCH token (TDS_CURFETCH_TOKEN) */ + { &hf_tds_curfetch, + { "Token - CurFetch", "tds.curfetch", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curfetch_length, + { "Token Length - CurFetch", "tds.curfetch.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curfetch_cursorid, + { "CursorId", "tds.curfetch.cursorid", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curfetch_cursor_name, + { "CurFetch - Cursorname", "tds.curfetch.cursor.name_len", + FT_UINT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curfetch_type, + { "CurFetch - Type", "tds.curinfo.type", + FT_UINT8, BASE_DEC, VALS(tds_curfetch_types), 0x0, + NULL, HFILL } + }, + { &hf_tds_curfetch_rowcnt, + { "CurFetch - Rowcnt", "tds.curfetch.rowcnt", + FT_INT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + /* CURINFO token (TDS_CURINFO_TOKEN) */ + { &hf_tds_curinfo, + { "Token - CurInfo", "tds.curinfo", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curinfo_length, + { "Token Length - Curinfo", "tds.curinfo.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursorid, + { "CursorId", "tds.curinfo.cursorid", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_name, + { "Cursorname", "tds.curinfo.cursor.name_len", + FT_UINT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_command, + { "Cursor Command", "tds.curinfo.cursor.command", + FT_UINT8, BASE_DEC, VALS(tds_curinfo_commands), 0x0, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_status, + { "Cursor Status", "tds.curinfo.cursor.status", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_status_declared, + { "Declared", "tds.curinfo.cursor.status.declared", + FT_BOOLEAN, 16, NULL, 0x0001, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_status_open, + { "Open", "tds.curinfo.cursor.status.open", + FT_BOOLEAN, 16, NULL, 0x0002, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_status_closed, + { "Closed", "tds.curinfo.cursor.status.closed", + FT_BOOLEAN, 16, NULL, 0x0004, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_status_rdonly, + { "Read only", "tds.curinfo.cursor.status.rdonly", + FT_BOOLEAN, 16, NULL, 0x0008, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_status_updatable, + { "Updatable", "tds.curinfo.cursor.status.updatable", + FT_BOOLEAN, 16, NULL, 0x0010, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_status_rowcnt, + { "Rowcount valid", "tds.curinfo.cursor.status.rowcnt", + FT_BOOLEAN, 16, NULL, 0x0020, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_status_dealloc, + { "Deallocated", "tds.curinfo.cursor.status.dealloc", + FT_BOOLEAN, 16, NULL, 0x0040, + NULL, HFILL } + }, + { &hf_tds_curinfo_cursor_rowcnt, + { "Cursor Rowcnt", "tds.curinfo.cursor.rowcnt", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + + /* CUROPEN token (TDS_CUROPEN_TOKEN) */ + { &hf_tds_curopen, + { "Token - CurOpen", "tds.curopen", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curopen_length, + { "Token Length - CurOpen", "tds.curopen.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curopen_cursorid, + { "CursorId", "tds.curopen.cursorid", + FT_UINT32, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curopen_cursor_name, + { "Cursorname", "tds.curopen.cursor.name_len", + FT_UINT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_tds_curopen_status_parameterized, + { "Status Parameterized", "tds.curopen.status.parameterized", + FT_BOOLEAN, 8, NULL, 0x01, + NULL, HFILL } + }, + /* DBRPC token (TDS5_DBRPC_TOKEN) */ { &hf_tds_dbrpc, { "Token - DBRPC", "tds.dbrpc", @@ -9065,7 +9890,9 @@ proto_register_tds(void) &ett_tds_flags, &ett_tds7_featureextack, &ett_tds7_featureextack_feature, - &ett_tds5_dbrpc_options + &ett_tds5_dbrpc_options, + &ett_tds5_curdeclare_options, + &ett_tds5_curinfo_status }; static ei_register_info ei[] = { @@ -9079,7 +9906,8 @@ proto_register_tds(void) #if 0 { &ei_tds_token_stats, { "tds.token.stats", PI_PROTOCOL, PI_NOTE, "Token stats", EXPFILL }}, #endif - { &ei_tds_invalid_plp_type, { "tds.type_info.type.invalidplp", PI_PROTOCOL, PI_NOTE, "Invalid PLP type", EXPFILL }} + { &ei_tds_invalid_plp_type, { "tds.type_info.type.invalidplp", PI_PROTOCOL, PI_NOTE, "Invalid PLP type", EXPFILL }}, + { &ei_tds_cursor_name_mismatch, { "tds.cursor.name_mismatch", PI_PROTOCOL, PI_WARN, "Cursor name mismatch", EXPFILL }} }; module_t *tds_module; |