Ethereal-dev: [Ethereal-dev] TDS dissector changes [packet-tds.c]

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: "Bill Meier" <wmeier@xxxxxxxxxxx>
Date: Sun, 21 Nov 2004 16:15:27 -0500
Below are:
1. An overview of changes I've made to packet-tds.c;
2. A diff of the changes. The diff is versus v 12115

I'm open to any and all feedback.

Note: 

Almost all of the changes relate to decoding TDS4/TDS5 which I've tested extensively using 
TDS4/TDS5 captures I have.

I've not been able to test these changes for TDS7/TDS8 capture files.
since I don't have any TDS7/TDS8 capures. In theory  the changes I've made should not affect 
decodes of TDS7/TDS8

If anyone can supply a TDS7/TDS capture (or a pointer to one) I'd be glad to test against same.

Thanks

Bill Meier


Overview of changes
===================

1. Do first-level dissection of:
     TDS4 ascii query, rpc and response packets;
     TDS5 query packets.

2. Handle big-endian TDS5 (and TDS4 if such exists).

3. Add preferences to allow 'hints' as to the TDS version and 
   'big-endian/little-endian' in the capture being decoded.

4. Register MS_SQL default ports as TDS ports. This also 
   enables TDS as a choice in 'decode as'.

   In addition: Add a preference to specify 'ranges' 
   of TCP ports to be recognized as TDS ports by the 
   TDS heuristics function.


Details
-------

1. Add Preferences:

   a. To allow specification of a hint as to TDS protocol being decoded 
      (Unspecified/TDS4/TDS5/TDS7/TDS8); Default: 'unspecified'

      The 'hint' is used only when needed to do a correct decode.

      If the protocol is unspecified, the decode is as previous.

   b. To allow specification of 'ranges' of TCP ports to be treated as 
      'TDS tcp ports'; i.e. if the source or destination port of a tcp
      connection matches a specified range, then the connection should be
      considered to be TDS.

   c. To allow specification of a hint as to whether TDS being decoded is 
      'little-endian' or 'big-endian'. Default: 'little-endian'.

      A hint is just that; E.G. if TDS7+ packets are encountered the decode
      is always 'little-endian'/

2, Register tcp MS SQL default ports (1433, 2433) as TDS ports
   ('dissector_add'). This also enables TDS as a choice for 'decode as'.

3. 'netlib_check_login_pkt' changed to check 'TDS tcp port' range(s) as 
    entered in preferences;

4. Change 'dissect_tds_query_packet' to handle TDS4 ascii in addition to 
   TDS7/8 UCS-16.

5. Change 'dissect_tds_rpc' to:

   a. handle TDS4 ascii RPC in addition to TDS7/8 UCS-16 RPC;
   b. handle Microsoft 'encoded' rpc_name;
   c. fix memory leak (not freeing memory obtained using
      'tvb_fake_unicode');

6. Change 'dissect_tds_response' to:

   a. handle tds4 tokens 'tds_col_name' and 'tds_col_info';
   b. dissect tokens 'tds_doneinproc' and tds 'doneproc' similarly to
      'tds_done'
   c. reclaim memory allocated for 'tds_col' structures when finished 
      processing response
           (Additional memory was being allocated each time a 
            tokenized tds5 response was processed)

7. New function 'dissect_tds_col_info_token' (similar to
   'read_results_tds5') associated with handling TDS4 responses.

8. New functions 'dissect_tds_query5_packet', 'dissect_tds5_lang_token'

9. Rework TDS token size calculation; Some TDS tokens have a length field
   of other than 2 bytes. (e.g.: the length field 
   for TDS_LANG_TOKEN is 4 bytes)

10. Update token definitions and usages;

   a. Update based upon info from current version of FreeTDS 'tds.h' 
      as well as info from Sybase TDS5 document;

      example: TDS_124_TOKEN renamed to TDS_PROCID_TOKEN

   b. TDS_124_TOKEN [TDS_PROCID] was incorrectly not considered 
      a 'fixed-size' token in function 'tds_is_fixed_token'
	

183a184
> /* TODO Update from current version of FreeTDS tds.h                       */
185,187c186,189
< #define TDS5_DYN_TOKEN      231  /* 0xE7    TDS 5.0 only              */
< #define TDS5_DYNRES_TOKEN   236  /* 0xEC    TDS 5.0 only              */
< #define TDS5_DYN3_TOKEN     215  /* 0xD7    TDS 5.0 only              */
---
> #define TDS5_PARAMS_TOKEN   215  /* 0xD7    TDS 5.0 only              */
> #define TDS5_DYNAMIC_TOKEN  231  /* 0xE7    TDS 5.0 only              */
> #define TDS5_PARAMFMT_TOKEN 236  /* 0xEC    TDS 5.0 only              */
> #define TDS5_PARAMFMT2_TOKEN 32  /* 0x20    TDS 5.0 only              */
189c191,195
< #define TDS_CLOSE_TOKEN     113  /* 0x71    TDS 5.0 only? ct_close()  */
---
> #define TDS5_ORDERBY2_TOKEN  34  /* 0x22    TDS 5.0 only              */
> #define TDS5_CURDECLARE2_TOKEN  35  /* 0x23    TDS 5.0 only              */
> #define TDS5_ROWFMT2_TOKEN   97  /* 0x61    TDS 5.0 only              */
> #define TDS5_MSG_TOKEN      101  /* 0x65    TDS 5.0 only              */
> #define TDS_LOGOUT_TOKEN    113  /* 0x71    TDS 5.0 only? ct_close()  */
191c197
< #define TDS_124_TOKEN       124  /* 0x7C    TDS 4.2 only - TDS_PROCID */
---
> #define TDS_PROCID_TOKEN    124  /* 0x7C    TDS 4.2 only - TDS_PROCID */
194a201
> #define TDS5_DYNAMIC2_TOKEN 163  /* 0xA3    TDS 5.0 only              */
197,198c204,205
< #define TDS_167_TOKEN       167  /* 0xA7                              */
< #define TDS_168_TOKEN       168  /* 0xA8                              */
---
> #define TDS_COMPUTE_NAMES_TOKEN   167	/* 0xA7 */
> #define TDS_COMPUTE_RESULT_TOKEN  168	/* 0xA8 */
204c211,212
< #define TDS_174_TOKEN       174  /* 0xAE    TDS_CONTROL               */
---
> #define TDS_CONTROL_TOKEN   174  /* 0xAE    TDS_CONTROL               */
> #define TDS_KEY_TOKEN       202  /* 0xCA                              */
215a224,243
> /* Microsoft internal stored procedure id's */
> 
> #define TDS_SP_CURSOR           1
> #define TDS_SP_CURSOROPEN       2
> #define TDS_SP_CURSORPREPARE    3
> #define TDS_SP_CURSOREXECUTE    4
> #define TDS_SP_CURSORPREPEXEC   5
> #define TDS_SP_CURSORUNPREPARE  6
> #define TDS_SP_CURSORFETCH      7
> #define TDS_SP_CURSOROPTION     8
> #define TDS_SP_CURSORCLOSE      9
> #define TDS_SP_EXECUTESQL      10
> #define TDS_SP_PREPARE         11
> #define TDS_SP_EXECUTE         12
> #define TDS_SP_PREPEXEC        13
> #define TDS_SP_PREPEXECRPC     14
> #define TDS_SP_UNPREPARE       15
> 
> /* Sybase Data Types */
> 
330a359,407
> /* TDS protocol type preference */
> /*   XXX: This preference is used as a 'hint' for cases where interpretation is ambiguous */
> /*        Currently the hint is global                                                    */
> /*   TODO: Consider storing protocol type with each conversation                          */
> /*        (when type is determined and using the preference as a default) ??              */
> 
> #define TDS_PROTOCOL_NOT_SPECIFIED   0
> #define TDS_PROTOCOL_4      4
> #define TDS_PROTOCOL_5      5
> #define TDS_PROTOCOL_7      7
> #define TDS_PROTOCOL_8      8
> 
> static gint tds_protocol_type = TDS_PROTOCOL_NOT_SPECIFIED;
> 
> const enum_val_t tds_protocol_type_options[] = {
>   {"not_specified", "Not Specified", TDS_PROTOCOL_NOT_SPECIFIED},
>   {"tds4", "TDS 4", TDS_PROTOCOL_4},  /* TDS 4.2 and TDS 4.6 */
>   {"tds5", "TDS 5", TDS_PROTOCOL_5},
>   {"tds7", "TDS 7", TDS_PROTOCOL_7},
>   {"tds8", "TDS 8", TDS_PROTOCOL_8},
>   {NULL, NULL, -1}
> };
> 
> #define TDS_PROTO_PREF_NOT_SPECIFIED (tds_protocol_type == TDS_NOT_SPECIFIED)
> #define TDS_PROTO_PREF_TDS4 (tds_protocol_type == TDS_PROTOCOL_4)
> #define TDS_PROTO_PREF_TDS5 (tds_protocol_type == TDS_PROTOCOL_5)
> #define TDS_PROTO_PREF_TDS7 (tds_protocol_type == TDS_PROTOCOL_7)
> #define TDS_PROTO_PREF_TDS8 (tds_protocol_type == TDS_PROTOCOL_8)
> #define TDS_PROTO_PREF_TDS7_TDS8 ( TDS_PROTO_PREF_TDS7 || TDS_PROTO_PREF_TDS8 )
> 
> /* TDS "endian type" */
> /*   XXX: Assumption is that all TDS conversations being decoded in a particular capture */
> /*        have the same endian type                                                      */
> /*   TODO: consider storing endian type with each conversation                           */
> /*         (using pref as the default)                                                   */
> 
> static gint tds_little_endian = TRUE;
> 
> const enum_val_t tds_endian_type_options[] = {
>     {"little_endian", "Little Endian", TRUE},
>     {"big_endian"   , "Big Endian"   , FALSE},
>     {NULL, NULL, -1}
> };
> 
> 
> /* TCP port preferences for TDS decode */
> 
> static range_t *tds_tcp_ports = NULL;
> 
366,368c443,446
< 	{TDS5_DYN_TOKEN, "Dynamic SQL"},
< 	{TDS5_DYNRES_TOKEN, "Dynamic Results"},
< 	{TDS5_DYN3_TOKEN, "Dynamic (Unknown)"},
---
> 	{TDS5_DYNAMIC_TOKEN, "TDS5 Dynamic SQL"},
> 	{TDS5_PARAMFMT_TOKEN, "TDS5 Parameter Format"},
> 	{TDS5_PARAMFMT2_TOKEN, "TDS5 Parameter2 Format"},
> 	{TDS5_PARAMS_TOKEN, "TDS5 Parameters"},
370c448
< 	{TDS_CLOSE_TOKEN, "Close Connection"},
---
> 	{TDS_LOGOUT_TOKEN, "Logout"},
372c450
< 	{TDS_124_TOKEN, "Proc ID"},
---
> 	{TDS_PROCID_TOKEN, "Proc ID"},
376,377c454,455
< 	{TDS_167_TOKEN, "Unknown (167)"},
< 	{TDS_168_TOKEN, "Unknown (168)"},
---
> 	{TDS_COMPUTE_NAMES_TOKEN, "Compute Names"},
> 	{TDS_COMPUTE_RESULT_TOKEN, "Compute Results"},
383c461,462
< 	{TDS_174_TOKEN, "Unknown (174)"},
---
> 	{TDS_CONTROL_TOKEN, "TDS Control"},
>     {TDS_KEY_TOKEN, "TDS Key"},
393a473,477
>     {TDS5_DYNAMIC2_TOKEN, "TDS5 Dynamic2"},
>     {TDS5_ORDERBY2_TOKEN, "TDS5 OrderBy2"},
>     {TDS5_CURDECLARE2_TOKEN, "TDS5 CurDeclare2"},
>     {TDS5_ROWFMT2_TOKEN, "TDS5 RowFmt2"},
>     {TDS5_MSG_TOKEN, "TDS5 Msg"},
396a481,500
> 
> static const value_string internal_stored_proc_id_names[] = {
>     {TDS_SP_CURSOR,          "sp_cursor"         },
>     {TDS_SP_CURSOROPEN,      "sp_cursoropen"     },
>     {TDS_SP_CURSORPREPARE,   "sp_cursorprepare"  },
>     {TDS_SP_CURSOREXECUTE,   "sp_cursorexecute"  },
>     {TDS_SP_CURSORPREPEXEC,  "sp_cursorprepexec" },
>     {TDS_SP_CURSORUNPREPARE, "sp_cursorunprepare"},
>     {TDS_SP_CURSORFETCH,     "sp_cursorfetch"    },
>     {TDS_SP_CURSOROPTION,    "sp_cursoroption"   },
>     {TDS_SP_CURSORCLOSE,     "sp_cursorclose"    },
>     {TDS_SP_EXECUTESQL,      "sp_executesql"     },
>     {TDS_SP_PREPARE,         "sp_prepare"        },
>     {TDS_SP_EXECUTE,         "sp_execute"        },
>     {TDS_SP_PREPEXEC,        "sp_prepexec"       },
>     {TDS_SP_PREPEXECRPC,     "sp_prepexecrpc"    },
>     {TDS_SP_UNPREPARE,       "sp_unprepare"      },
> 	{0,                      NULL                },
> };
> 
404c508
< 	{7, "Collation Info"},
---
>         {7, "Collation Info"},
457c561
< #define tds_column_init_count 10
---
> #define tds_column_init_count 40
461a566
> 
471a577,654
> /*  */
> 
> static guint16
> tds_tvb_get_xxtohs(tvbuff_t *tvb, gint offset, gint tds_little_endian) {
>     if (tds_little_endian)
>         return tvb_get_letohs(tvb, offset);
>     else
>         return tvb_get_ntohs(tvb, offset);
> }
> 
> static guint32
> tds_tvb_get_xxtohl(tvbuff_t *tvb, gint offset, gint tds_little_endian) {
>     if (tds_little_endian)
>         return tvb_get_letohl(tvb, offset);
>     else
>         return tvb_get_ntohl(tvb, offset);
> }
> 
> 
> static int tds_token_is_fixed_size(guint8 token)
> {
>      switch (token) {
>           case TDS_DONE_TOKEN:
>           case TDS_DONEPROC_TOKEN:
>           case TDS_DONEINPROC_TOKEN:
>           case TDS_RET_STAT_TOKEN:
>           case TDS7_RESULT_TOKEN:
>           case TDS_PROCID_TOKEN:
>           case TDS_LOGOUT_TOKEN:
>                return 1;
>           default:
>                return 0;
>      }
> }
> 
> 
> static int tds_get_fixed_token_size(guint8 token)
> {
>      switch(token) {
>           case TDS_DONE_TOKEN:
>           case TDS_DONEPROC_TOKEN:
>           case TDS_DONEINPROC_TOKEN:
>           case TDS_PROCID_TOKEN:
>                return 8;
>           case TDS_RET_STAT_TOKEN:
>                return 4;
>           case TDS_LOGOUT_TOKEN:
>                return 1;
>           case TDS7_RESULT_TOKEN:
>           default:
>                return 0;
>      }
> }
> 
> static guint tds_get_variable_token_size(tvbuff_t *tvb, gint offset, guint8 token, guint *len_field_size_p)
> {
>     switch(token) {
>         /* some tokens have a 4 byte length field */
>         case TDS5_PARAMFMT2_TOKEN:
>         case TDS_LANG_TOKEN:
>         case TDS5_ORDERBY2_TOKEN:
>         case TDS5_CURDECLARE2_TOKEN:
>         case TDS5_ROWFMT2_TOKEN:
>         case TDS5_DYNAMIC2_TOKEN:
>             *len_field_size_p = 4;
>             return tds_tvb_get_xxtohl(tvb, offset, tds_little_endian) + 5;
>         /* some have a 1 byte length field */
>         case TDS5_MSG_TOKEN:
>             *len_field_size_p = 1;
>             return tvb_get_guint8(tvb, offset) +2;
>         /* and most have a 2 byte length field */
>         default:
>             *len_field_size_p = 2;
>             return tds_tvb_get_xxtohs(tvb, offset, tds_little_endian) + 3;
>     }
> }
> 
> 
486c669,671
< 	if((len < 2) || tvb_get_guint8(tvb, offset+1) !=0)
---
> 
>     if( TDS_PROTO_PREF_TDS4 || 
>         !TDS_PROTO_PREF_TDS7_TDS8 && ((len < 2) || tvb_get_guint8(tvb, offset+1) !=0) )
489c674
< 	if (is_unicode) {
---
> 	if (is_unicode)
491,494c676,755
< 		proto_tree_add_text(query_tree, tvb, offset, len, "Query: %s", msg);
< 		g_free(msg);
< 		offset += len;
< 	}
---
>     else
>         msg = tvb_get_string(tvb, offset, len);
> 	
>     proto_tree_add_text(query_tree, tvb, offset, len, "Query: %s", msg);
> 	g_free(msg);
> 	offset += len;
> }
> 
> 
> static void 
> dissect_tds5_lang_token(tvbuff_t *tvb, guint offset, guint len, proto_tree *tree) {
>     gboolean is_unicode = FALSE;
>     char *msg;
> 
>     proto_tree_add_text(tree, tvb, offset, 1 , "Status: %u", tvb_get_guint8(tvb, offset));
>     offset += 1;
>     len    -= 1;
> 
>    	if (is_unicode)
> 		msg = tvb_fake_unicode(tvb, offset, (len)/2, TRUE);
>     else
>         msg = tvb_get_string(tvb, offset, len);
> 	
>     proto_tree_add_text(tree, tvb, offset, len, "Language text: %s", msg);
> 	g_free(msg);
> }
> 
> static void
> dissect_tds_query5_packet(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
> {
> 	guint offset;
>     guint pos;
>     guint token_len_field_size = 2;
> 	guint8 token;
>     guint token_sz;
> 	proto_item *query_hdr;
> 	proto_tree *query_tree;
> 	proto_item *token_item;
> 	proto_tree *token_tree;
> 	
> 	offset = 0;
> 	query_hdr = proto_tree_add_text(tree, tvb, offset, -1, "TDS5 Query Packet");
> 	query_tree = proto_item_add_subtree(query_hdr, ett_tds7_query);
> 
>    	/*
> 	 * Until we reach the end of the packet, read tokens.
> 	 */
> 	pos = offset;
> 	while (tvb_reported_length_remaining(tvb, pos) > 0) {
> 
>         /* our token */
> 		token = tvb_get_guint8(tvb, pos);
>         if (tds_token_is_fixed_size(token))
> 			token_sz = tds_get_fixed_token_size(token) + 1;
> 		else
>             token_sz = tds_get_variable_token_size(tvb, pos+1, token, &token_len_field_size);
> 
>         token_item = proto_tree_add_text(tree, tvb, pos, token_sz,
>                     "Token 0x%02x %s", token,
>                     val_to_str(token, token_names, "Unknown Token Type"));
> 		token_tree = proto_item_add_subtree(token_item, ett_tds_token);
> 
> 		/*
> 		 * If it's a variable token, put the length field in here
> 		 * instead of replicating this for each token subdissector.
> 		 */
> 		if (!tds_token_is_fixed_size(token))
> 			proto_tree_add_text(token_tree, tvb, pos+1, token_len_field_size, "Length: %u", token_sz);
> 
>         switch (token) {
>             case TDS_LANG_TOKEN:
>                 dissect_tds5_lang_token(tvb, pos + 5, token_sz -5, token_tree);
>                 break;
>             default:
>                 break;
>         }
> 
>         pos += token_sz;
> 
>     }  /* while */
496a758
> 
523c785,786
< 	proto_tree_add_uint(header_tree, hf_tds7_login_total_size, tvb, offset, sizeof(td7hdr.total_packet_size), td7hdr.total_packet_size);
---
> 	proto_tree_add_uint(header_tree, hf_tds7_login_total_size, tvb, offset, 
>         sizeof(td7hdr.total_packet_size), td7hdr.total_packet_size);
632,660d894
< static int tds_is_fixed_token(int token)
< {
<      switch (token) {
<           case TDS_DONE_TOKEN:
<           case TDS_DONEPROC_TOKEN:
<           case TDS_DONEINPROC_TOKEN:
<           case TDS_RET_STAT_TOKEN:
<           case TDS7_RESULT_TOKEN:
<                return 1;
<           default:
<                return 0;
<      }
< }
< static int tds_get_token_size(int token)
< {
<      switch(token) {
<           case TDS_DONE_TOKEN:
<           case TDS_DONEPROC_TOKEN:
<           case TDS_DONEINPROC_TOKEN:
<                return 8;
<           case TDS_RET_STAT_TOKEN:
<                return 4;
<           case TDS_124_TOKEN:
<                return 8;
<           default:
<                return 0;
<      }
< }
< 
716a951,1003
>  * Process TDS 4 "COL_INFO" token and store relevant information in the 
>  * _netlib_data structure for later use (see tds_get_row_size)
>  * 
>  * XXX Can TDS 4 be "big-endian" ? we'll assume yes.
>  *
>  */
> static gboolean
> dissect_tds_col_info_token(tvbuff_t *tvb, struct _netlib_data *nl_data, guint offset)
> {
>     guint next, cur;
> 	guint col;
> 
>   	next = offset + tds_tvb_get_xxtohs(tvb, offset+1, tds_little_endian) + 3;
> 	cur = offset + 3;
> 
>     col = 0;
>     while (cur < next) {
> 
>     	if (col >= MAX_COLUMNS) {
> 	    	nl_data->num_cols = 0;
> 		    return FALSE;
>         }
>         
>         nl_data->columns[col] = g_mem_chunk_alloc(tds_column);
> 
>         nl_data->columns[col]->name[0] ='\0'; 
> 
>         nl_data->columns[col]->utype = tds_tvb_get_xxtohs(tvb, cur, tds_little_endian);
> 		cur += 2;
> 
> 		cur += 2; /* unknown */
> 
> 		nl_data->columns[col]->ctype = tvb_get_guint8(tvb,cur);
> 		cur++;
> 
> 		if (!is_fixed_coltype(nl_data->columns[col]->ctype)) {
> 			nl_data->columns[col]->csize = tvb_get_guint8(tvb,cur);
> 			cur ++;
> 		} else {
> 			nl_data->columns[col]->csize =
> 			    get_size_by_coltype(nl_data->columns[col]->ctype);
> 		}
> 
>         col += 1;
> 
>     } /* while */
> 
>     nl_data->num_cols = col;
>     return TRUE;
> }
> 
> 
> /*
718a1006,1007
>  *
>  * TODO: check we don't go past end of the token
721c1010
< read_results_tds5(tvbuff_t *tvb, struct _netlib_data *nl_data, guint offset)
---
> read_results_tds5(tvbuff_t *tvb, struct _netlib_data *nl_data, guint offset, guint len)
723c1012
< 	guint len, name_len;
---
>     guint name_len;
727,728c1016
< 	len = tvb_get_letohs(tvb, offset+1);
< 	cur = offset + 3;
---
> 	cur = offset;
732a1021
>      * XXX: We'll take a hint
734c1023
< 	nl_data->num_cols = tvb_get_letohs(tvb, cur);
---
> 	nl_data->num_cols = tds_tvb_get_xxtohs(tvb, cur, tds_little_endian);
750c1039
< 		nl_data->columns[i]->utype = tvb_get_letohs(tvb, cur);
---
> 		nl_data->columns[i]->utype = tds_tvb_get_xxtohs(tvb, cur, tds_little_endian);
810,815d1098
< 	/* check if it is MS SQL default port */
< 	} else if ((pinfo->srcport != 1433 &&
< 		pinfo->destport != 1433) && (pinfo->srcport != 2433 && pinfo->destport != 2433)) {
< 		/* otherwise, we can not ensure this is netlib */
< 		/* beyond a reasonable doubt.                  */
<           		return FALSE;
816a1100,1108
>     /*
>      * See if either tcp.destport or tcp.srcport is specified
>      * in the preferences as being a TDS port.
>      */
>     else if (!value_is_in_range(tds_tcp_ports, pinfo->srcport) && 
>              !value_is_in_range(tds_tcp_ports, pinfo->destport)) {
>              return FALSE;
>     }
> 
903c1195
< 	proto_tree_add_text(tree, tvb, offset, 4, "SQL Error Number: %d", tvb_get_letohl(tvb, offset));
---
> 	proto_tree_add_text(tree, tvb, offset, 4, "SQL Error Number: %d", tds_tvb_get_xxtohl(tvb, offset, tds_little_endian));
910c1202
< 	msg_len = tvb_get_letohs(tvb, offset);
---
> 	msg_len = tds_tvb_get_xxtohs(tvb, offset, tds_little_endian);
959c1251
< 	proto_tree_add_text(tree, tvb, offset, 2, "line number: %d", tvb_get_letohs(tvb, offset));
---
> 	proto_tree_add_text(tree, tvb, offset, 2, "line number: %d", tds_tvb_get_xxtohs(tvb, offset, tds_little_endian));
1083c1375
< 	proto_tree_add_text(tree, tvb, offset, 4, "row count: %u", tvb_get_letohl(tvb, offset));
---
> 	proto_tree_add_text(tree, tvb, offset, 4, "row count: %u", tds_tvb_get_xxtohl(tvb, offset, tds_little_endian));
1092c1384,1385
< 	const char *val;
---
>     guint16 sp_id;
> 	char *val;
1096d1388
< 	 * XXX - how can we determine whether this is ASCII or Unicode?
1098,1109c1390,1423
< 	len = tvb_get_letohs(tvb, offset);
< 	proto_tree_add_text(tree, tvb, offset, 2, "RPC Name Length: %u", len);
< 	offset += 2;
< 	if (len != 0) {
< 		val = tvb_fake_unicode(tvb, offset, len, TRUE);
< 		len *= 2;
< 		proto_tree_add_text(tree, tvb, offset, len, "RPC Name: %s",
< 		    val);
< 		offset += len;
< 	}
< 	
< 	proto_tree_add_text(tree, tvb, offset, -1, "Unknown data");
---
>     switch(tds_protocol_type) {
>         case TDS_PROTOCOL_4:
>             len = tvb_get_guint8(tvb, offset);
>         	proto_tree_add_text(tree, tvb, offset, 1, "RPC Name Length: %u", len);
>         	offset += 1;
>             val = tvb_get_string(tvb, offset, len);
>             proto_tree_add_text(tree, tvb, offset, len, "RPC Name: %s", val);
>             g_free(val);
>             offset += len;
>             break;
> 
>         case TDS_PROTOCOL_7:
>         case TDS_PROTOCOL_8:
>         default:      /* unspecified: try as if TDS7/TDS8 */
>             len = tvb_get_letohs(tvb, offset);
>         	proto_tree_add_text(tree, tvb, offset, 2, "RPC Name Length: %u", len);
>         	offset += 2;
>             if (len == 0xFFFF) {
>                 sp_id = tvb_get_letohs(tvb, offset);
>                 proto_tree_add_text(tree, tvb, offset, 2, "RPC Stored Proc ID: %u (%s)", 
>                                     sp_id,
>                                     val_to_str(sp_id, internal_stored_proc_id_names, "Unknown"));
>                 offset += 2;
>             }
>         	else if (len != 0) {
> 	    	    val = tvb_fake_unicode(tvb, offset, len, TRUE);
> 		        len *= 2;
> 		        proto_tree_add_text(tree, tvb, offset, len, "RPC Name: %s", val);
>                 g_free(val);
> 		        offset += len;
> 	        }
>             break;
>     }
> 	proto_tree_add_text(tree, tvb, offset, -1, "Params (not dissected)");
1118a1433
>     guint token_len_field_size = 2;
1123c1438,1440
< 	memset(&nl_data, '\0', sizeof nl_data);
---
>     g_mem_chunk_reset(tds_column);   /* in case exception thrown the previous time thru this code */
> 
>     memset(&nl_data, '\0', sizeof nl_data);
1133,1134c1450,1452
< 		if (tds_is_fixed_token(token)) {
< 			token_sz = tds_get_token_size(token) + 1;
---
>         /* TODO Handle TDS_PARAMFMT, TDS_PARAMS [similar to TDS_RESULTS, TDS_ROW] */
>         if (tds_token_is_fixed_size(token)) {
> 			token_sz = tds_get_fixed_token_size(token) + 1;
1142c1460
< 			token_sz = tvb_get_letohs(tvb, pos + 1) + 3;
---
>             token_sz = tds_get_variable_token_size(tvb, pos+1, token, &token_len_field_size);
1145,1146d1462
< 		if (token_sz > (guint)length_remaining)
< 			token_sz = (guint)length_remaining;
1157,1159c1473,1474
< 		if (!tds_is_fixed_token(token) && token != TDS_ROW_TOKEN) {
< 			proto_tree_add_text(token_tree, tvb, pos+1, 2,
< 			    "Length: %u", tvb_get_letohs(tvb, pos+1));
---
> 		if (!tds_token_is_fixed_size(token) && token != TDS_ROW_TOKEN) {
> 			proto_tree_add_text(token_tree, tvb, pos+1, token_len_field_size, "Length: %u", token_sz);
1162c1477,1494
< 		switch (token) {
---
> 		if (token_sz > (guint)length_remaining)
> 			token_sz = (guint)length_remaining;
> 
>         switch (token) {
> 
>         case TDS_COL_NAME_TOKEN:
>             /*
>              * TDS 4.2
>              * TODO dissect token to get "column names" to fill in _netlib_data
>              */
>             break;
> 
>         case TDS_COL_INFO_TOKEN:
>             /*
>              * TDS 4.2: get the column info 
>              */
>             dissect_tds_col_info_token(tvb, &nl_data, pos);
>             break;
1164c1496
< 		case TDS_RESULT_TOKEN:
---
>         case TDS_RESULT_TOKEN:
1169c1501
< 			read_results_tds5(tvb, &nl_data, pos);
---
> 			read_results_tds5(tvb, &nl_data, pos + 3, token_sz - 3);
1173,1174c1505
< 			dissect_tds_env_chg(tvb, pos + 3, token_sz - 3,
< 			    token_tree);
---
> 			dissect_tds_env_chg(tvb, pos + 3, token_sz - 3, token_tree);
1178,1179c1509
< 			dissect_tds_ntlmssp(tvb, pinfo, token_tree, pos + 3,
< 			    token_sz - 3);
---
> 			dissect_tds_ntlmssp(tvb, pinfo, token_tree, pos + 3, token_sz - 3);
1184a1515
> 
1186c1517,1519
< 			dissect_tds_done_token(tvb, pos + 1, token_tree);
---
>         case TDS_DONEPROC_TOKEN:
>         case TDS_DONEINPROC_TOKEN:
>             dissect_tds_done_token(tvb, pos + 1, token_tree);
1198a1532,1534
>     /* reset tds_column mem_chunk since finished processing response */
>     /*  (pointers to atoms in nl_data being discarded) */
>     g_mem_chunk_reset(tds_column);
1254a1591,1594
>      *
>      * TODO: handle case where netlib headers 'packet-number'.is always 0
>      *       use fragment_add_seq_next in this case ?
>      *       
1293c1633,1635
< 	if (next_tvb != NULL) {
---
> 
>     if (next_tvb != NULL) {
> 
1310c1652,1655
< 		case TDS_NTLMAUTH_PKT:
---
>         case TDS_QUERY5_PKT:
>             dissect_tds_query5_packet(next_tvb, pinfo, tds_tree);
>             break;
>         case TDS_NTLMAUTH_PKT:
1492c1837
< 	/*
---
>     /*
1738c2083,2084
< 	static gint *ett[] = {
---
> 
>     static gint *ett[] = {
1756,1757d2101
< 	tds_tcp_handle = create_dissector_handle(dissect_tds_tcp, proto_tds);
< 
1767a2112,2125
>     prefs_register_enum_preference(tds_module, "protocol_type",
>         "TDS Protocol Type",
>         "Hint as to version of TDS protocol being decoded",
>         &tds_protocol_type,
> 	    tds_protocol_type_options, FALSE);
>     prefs_register_enum_preference(tds_module, "endian_type",
>         "TDS decode as ",
>         "Hint as to whether to decode TDS protocol as little-endian or big-endian. (TDS7/8 always decoded as little-endian)",
>         &tds_little_endian,
> 	    tds_endian_type_options, FALSE);
>     prefs_register_range_preference(tds_module, "tcp_ports",
>         "TDS TCP ports",
> 	    "Additional TCP ports to decode as TDS",
> 	    &tds_tcp_ports, 0xFFFF);
1779,1781c2137,2143
< 	/* dissector_add("tcp.port", 1433, dissect_tds,
< 	    proto_tds); */
< 	heur_dissector_add("tcp", dissect_tds_tcp_heur, proto_tds);
---
> 	tds_tcp_handle = create_dissector_handle(dissect_tds_tcp, proto_tds);
> 
>     /* Initial TDS ports: MS SQL default ports */
>     dissector_add("tcp.port", 1433, tds_tcp_handle);
>     dissector_add("tcp.port", 2433, tds_tcp_handle);
> 
>     heur_dissector_add("tcp", dissect_tds_tcp_heur, proto_tds);