Fix for bug 5422:
[obnox/wireshark/wip.git] / epan / dissectors / packet-tds.c
1 /* packet-tds.c
2  * Routines for TDS NetLib dissection
3  * Copyright 2000-2002, Brian Bruns <camber@ais.org>
4  * Copyright 2002, Steve Langasek <vorlon@netexpress.net>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*
28  * The NETLIB protocol is a small blocking protocol designed to allow TDS
29  * to be placed within different transports (TCP, DECNet, IPX/SPX).  A
30  * NETLIB packet starts with an eight byte header containing:
31  *
32  *      a one-byte packet type field;
33  *
34  *      a one-byte status field;
35  *
36  *      a two-byte big-endian size field giving the size of the packet,
37  *      including the header;
38  *
39  *      a two-byte big-endian channel number, used when multiple sessions
40  *      are being multiplexed on a single connection;
41  *
42  *      a one-byte packet number, giving "the frame number of a multiplexed
43  *      message, modulo 256";
44  *
45  *      a one-byte window, which is the number of frames to be sent
46  *      before an acknowledgment message is received.
47  *
48  * followed by payload whose size is the value in the size field minus
49  * 8.
50  *
51  * Microsoft Network Monitor 2.x dissects the 4 byte field (and indicates
52  * that the one-byte last packet indicator also contains other bits).
53  *
54  * The TDS protocol consists of a number of protocol data units (PDUs) that
55  * appear to be assembled from NETLIB packets, in the form of zero or more
56  * NETLIB packets with the last packet indicator clear and a final NETLIB
57  * packet with the last packet indicator set.  The type of the TDS PDU is
58  * specified by the packet type field of the NETLIB header (presumably that
59  * field has the same value for all NETLIB packets that make up a TDS PDU).
60  *
61  * The "server response" PDU consists of a sequence of multiple items, each
62  * one beginning with a one byte type field at the start of the PDU.  Some
63  * items are fixed length, some are variable length with a two byte size
64  * field following the item type, and then there is TDS_ROW_TOKEN in which
65  * size is determined by analyzing the result set returned from the server.
66  * This in effect means that we are hopelessly lost if we haven't seen the
67  * result set.  Also, TDS 4/5 is byte order negotiable, which is specified
68  * in the login packet.  We can attempt to determine it later on, but not
69  * with 100% accuracy.
70  *
71  * Some preliminary documentation on the packet format can be found at
72  * http://www.freetds.org/tds.html
73  *
74  * Some more information can be found in
75  * http://download.nai.com/products/media/sniffer/support/sdos/sybase.pdf
76  *
77  * Much of this code was originally developed for the FreeTDS project.
78  * http://www.freetds.org
79  */
80
81 /*
82  * Excerpts from Brian's posting to wireshark-dev:
83  *
84  * The TDS Protocol is actually a protocol within a protocol.  On the outside
85  * there is netlib which is not so much a encapsulation as a blocking of the
86  * data, typically to 512 or 4096 bytes.  Between this are the protocol data
87  * units for TDS.  Netlib packets may be split over real packets, multiple
88  * netlib packets may appear in single real packets.  TDS PDUs may be split
89  * over netlib packets (and real packets) and most certainly can appear
90  * multiple times within a netlib packet.
91  *
92  * Because of this, I abandoned my earlier attempt at making two dissectors,
93  * one for netlib and one for TDS. Counterintuitively, a single dissector
94  * turned out to be simpler than splitting it up.
95  *
96  * Here are some of the (hefty) limitations of the current code
97  *
98  * . We currently do not handle netlib headers that cross packet boundaries.
99  *   This should be an easy fix.
100  * . I probably could have used the packet reassembly stuff, but I started
101  *   this at version 0.8.20, so c'est la vie. It wouldn't have covered the
102  *   netlib stuff anyway, so no big loss.
103  * . The older two layer version of the code dissected the PDU's, but the new
104  *   version does not yet, it only labels the names. I need an elegant way to
105  *   deal with dissecting data crossing (netlib and tcp) packet boundries.  I
106  *   think I have one, but ran out of time to do it.
107  * . It will only work on little endian platforms.  Or rather I should say,
108  *   the client that was captured must be little endian.  TDS 7.0/8.0 is
109  *   always LE; for TDS 4.2/5.0 look in the code for tvb_get_le*() functions,
110  *   there are fields in the login packet which determine byte order.
111  * . result sets that span netlib packets are not working
112  * . TDS 7 and 4.2 result sets are not working yet
113  *
114  * All that said, the code does deal gracefully with different boudary
115  * conditions and what remains are the easier bits, IMHO.
116  *
117  * XXX - "real packets" means "TCP segments", for TCP.
118  *
119  * XXX - is it *REALLY* true that you can have more than one TDS PDU (as
120  * opposed to more than one server response item) per NETLIB packet?  Or is
121  * all the data in a NETLIB packet put into a single TDS PDU?  If so, then
122  * we can reassemble NETLIB packets using the standard TCP desegmentation
123  * code, and can reassemble TDS PDUs using "fragment_add_seq_check()",
124  * and more cleanly separate the NETLIB and TDS dissectors (although the
125  * "is this NETLIB" heuristic would have to look at TDS information past
126  * the NETLIB header, in order to make the heuristic strong enough not
127  * to get too many false positives; note that the heuristic should reject
128  * any putative NETLIB packet with a length field with a value < 8).
129  *
130  * That would substantially clean the dissector up, eliminating most of
131  * the per-packet data (we might still need information to handle
132  * TDS_ROW_TOKEN), getting rid of the stuff to handle data split across
133  * TCP segment boundaries in favor of simple reassembly code, and
134  * fixing some otherwise nasty-looking crashing bugs.
135  *
136  * NOTE: we assume that all the data in a NETLIB packet *can* be put into
137  * a single TDS PTU, so that we have separate reassembly of NETLIB
138  * packets and TDS PDUs; it seems to work, and it really did clean stuff
139  * up and fix crashes.
140  */
141
142 #ifdef HAVE_CONFIG_H
143 # include "config.h"
144 #endif
145
146 #include <stdlib.h>
147 #include <string.h>
148 #include <ctype.h>
149
150 #include <glib.h>
151
152 #include "isprint.h"
153
154 #include <epan/packet.h>
155 #include <epan/conversation.h>
156 #include <epan/strutil.h>
157
158 #include "packet-frame.h"
159 #include <epan/reassemble.h>
160 #include <epan/prefs.h>
161 #include <epan/emem.h>
162
163 #define TDS_QUERY_PKT        1
164 #define TDS_LOGIN_PKT        2
165 #define TDS_RPC_PKT          3
166 #define TDS_RESP_PKT         4
167 #define TDS_RAW_PKT          5
168 #define TDS_CANCEL_PKT       6
169 #define TDS_BULK_DATA_PKT    7
170 #define TDS_OPEN_CHN_PKT     8
171 #define TDS_CLOSE_CHN_PKT    9
172 #define TDS_RES_ERROR_PKT   10
173 #define TDS_LOG_CHN_ACK_PKT 11
174 #define TDS_ECHO_PKT        12
175 #define TDS_LOGOUT_CHN_PKT  13
176 #define TDS_QUERY5_PKT      15  /* or "Normal tokenized request or response */
177 #define TDS_LOGIN7_PKT      16  /* or "Urgent tokenized request or response */
178 #define TDS_NTLMAUTH_PKT    17
179 #define TDS_XXX7_PKT        18  /* seen in one capture */
180
181 #define is_valid_tds_type(x) ((x) >= TDS_QUERY_PKT && (x) <= TDS_XXX7_PKT)
182
183 /* The following constants are imported more or less directly from FreeTDS */
184 /*      Updated from FreeTDS v0.63 tds.h                                   */
185 /*         "$Id: tds.h,v 1.192 2004/10/28 12:42:12 freddy77]"              */
186 /* Note: [###] below means 'not defined in FreeTDS tds.h'                  */
187
188 #define TDS5_PARAMFMT2_TOKEN       32  /* 0x20    TDS 5.0 only              */
189 #define TDS_LANG_TOKEN             33  /* 0x21    TDS 5.0 only              */
190 #define TDS5_ORDERBY2_TOKEN        34  /* 0x22    TDS 5.0 only              */
191 #define TDS5_CURDECLARE2_TOKEN     35  /* 0x23    TDS 5.0 only        [###] */
192 #define TDS5_ROWFMT2_TOKEN         97  /* 0x61    TDS 5.0 only              */
193 #define TDS5_MSG_TOKEN            101  /* 0x65    TDS 5.0 only        [###] */
194 #define TDS_LOGOUT_TOKEN          113  /* 0x71    TDS 5.0 only? ct_close()  */
195 #define TDS_RET_STAT_TOKEN        121  /* 0x79                              */
196 #define TDS_PROCID_TOKEN          124  /* 0x7C    TDS 4.2 only - TDS_PROCID */
197 #define TDS_CURCLOSE_TOKEN        128  /* 0x80    TDS 5.0 only              */
198 #define TDS7_RESULT_TOKEN         129  /* 0x81    TDS 7.0 only              */
199 #define TDS_CURFETCH_TOKEN        130  /* 0x82    TDS 5.0 only              */
200 #define TDS_CURINFO_TOKEN         131  /* 0x83    TDS 5.0 only              */
201 #define TDS_CUROPEN_TOKEN         132  /* 0x84    TDS 5.0 only              */
202 #define TDS_CURDECLARE_TOKEN      134  /* 0x86    TDS 5.0 only              */
203 #define TDS7_COMPUTE_RESULT_TOKEN 136  /* 0x88    TDS 7.0 only              */
204 #define TDS_COL_NAME_TOKEN        160  /* 0xA0    TDS 4.2 only              */
205 #define TDS_COL_INFO_TOKEN        161  /* 0xA1    TDS 4.2 only - TDS_COLFMT */
206 #define TDS5_DYNAMIC2_TOKEN       163  /* 0xA3    TDS 5.0 only              */
207 #if 0 /* XX: Why commented out ? These are 'live' in FreeTDS tds.h */
208 #define TDS_TABNAME               164  /* 0xA4                              */
209 #define TDS_COL_INFO              165  /* 0xA5                              */
210 #endif
211 #define TDS_OPTIONCMD_TOKEN       166  /* 0xA6 */
212 #define TDS_COMPUTE_NAMES_TOKEN   167  /* 0xA7 */
213 #define TDS_COMPUTE_RESULT_TOKEN  168  /* 0xA8 */
214 #define TDS_ORDER_BY_TOKEN        169  /* 0xA9    TDS_ORDER                 */
215 #define TDS_ERR_TOKEN             170  /* 0xAA                              */
216 #define TDS_MSG_TOKEN             171  /* 0xAB                              */
217 #define TDS_PARAM_TOKEN           172  /* 0xAC    RETURNVALUE?              */
218 #define TDS_LOGIN_ACK_TOKEN       173  /* 0xAD                              */
219 #define TDS_CONTROL_TOKEN         174  /* 0xAE    TDS_CONTROL               */
220 #define TDS_KEY_TOKEN             202  /* 0xCA                        [###] */
221 #define TDS_ROW_TOKEN             209  /* 0xD1                              */
222 #define TDS_CMP_ROW_TOKEN         211  /* 0xD3                              */
223 #define TDS5_PARAMS_TOKEN         215  /* 0xD7    TDS 5.0 only              */
224 #define TDS_CAP_TOKEN             226  /* 0xE2                              */
225 #define TDS_ENV_CHG_TOKEN         227  /* 0xE3                              */
226 #define TDS_EED_TOKEN             229  /* 0xE5                              */
227 #define TDS_DBRPC_TOKEN           230  /* 0xE6                              */
228 #define TDS5_DYNAMIC_TOKEN        231  /* 0xE7    TDS 5.0 only              */
229 #define TDS5_PARAMFMT_TOKEN       236  /* 0xEC    TDS 5.0 only              */
230 #define TDS_AUTH_TOKEN            237  /* 0xED                              */
231 #define TDS_RESULT_TOKEN          238  /* 0xEE                              */
232 #define TDS_DONE_TOKEN            253  /* 0xFD    TDS_DONE                  */
233 #define TDS_DONEPROC_TOKEN        254  /* 0xFE    TDS_DONEPROC              */
234 #define TDS_DONEINPROC_TOKEN      255  /* 0xFF    TDS_DONEINPROC            */
235
236 /* Microsoft internal stored procedure id's */
237
238 #define TDS_SP_CURSOR           1
239 #define TDS_SP_CURSOROPEN       2
240 #define TDS_SP_CURSORPREPARE    3
241 #define TDS_SP_CURSOREXECUTE    4
242 #define TDS_SP_CURSORPREPEXEC   5
243 #define TDS_SP_CURSORUNPREPARE  6
244 #define TDS_SP_CURSORFETCH      7
245 #define TDS_SP_CURSOROPTION     8
246 #define TDS_SP_CURSORCLOSE      9
247 #define TDS_SP_EXECUTESQL      10
248 #define TDS_SP_PREPARE         11
249 #define TDS_SP_EXECUTE         12
250 #define TDS_SP_PREPEXEC        13
251 #define TDS_SP_PREPEXECRPC     14
252 #define TDS_SP_UNPREPARE       15
253
254 /* Sybase Data Types */
255
256 #define SYBCHAR        47  /* 0x2F */
257 #define SYBVARCHAR     39  /* 0x27 */
258 #define SYBINTN        38  /* 0x26 */
259 #define SYBINT1        48  /* 0x30 */
260 #define SYBINT2        52  /* 0x34 */
261 #define SYBINT4        56  /* 0x38 */
262 #define SYBINT8       127  /* 0x7F */
263 #define SYBFLT8        62  /* 0x3E */
264 #define SYBDATETIME    61  /* 0x3D */
265 #define SYBBIT         50  /* 0x32 */
266 #define SYBTEXT        35  /* 0x23 */
267 #define SYBNTEXT       99  /* 0x63 */
268 #define SYBIMAGE       34  /* 0x22 */
269 #define SYBMONEY4     122  /* 0x7A */
270 #define SYBMONEY       60  /* 0x3C */
271 #define SYBDATETIME4   58  /* 0x3A */
272 #define SYBREAL        59  /* 0x3B */
273 #define SYBBINARY      45  /* 0x2D */
274 #define SYBVOID        31  /* 0x1F */
275 #define SYBVARBINARY   37  /* 0x25 */
276 #define SYBNVARCHAR   103  /* 0x67 */
277 #define SYBBITN       104  /* 0x68 */
278 #define SYBNUMERIC    108  /* 0x6C */
279 #define SYBDECIMAL    106  /* 0x6A */
280 #define SYBFLTN       109  /* 0x6D */
281 #define SYBMONEYN     110  /* 0x6E */
282 #define SYBDATETIMN   111  /* 0x6F */
283 #define XSYBCHAR      175  /* 0xA7 */
284 #define XSYBVARCHAR   167  /* 0xAF */
285 #define XSYBNVARCHAR  231  /* 0xE7 */
286 #define XSYBNCHAR     239  /* 0xEF */
287 #define XSYBVARBINARY 165  /* 0xA5 */
288 #define XSYBBINARY    173  /* 0xAD */
289 #define SYBLONGBINARY 225  /* 0xE1 */
290 #define SYBSINT1       64  /* 0x40 */
291 #define SYBUINT2       65  /* 0x41 */
292 #define SYBUINT4       66  /* 0x42 */
293 #define SYBUINT8       67  /* 0x43 */
294 #define SYBUNIQUE      36  /* 0x24 */
295 #define SYBVARIANT     98  /* 0x62 */
296
297 #define is_fixed_coltype(x) (x==SYBINT1    ||           \
298                              x==SYBINT2      ||         \
299                              x==SYBINT4      ||         \
300                              x==SYBINT8      ||         \
301                              x==SYBREAL       ||        \
302                              x==SYBFLT8      ||         \
303                              x==SYBDATETIME  ||         \
304                              x==SYBDATETIME4 ||         \
305                              x==SYBBIT       ||         \
306                              x==SYBMONEY     ||         \
307                              x==SYBMONEY4    ||         \
308                              x==SYBUNIQUE)
309
310 /* Initialize the protocol and registered fields */
311 static int proto_tds = -1;
312 static int hf_tds_type = -1;
313 static int hf_tds_status = -1;
314 static int hf_tds_size = -1;
315 static int hf_tds_channel = -1;
316 static int hf_tds_packet_number = -1;
317 static int hf_tds_window = -1;
318 static int hf_tds_reassembled_in = -1;
319 static int hf_tds_reassembled_length = -1;
320 static int hf_tds_fragments = -1;
321 static int hf_tds_fragment = -1;
322 static int hf_tds_fragment_overlap = -1;
323 static int hf_tds_fragment_overlap_conflict = -1;
324 static int hf_tds_fragment_multiple_tails = -1;
325 static int hf_tds_fragment_too_long_fragment = -1;
326 static int hf_tds_fragment_error = -1;
327
328 static int hf_tds7_login_total_size = -1;
329 static int hf_tds7_version = -1;
330 static int hf_tds7_packet_size = -1;
331 static int hf_tds7_client_version = -1;
332 static int hf_tds7_client_pid = -1;
333 static int hf_tds7_connection_id = -1;
334 static int hf_tds7_option_flags1 = -1;
335 static int hf_tds7_option_flags2 = -1;
336 static int hf_tds7_sql_type_flags = -1;
337 static int hf_tds7_reserved_flags = -1;
338 static int hf_tds7_time_zone = -1;
339 static int hf_tds7_collation = -1;
340 static int hf_tds7_message = -1;
341
342 /* Initialize the subtree pointers */
343 static gint ett_tds = -1;
344 static gint ett_tds_fragments = -1;
345 static gint ett_tds_fragment = -1;
346 static gint ett_tds_token = -1;
347 static gint ett_tds7_login = -1;
348 static gint ett_tds7_query = 0;
349 static gint ett_tds7_hdr = -1;
350
351 /* Desegmentation of Netlib buffers crossing TCP segment boundaries. */
352 static gboolean tds_desegment = TRUE;
353
354 static const fragment_items tds_frag_items = {
355     &ett_tds_fragment,
356     &ett_tds_fragments,
357     &hf_tds_fragments,
358     &hf_tds_fragment,
359     &hf_tds_fragment_overlap,
360     &hf_tds_fragment_overlap_conflict,
361     &hf_tds_fragment_multiple_tails,
362     &hf_tds_fragment_too_long_fragment,
363     &hf_tds_fragment_error,
364     &hf_tds_reassembled_in,
365     &hf_tds_reassembled_length,
366     "fragments"
367 };
368
369 /* Tables for reassembly of fragments. */
370 static GHashTable *tds_fragment_table = NULL;
371 static GHashTable *tds_reassembled_table = NULL;
372
373 /* defragmentation of multi-buffer TDS PDUs */
374 static gboolean tds_defragment = TRUE;
375
376 static dissector_handle_t tds_tcp_handle;
377 static dissector_handle_t ntlmssp_handle;
378 static dissector_handle_t gssapi_handle;
379 static dissector_handle_t data_handle;
380
381 /* TDS protocol type preference */
382 /*   XXX: This preference is used as a 'hint' for cases where interpretation is ambiguous */
383 /*        Currently the hint is global                                                    */
384 /*   TODO: Consider storing protocol type with each conversation                          */
385 /*        (when type is determined and using the preference as a default) ??              */
386
387 #define TDS_PROTOCOL_NOT_SPECIFIED   0
388 #define TDS_PROTOCOL_4      4
389 #define TDS_PROTOCOL_5      5
390 #define TDS_PROTOCOL_7      7
391 #define TDS_PROTOCOL_8      8
392
393 static gint tds_protocol_type = TDS_PROTOCOL_NOT_SPECIFIED;
394
395 static const enum_val_t tds_protocol_type_options[] = {
396     {"not_specified", "Not Specified", TDS_PROTOCOL_NOT_SPECIFIED},
397     {"tds4", "TDS 4", TDS_PROTOCOL_4},  /* TDS 4.2 and TDS 4.6 */
398     {"tds5", "TDS 5", TDS_PROTOCOL_5},
399     {"tds7", "TDS 7", TDS_PROTOCOL_7},
400     {"tds8", "TDS 8", TDS_PROTOCOL_8},
401     {NULL, NULL, -1}
402 };
403
404 #define TDS_PROTO_PREF_NOT_SPECIFIED (tds_protocol_type == TDS_NOT_SPECIFIED)
405 #define TDS_PROTO_PREF_TDS4 (tds_protocol_type == TDS_PROTOCOL_4)
406 #define TDS_PROTO_PREF_TDS5 (tds_protocol_type == TDS_PROTOCOL_5)
407 #define TDS_PROTO_PREF_TDS7 (tds_protocol_type == TDS_PROTOCOL_7)
408 #define TDS_PROTO_PREF_TDS8 (tds_protocol_type == TDS_PROTOCOL_8)
409 #define TDS_PROTO_PREF_TDS7_TDS8 ( TDS_PROTO_PREF_TDS7 || TDS_PROTO_PREF_TDS8 )
410
411 /* TDS "endian type" */
412 /*   XXX: Assumption is that all TDS conversations being decoded in a particular capture */
413 /*        have the same endian type                                                      */
414 /*   TODO: consider storing endian type with each conversation                           */
415 /*         (using pref as the default)                                                   */
416
417 static gboolean tds_little_endian = TRUE;
418
419 static const enum_val_t tds_endian_type_options[] = {
420     {"little_endian", "Little Endian", TRUE},
421     {"big_endian"   , "Big Endian"   , FALSE},
422     {NULL, NULL, -1}
423 };
424
425
426 /* TCP port preferences for TDS decode */
427
428 static range_t *tds_tcp_ports = NULL;
429
430 /* These correspond to the netlib packet type field */
431 static const value_string packet_type_names[] = {
432     {TDS_QUERY_PKT,    "Query Packet"},
433     {TDS_LOGIN_PKT,    "Login Packet"},
434     {TDS_RPC_PKT,      "Remote Procedure Call Packet"},
435     {TDS_RESP_PKT,     "Response Packet"},
436     {TDS_CANCEL_PKT,   "Cancel Packet"},
437     {TDS_QUERY5_PKT,   "TDS5 Query Packet"},
438     {TDS_LOGIN7_PKT,   "TDS7/8 Login Packet"},
439     {TDS_XXX7_PKT,     "TDS7/8 0x12 Packet"},
440     {TDS_NTLMAUTH_PKT, "NT Authentication Packet"},
441     {0, NULL},
442 };
443
444 /* The status field */
445
446 #define is_valid_tds_status(x) ((x) <= STATUS_EVENT_NOTIFICATION)
447
448 #define STATUS_NOT_LAST_BUFFER          0x00
449 #define STATUS_LAST_BUFFER              0x01
450 #define STATUS_ATTN_REQUEST_ACK         0x02
451 #define STATUS_ATTN_REQUEST             0x03
452 #define STATUS_EVENT_NOTIFICATION       0x04
453
454 static const value_string status_names[] = {
455     {STATUS_NOT_LAST_BUFFER,    "Not last buffer"},
456     {STATUS_LAST_BUFFER,        "Last buffer in request or response"},
457     {STATUS_ATTN_REQUEST_ACK,   "Acknowledgment of last attention request"},
458     {STATUS_ATTN_REQUEST,       "Attention request"},
459     {STATUS_EVENT_NOTIFICATION, "Event notification"},
460     {0, NULL},
461 };
462
463 /* The one byte token at the start of each TDS PDU */
464 static const value_string token_names[] = {
465     {TDS5_DYNAMIC_TOKEN,        "TDS5 Dynamic SQL"},
466     {TDS5_PARAMFMT_TOKEN,       "TDS5 Parameter Format"},
467     {TDS5_PARAMFMT2_TOKEN,      "TDS5 Parameter2 Format"},
468     {TDS5_PARAMS_TOKEN,         "TDS5 Parameters"},
469     {TDS_LANG_TOKEN,            "Language"},
470     {TDS_LOGOUT_TOKEN,          "Logout"},
471     {TDS_RET_STAT_TOKEN,        "Return Status"},
472     {TDS_PROCID_TOKEN,          "Proc ID"},
473     {TDS7_RESULT_TOKEN,         "TDS7+ Results"},
474     {TDS_COL_NAME_TOKEN,        "Column Names"},
475     {TDS_COL_INFO_TOKEN,        "Column Info"},
476     {TDS_COMPUTE_NAMES_TOKEN,   "Compute Names"},
477     {TDS_COMPUTE_RESULT_TOKEN,  "Compute Results"},
478     {TDS_ORDER_BY_TOKEN,        "Order By"},
479     {TDS_ERR_TOKEN,             "Error Message"},
480     {TDS_MSG_TOKEN,             "Info Message"},
481     {TDS_PARAM_TOKEN,           "Parameter"},
482     {TDS_LOGIN_ACK_TOKEN,       "Login Acknowledgement"},
483     {TDS_CONTROL_TOKEN,         "TDS Control"},
484     {TDS_KEY_TOKEN,             "TDS Key"},
485     {TDS_ROW_TOKEN,             "Row"},
486     {TDS_CMP_ROW_TOKEN,         "Compute Row"},
487     {TDS_CAP_TOKEN,             "Capabilities"},
488     {TDS_ENV_CHG_TOKEN,         "Environment Change"},
489     {TDS_EED_TOKEN,             "Extended Error"},
490     {TDS_AUTH_TOKEN,            "Authentication"},
491     {TDS_RESULT_TOKEN,          "Results"},
492     {TDS_DONE_TOKEN,            "Done"},
493     {TDS_DONEPROC_TOKEN,        "Done Proc"},
494     {TDS_DONEINPROC_TOKEN,      "Done In Proc"},
495     {TDS5_DYNAMIC2_TOKEN,       "TDS5 Dynamic2"},
496     {TDS5_ORDERBY2_TOKEN,       "TDS5 OrderBy2"},
497     {TDS5_CURDECLARE2_TOKEN,    "TDS5 CurDeclare2"},
498     {TDS5_ROWFMT2_TOKEN,        "TDS5 RowFmt2"},
499     {TDS5_MSG_TOKEN,            "TDS5 Msg"},
500     {0, NULL},
501 };
502
503
504 static const value_string internal_stored_proc_id_names[] = {
505     {TDS_SP_CURSOR,          "sp_cursor"         },
506     {TDS_SP_CURSOROPEN,      "sp_cursoropen"     },
507     {TDS_SP_CURSORPREPARE,   "sp_cursorprepare"  },
508     {TDS_SP_CURSOREXECUTE,   "sp_cursorexecute"  },
509     {TDS_SP_CURSORPREPEXEC,  "sp_cursorprepexec" },
510     {TDS_SP_CURSORUNPREPARE, "sp_cursorunprepare"},
511     {TDS_SP_CURSORFETCH,     "sp_cursorfetch"    },
512     {TDS_SP_CURSOROPTION,    "sp_cursoroption"   },
513     {TDS_SP_CURSORCLOSE,     "sp_cursorclose"    },
514     {TDS_SP_EXECUTESQL,      "sp_executesql"     },
515     {TDS_SP_PREPARE,         "sp_prepare"        },
516     {TDS_SP_EXECUTE,         "sp_execute"        },
517     {TDS_SP_PREPEXEC,        "sp_prepexec"       },
518     {TDS_SP_PREPEXECRPC,     "sp_prepexecrpc"    },
519     {TDS_SP_UNPREPARE,       "sp_unprepare"      },
520     {0,                      NULL                },
521 };
522
523 static const value_string env_chg_names[] = {
524     {1, "Database"},
525     {2, "Language"},
526     {3, "Sort Order"},
527     {4, "Blocksize"},
528     {5, "Unicode Locale ID"},
529     {6, "Unicode Comparison Style"},
530     {7, "Collation Info"},
531     {0, NULL},
532 };
533
534 static const value_string login_field_names[] = {
535     {0, "Client Name"},
536     {1, "Username"},
537     {2, "Password"},
538     {3, "App Name"},
539     {4, "Server Name"},
540     {5, "Unknown1"},
541     {6, "Library Name"},
542     {7, "Locale"},
543     {8, "Database Name"},
544     {0, NULL},
545 };
546
547
548 #define MAX_COLUMNS 256
549
550 /*
551  * This is where we store the column information to be used in decoding the
552  * TDS_ROW_TOKEN tokens.
553  */
554 struct _tds_col {
555     gchar name[256];
556     guint16 utype;
557     guint8 ctype;
558     guint csize;
559 };
560
561 struct _netlib_data {
562     guint num_cols;
563     struct _tds_col *columns[MAX_COLUMNS];
564 };
565
566 struct tds7_login_packet_hdr {
567     guint32 total_packet_size;
568     guint32 tds_version;
569     guint32 packet_size;
570     guint32 client_version;
571     guint32 client_pid;
572     guint32 connection_id;
573     guint8  option_flags1;
574     guint8  option_flags2;
575     guint8  sql_type_flags;
576     guint8  reserved_flags;
577     guint32 time_zone;
578     guint32 collation;
579 };
580
581 /* support routines */
582
583 static void
584 dissect_tds_nt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
585                guint offset, guint length)
586 {
587     tvbuff_t *nt_tvb;
588
589     nt_tvb = tvb_new_subset(tvb, offset, -1, length);
590     if(tvb_strneql(tvb, offset, "NTLMSSP", 7) == 0)
591         call_dissector(ntlmssp_handle, nt_tvb, pinfo, tree);
592     else
593         call_dissector(gssapi_handle, nt_tvb, pinfo, tree);
594 }
595
596 /*  */
597
598 static guint16
599 tds_tvb_get_xxtohs(tvbuff_t *tvb, gint offset, gboolean tds_little_endian_flag) {
600     if (tds_little_endian_flag)
601         return tvb_get_letohs(tvb, offset);
602     else
603         return tvb_get_ntohs(tvb, offset);
604 }
605
606 static guint32
607 tds_tvb_get_xxtohl(tvbuff_t *tvb, gint offset, gboolean tds_little_endian_flag) {
608     if (tds_little_endian_flag)
609         return tvb_get_letohl(tvb, offset);
610     else
611         return tvb_get_ntohl(tvb, offset);
612 }
613
614
615 static int
616 tds_token_is_fixed_size(guint8 token)
617 {
618     switch (token) {
619         case TDS_DONE_TOKEN:
620         case TDS_DONEPROC_TOKEN:
621         case TDS_DONEINPROC_TOKEN:
622         case TDS_RET_STAT_TOKEN:
623         case TDS7_RESULT_TOKEN:
624         case TDS_PROCID_TOKEN:
625         case TDS_LOGOUT_TOKEN:
626             return 1;
627         default:
628             return 0;
629     }
630 }
631
632
633 static int
634 tds_get_fixed_token_size(guint8 token)
635 {
636     switch(token) {
637         case TDS_DONE_TOKEN:
638         case TDS_DONEPROC_TOKEN:
639         case TDS_DONEINPROC_TOKEN:
640         case TDS_PROCID_TOKEN:
641             return 8;
642         case TDS_RET_STAT_TOKEN:
643             return 4;
644         case TDS_LOGOUT_TOKEN:
645             return 1;
646         case TDS7_RESULT_TOKEN:
647         default:
648             return 0;
649     }
650 }
651
652 static guint
653 tds_get_variable_token_size(tvbuff_t *tvb, gint offset, guint8 token,
654                             guint *len_field_size_p, guint *len_field_val_p)
655 {
656     switch(token) {
657         /* some tokens have a 4 byte length field */
658         case TDS5_PARAMFMT2_TOKEN:
659         case TDS_LANG_TOKEN:
660         case TDS5_ORDERBY2_TOKEN:
661         case TDS5_CURDECLARE2_TOKEN:
662         case TDS5_ROWFMT2_TOKEN:
663         case TDS5_DYNAMIC2_TOKEN:
664             *len_field_size_p = 4;
665             *len_field_val_p = tds_tvb_get_xxtohl(tvb, offset, tds_little_endian);
666             break;
667             /* some have a 1 byte length field */
668         case TDS5_MSG_TOKEN:
669             *len_field_size_p = 1;
670             *len_field_val_p = tvb_get_guint8(tvb, offset);
671             break;
672             /* and most have a 2 byte length field */
673         default:
674             *len_field_size_p = 2;
675             *len_field_val_p = tds_tvb_get_xxtohs(tvb, offset, tds_little_endian);
676             break;
677     }
678     return *len_field_val_p + *len_field_size_p + 1;
679 }
680
681
682 static void
683 dissect_tds_query_packet(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
684 {
685     guint offset, len;
686     gboolean is_unicode = TRUE;
687     char *msg;
688
689     proto_item *query_hdr;
690     proto_tree *query_tree;
691
692     offset = 0;
693     query_hdr = proto_tree_add_text(tree, tvb, offset, -1, "TDS Query Packet");
694     query_tree = proto_item_add_subtree(query_hdr, ett_tds7_query);
695     len = tvb_reported_length_remaining(tvb, offset);
696
697     if (TDS_PROTO_PREF_TDS4 ||
698         (!TDS_PROTO_PREF_TDS7_TDS8 &&
699          ((len < 2) || tvb_get_guint8(tvb, offset+1) != 0)))
700         is_unicode = FALSE;
701
702     if (is_unicode)
703         msg = tvb_get_ephemeral_faked_unicode(tvb, offset, len/2, TRUE);
704     else
705         msg = (gchar*)tvb_get_ephemeral_string(tvb, offset, len);
706
707     proto_tree_add_text(query_tree, tvb, offset, len, "Query: %s", msg);
708     offset += len;
709 }
710
711
712 static void
713 dissect_tds5_lang_token(tvbuff_t *tvb, guint offset, guint len, proto_tree *tree) {
714     gboolean is_unicode = FALSE;
715     char *msg;
716
717     proto_tree_add_text(tree, tvb, offset, 1 , "Status: %u", tvb_get_guint8(tvb, offset));
718     offset += 1;
719     len    -= 1;
720
721     if (is_unicode)
722         msg = tvb_get_ephemeral_faked_unicode(tvb, offset, (len)/2, TRUE);
723     else
724         msg = (gchar*)tvb_get_ephemeral_string(tvb, offset, len);
725
726     proto_tree_add_text(tree, tvb, offset, len, "Language text: %s", msg);
727 }
728
729 static void
730 dissect_tds_query5_packet(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
731 {
732     guint offset;
733     guint pos;
734     guint token_len_field_size = 2;
735     guint token_len_field_val = 0;
736     guint8 token;
737     guint token_sz;
738     proto_item *query_hdr;
739     proto_tree *query_tree;
740     proto_item *token_item;
741     proto_tree *token_tree;
742
743     offset = 0;
744     query_hdr = proto_tree_add_text(tree, tvb, offset, -1, "TDS5 Query Packet");
745     query_tree = proto_item_add_subtree(query_hdr, ett_tds7_query);
746
747     /*
748      * Until we reach the end of the packet, read tokens.
749      */
750     pos = offset;
751     while (tvb_reported_length_remaining(tvb, pos) > 0) {
752
753         /* our token */
754         token = tvb_get_guint8(tvb, pos);
755         if (tds_token_is_fixed_size(token))
756             token_sz = tds_get_fixed_token_size(token) + 1;
757         else
758             token_sz = tds_get_variable_token_size(tvb, pos+1, token, &token_len_field_size,
759                                                    &token_len_field_val);
760
761         /* XXX - Should this check be done in tds_get_variable_token_size()
762          * instead? */
763         if ((int) token_sz < 0) {
764             proto_tree_add_text(tree, tvb, 0, 0, "Bogus token size: %u",
765                                 token_sz);
766             break;
767         }
768
769         token_item = proto_tree_add_text(tree, tvb, pos, token_sz,
770                                          "Token 0x%02x %s", token,
771                                          val_to_str(token, token_names, "Unknown Token Type"));
772         token_tree = proto_item_add_subtree(token_item, ett_tds_token);
773
774         /*
775          * If it's a variable token, put the length field in here
776          * instead of replicating this for each token subdissector.
777          */
778         if (!tds_token_is_fixed_size(token))
779             proto_tree_add_text(token_tree, tvb, pos+1, token_len_field_size, "Length: %u", token_len_field_val);
780
781         switch (token) {
782             case TDS_LANG_TOKEN:
783                 dissect_tds5_lang_token(tvb, pos + 5, token_sz -5, token_tree);
784                 break;
785             default:
786                 break;
787         }
788
789         pos += token_sz;
790
791     }  /* while */
792 }
793
794
795 static void
796 dissect_tds7_login(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
797 {
798     guint offset, i, j, k, offset2, len;
799     char *val, *val2;
800
801     proto_item *login_hdr;
802     proto_tree *login_tree;
803     proto_item *header_hdr;
804     proto_tree *header_tree;
805     proto_item *length_hdr;
806     proto_tree *length_tree;
807
808     struct tds7_login_packet_hdr td7hdr;
809     gint length_remaining;
810
811
812     /* create display subtree for the protocol */
813     offset = 0;
814     login_hdr = proto_tree_add_text(tree, tvb, offset, -1, "TDS7 Login Packet");
815     login_tree = proto_item_add_subtree(login_hdr, ett_tds7_login);
816     header_hdr = proto_tree_add_text(login_tree, tvb, offset, 36, "Login Packet Header");
817     header_tree = proto_item_add_subtree(header_hdr, ett_tds7_hdr);
818
819     td7hdr.total_packet_size = tvb_get_letohl(tvb, offset);
820     proto_tree_add_uint(header_tree, hf_tds7_login_total_size, tvb, offset,
821                         sizeof(td7hdr.total_packet_size), td7hdr.total_packet_size);
822     offset += sizeof(td7hdr.total_packet_size);
823
824     td7hdr.tds_version = tvb_get_ntohl(tvb, offset);
825     proto_tree_add_uint(header_tree, hf_tds7_version, tvb, offset, sizeof(td7hdr.tds_version), td7hdr.tds_version);
826     offset += sizeof(td7hdr.tds_version);
827
828     td7hdr.packet_size = tvb_get_ntohl(tvb, offset);
829     proto_tree_add_uint(header_tree, hf_tds7_packet_size, tvb, offset, sizeof(td7hdr.packet_size), td7hdr.packet_size);
830     offset += sizeof(td7hdr.packet_size);
831
832     td7hdr.client_version = tvb_get_ntohl(tvb, offset);
833     proto_tree_add_uint(header_tree, hf_tds7_client_version, tvb, offset, sizeof(td7hdr.client_version), td7hdr.client_version);
834     offset += sizeof(td7hdr.client_version);
835
836     td7hdr.client_pid = tvb_get_letohl(tvb, offset);
837     proto_tree_add_uint(header_tree, hf_tds7_client_pid, tvb, offset, sizeof(td7hdr.client_pid), td7hdr.client_pid);
838     offset += sizeof(td7hdr.client_pid);
839
840     td7hdr.connection_id= tvb_get_letohl(tvb, offset);
841     proto_tree_add_uint(header_tree, hf_tds7_connection_id, tvb, offset, sizeof(td7hdr.connection_id), td7hdr.connection_id);
842     offset += sizeof(td7hdr.connection_id);
843
844     td7hdr.option_flags1 = tvb_get_guint8(tvb, offset);
845     proto_tree_add_uint(header_tree, hf_tds7_option_flags1, tvb, offset, sizeof(td7hdr.option_flags1), td7hdr.option_flags1);
846     offset += sizeof(td7hdr.option_flags1);
847
848     td7hdr.option_flags2 = tvb_get_guint8(tvb, offset);
849     proto_tree_add_uint(header_tree, hf_tds7_option_flags2, tvb, offset, sizeof(td7hdr.option_flags2), td7hdr.option_flags2);
850     offset += sizeof(td7hdr.option_flags2);
851
852     td7hdr.sql_type_flags = tvb_get_guint8(tvb, offset);
853     proto_tree_add_uint(header_tree, hf_tds7_sql_type_flags, tvb, offset, sizeof(td7hdr.sql_type_flags), td7hdr.sql_type_flags);
854     offset += sizeof(td7hdr.sql_type_flags);
855
856     td7hdr.reserved_flags = tvb_get_guint8(tvb, offset);
857     proto_tree_add_uint(header_tree, hf_tds7_reserved_flags, tvb, offset, sizeof(td7hdr.reserved_flags), td7hdr.reserved_flags);
858     offset += sizeof(td7hdr.reserved_flags);
859
860     td7hdr.time_zone = tvb_get_ntohl(tvb, offset);
861     proto_tree_add_uint(header_tree, hf_tds7_time_zone, tvb, offset, sizeof(td7hdr.time_zone), td7hdr.time_zone);
862     offset += sizeof(td7hdr.time_zone);
863
864     td7hdr.collation = tvb_get_ntohl(tvb, offset);
865     proto_tree_add_uint(header_tree, hf_tds7_collation, tvb, offset, sizeof(td7hdr.collation), td7hdr.collation);
866     offset += sizeof(td7hdr.collation);
867
868     length_hdr = proto_tree_add_text(login_tree, tvb, offset, 50, "Lengths and offsets");
869     length_tree = proto_item_add_subtree(length_hdr, ett_tds7_hdr);
870
871     for (i = 0; i < 9; i++) {
872         offset2 = tvb_get_letohs(tvb, offset + i*4);
873         len = tvb_get_letohs(tvb, offset + i*4 + 2);
874         proto_tree_add_text(length_tree, tvb, offset + i*4, 2,
875                             "%s offset: %u",
876                             val_to_str(i, login_field_names, "Unknown"),
877                             offset2);
878         proto_tree_add_text(length_tree, tvb, offset + i*4 + 2, 2,
879                             "%s length: %u",
880                             val_to_str(i, login_field_names, "Unknown"),
881                             len);
882         if (len != 0) {
883             if( i != 2) {
884                 /* tds 7 is always unicode */
885                 val = tvb_get_ephemeral_faked_unicode(tvb, offset2, len, TRUE);
886                 len *= 2;
887                 proto_tree_add_text(login_tree, tvb, offset2, len, "%s: %s", val_to_str(i, login_field_names, "Unknown"), val);
888             } else {
889                 /* This field is the password.  We retrieve it from the packet
890                  * as a non-unicode string and then perform two operations on it
891                  * to "decrypt" it.  Finally, we create a new string that consists
892                  * of ASCII characters instead of unicode by skipping every other
893                  * byte in the original string.
894                  */
895
896                 len *= 2;
897                 val = (gchar*)tvb_get_ephemeral_string(tvb, offset2, len);
898                 val2 = g_malloc((len/2)+1);
899
900                 for(j = 0, k = 0; j < len; j += 2, k++) {
901                     val[j] ^= 0xA5;
902
903                     /* Swap the most and least significant bits */
904                     val[j] = ((val[j] & 0x0F) << 4) | ((val[j] & 0xF0) >> 4);
905
906                     val2[k] = val[j];
907                 }
908                 val2[k] = '\0'; /* Null terminate our new string */
909
910                 proto_tree_add_text(login_tree, tvb, offset2, len, "%s: %s", val_to_str(i, login_field_names, "Unknown"), val2);
911                 g_free(val2);
912             }
913         }
914     }
915
916     /*
917      * XXX - what about the client MAC address, etc.?
918      */
919     length_remaining = tvb_reported_length_remaining(tvb, offset2 + len);
920     if (length_remaining > 0) {
921         dissect_tds_nt(tvb, pinfo, login_tree, offset2 + len,
922                        length_remaining);
923     }
924 }
925
926 static int
927 get_size_by_coltype(int servertype)
928 {
929     switch(servertype)
930     {
931         case SYBINT1:        return 1;
932         case SYBINT2:        return 2;
933         case SYBINT4:        return 4;
934         case SYBINT8:        return 8;
935         case SYBREAL:        return 4;
936         case SYBFLT8:        return 8;
937         case SYBDATETIME:    return 8;
938         case SYBDATETIME4:   return 4;
939         case SYBBIT:         return 1;
940         case SYBBITN:        return 1;
941         case SYBMONEY:       return 8;
942         case SYBMONEY4:      return 4;
943         case SYBUNIQUE:      return 16;
944         default:             return -1;
945     }
946 }
947 # if 0
948 /*
949  * data_to_string should take column data and turn it into something we can
950  * display on the tree.
951  */
952 static char *data_to_string(void *data, guint col_type, guint col_size)
953 {
954     char *result;
955     guint i;
956
957     result=ep_alloc(256);
958     switch(col_type) {
959         case SYBVARCHAR:
960             /* strncpy(result, (char *)data, col_size); */
961             for (i=0;i<col_size && i<(256-1);i++)
962                 if (!isprint(((char *)data)[i])) result[i]='.';
963                 else result[i]=((char *)data)[i];
964             result[i] = '\0';
965             break;
966         case SYBINT2:
967             g_snprintf(result, 256, "%d", *(short *)data);
968             break;
969         case SYBINT4:
970             g_snprintf(result, 256, "%d", *(int *)data);
971             break;
972         default:
973             g_snprintf(result, 256, "Unexpected column_type %d", col_type);
974             break;
975     }
976     return result;
977 }
978 #endif
979
980 /*
981  * Since rows are special PDUs in that they are not fixed and lack a size field,
982  * the length must be computed using the column information seen in the result
983  * PDU. This function does just that.
984  */
985 static guint
986 tds_get_row_size(tvbuff_t *tvb, struct _netlib_data *nl_data, guint offset)
987 {
988     guint cur, i, csize;
989
990     cur = offset;
991     for (i = 0; i < nl_data->num_cols; i++) {
992         if (!is_fixed_coltype(nl_data->columns[i]->ctype)) {
993             csize = tvb_get_guint8(tvb, cur);
994             cur++;
995         } else
996             csize = get_size_by_coltype(nl_data->columns[i]->ctype);
997         cur += csize;
998     }
999
1000     return (cur - offset + 1);
1001 }
1002
1003 /*
1004  * Process TDS 4 "COL_INFO" token and store relevant information in the
1005  * _netlib_data structure for later use (see tds_get_row_size)
1006  *
1007  * XXX Can TDS 4 be "big-endian" ? we'll assume yes.
1008  *
1009  */
1010 static gboolean
1011 dissect_tds_col_info_token(tvbuff_t *tvb, struct _netlib_data *nl_data, guint offset)
1012 {
1013     guint next, cur;
1014     guint col;
1015
1016     next = offset + tds_tvb_get_xxtohs(tvb, offset+1, tds_little_endian) + 3;
1017     cur = offset + 3;
1018
1019     col = 0;
1020     while (cur < next) {
1021
1022         if (col >= MAX_COLUMNS) {
1023             nl_data->num_cols = 0;
1024             return FALSE;
1025         }
1026
1027         nl_data->columns[col] = ep_alloc(sizeof(struct _tds_col));
1028
1029         nl_data->columns[col]->name[0] ='\0';
1030
1031         nl_data->columns[col]->utype = tds_tvb_get_xxtohs(tvb, cur, tds_little_endian);
1032         cur += 2;
1033
1034         cur += 2; /* unknown */
1035
1036         nl_data->columns[col]->ctype = tvb_get_guint8(tvb,cur);
1037         cur++;
1038
1039         if (!is_fixed_coltype(nl_data->columns[col]->ctype)) {
1040             nl_data->columns[col]->csize = tvb_get_guint8(tvb,cur);
1041             cur ++;
1042         } else {
1043             nl_data->columns[col]->csize =
1044                 get_size_by_coltype(nl_data->columns[col]->ctype);
1045         }
1046
1047         col += 1;
1048
1049     } /* while */
1050
1051     nl_data->num_cols = col;
1052     return TRUE;
1053 }
1054
1055
1056 /*
1057  * Read the results token and store the relevant information in the
1058  * _netlib_data structure for later use (see tds_get_row_size).
1059  *
1060  * TODO: check we don't go past end of the token
1061  */
1062 static gboolean
1063 read_results_tds5(tvbuff_t *tvb, struct _netlib_data *nl_data, guint offset, guint len _U_)
1064 {
1065     guint name_len;
1066     guint cur;
1067     guint i;
1068
1069     cur = offset;
1070
1071     /*
1072      * This would be the logical place to check for little/big endianess
1073      * if we didn't see the login packet.
1074      * XXX: We'll take a hint
1075      */
1076     nl_data->num_cols = tds_tvb_get_xxtohs(tvb, cur, tds_little_endian);
1077     if (nl_data->num_cols > MAX_COLUMNS) {
1078         nl_data->num_cols = 0;
1079         return FALSE;
1080     }
1081
1082     cur += 2;
1083
1084     for (i = 0; i < nl_data->num_cols; i++) {
1085         nl_data->columns[i] = ep_alloc(sizeof(struct _tds_col));
1086         name_len = tvb_get_guint8(tvb,cur);
1087         cur ++;
1088         cur += name_len;
1089
1090         cur++; /* unknown */
1091
1092         nl_data->columns[i]->utype = tds_tvb_get_xxtohs(tvb, cur, tds_little_endian);
1093         cur += 2;
1094
1095         cur += 2; /* unknown */
1096
1097         nl_data->columns[i]->ctype = tvb_get_guint8(tvb,cur);
1098         cur++;
1099
1100         if (!is_fixed_coltype(nl_data->columns[i]->ctype)) {
1101             nl_data->columns[i]->csize = tvb_get_guint8(tvb,cur);
1102             cur ++;
1103         } else {
1104             nl_data->columns[i]->csize =
1105                 get_size_by_coltype(nl_data->columns[i]->ctype);
1106         }
1107         cur++; /* unknown */
1108     }
1109     return TRUE;
1110 }
1111
1112 /*
1113  * If the packet type from the netlib header is a login packet, then dig into
1114  * the packet to see if this is a supported TDS version and verify the otherwise
1115  * weak heuristics of the netlib check.
1116  */
1117 static gboolean
1118 netlib_check_login_pkt(tvbuff_t *tvb, guint offset, packet_info *pinfo, guint8 type)
1119 {
1120     guint tds_major, bytes_avail;
1121
1122     bytes_avail = tvb_length(tvb) - offset;
1123     /*
1124      * we have two login packet styles, one for TDS 4.2 and 5.0
1125      */
1126     if (type==TDS_LOGIN_PKT) {
1127         /* Use major version number to validate TDS 4/5 login
1128          * packet */
1129
1130         /* Login packet is first in stream and should not be fragmented...
1131          * if it is we are screwed */
1132         if (bytes_avail < 467) return FALSE;
1133         tds_major = tvb_get_guint8(tvb, 466);
1134         if (tds_major != 4 && tds_major != 5) {
1135             return FALSE;
1136         }
1137         /*
1138          * and one added by Microsoft in SQL Server 7
1139          */
1140     } else if (type==TDS_LOGIN7_PKT) {
1141         if (bytes_avail < 16) return FALSE;
1142         tds_major = tvb_get_guint8(tvb, 15);
1143         if (tds_major != 0x70 && tds_major != 0x80) {
1144             return FALSE;
1145         }
1146     } else if (type==TDS_QUERY5_PKT) {
1147         if (bytes_avail < 9) return FALSE;
1148         /* if this is a TDS 5.0 query check the token */
1149         if (tvb_get_guint8(tvb, 8) != TDS_LANG_TOKEN) {
1150             return FALSE;
1151         }
1152     }
1153     /*
1154      * See if either tcp.destport or tcp.srcport is specified
1155      * in the preferences as being a TDS port.
1156      */
1157     else if (!value_is_in_range(tds_tcp_ports, pinfo->srcport) &&
1158              !value_is_in_range(tds_tcp_ports, pinfo->destport)) {
1159         return FALSE;
1160     }
1161
1162     return TRUE;
1163 }
1164
1165 static void
1166 dissect_tds_env_chg(tvbuff_t *tvb, guint offset, guint token_sz,
1167                     proto_tree *tree)
1168 {
1169     guint8 env_type;
1170     guint old_len, new_len, old_len_offset;
1171     char *new_val = NULL, *old_val = NULL;
1172     guint32 string_offset;
1173     gboolean is_unicode = FALSE;
1174     guint16 collate_codepage, collate_flags;
1175     guint8 collate_charset_id;
1176
1177     env_type = tvb_get_guint8(tvb, offset);
1178     proto_tree_add_text(tree, tvb, offset, 1, "Type: %u (%s)", env_type,
1179                         val_to_str(env_type, env_chg_names, "Unknown"));
1180
1181     new_len = tvb_get_guint8(tvb, offset+1);
1182     old_len_offset = offset + new_len + 2;
1183     old_len = tvb_get_guint8(tvb, old_len_offset);
1184
1185     /*
1186      * If our lengths plus the lengths of the type and the lengths
1187      * don't add up to the token size, it must be UCS2.
1188      */
1189     if (old_len + new_len + 3 != token_sz) {
1190         is_unicode = TRUE;
1191         old_len_offset = offset + (new_len * 2) + 2;
1192         old_len = tvb_get_guint8(tvb, old_len_offset);
1193     }
1194
1195     proto_tree_add_text(tree, tvb, offset + 1, 1, "New Value Length: %u",
1196                         new_len);
1197     if (new_len) {
1198         if (env_type != 7) { /* if it's not 'Collation Info - which is not textual! */
1199             string_offset = offset + 2;
1200             if (is_unicode == TRUE) {
1201                 new_val = tvb_get_ephemeral_faked_unicode(tvb, string_offset,
1202                                                           new_len, TRUE);
1203                 new_len *= 2;
1204             } else
1205                 new_val = (gchar*)tvb_get_ephemeral_string(tvb, string_offset, new_len);
1206             proto_tree_add_text(tree, tvb, string_offset, new_len,
1207                                 "New Value: %s", new_val);
1208         }
1209         else { /* parse collation info structure. From http://www.freetds.org/tds.html#collate */
1210             offset +=2;
1211             collate_codepage = tvb_get_letohs(tvb, offset);
1212             proto_tree_add_text(tree, tvb, offset, 2, "Codepage: %u" , collate_codepage);
1213             offset += 2;
1214             collate_flags = tvb_get_letohs(tvb, offset);
1215             proto_tree_add_text(tree, tvb, offset, 2, "Flags: 0x%x", collate_flags);
1216             offset += 2;
1217             collate_charset_id = tvb_get_guint8(tvb, offset);
1218             proto_tree_add_text(tree, tvb, offset, 1, "Charset ID: %u", collate_charset_id);
1219             offset +=1;
1220         }
1221     }
1222
1223     proto_tree_add_text(tree, tvb, old_len_offset, 1, "Old Value Length: %u",
1224                         old_len);
1225     if (old_len) {
1226         string_offset = old_len_offset + 1;
1227         if (is_unicode == TRUE) {
1228             old_val = tvb_get_ephemeral_faked_unicode(tvb, string_offset,
1229                                                       old_len, TRUE);
1230             old_len *= 2;
1231         } else
1232             old_val = (gchar*)tvb_get_ephemeral_string(tvb, string_offset, old_len);
1233         proto_tree_add_text(tree, tvb, string_offset, old_len,
1234                             "Old Value: %s", old_val);
1235     }
1236 }
1237
1238 static void
1239 dissect_tds_err_token(tvbuff_t *tvb, guint offset, guint token_sz _U_, proto_tree *tree)
1240 {
1241     guint16 msg_len;
1242     guint8 srvr_len, proc_len;
1243     char *msg;
1244     gboolean is_unicode = FALSE;
1245
1246     proto_tree_add_text(tree, tvb, offset, 4, "SQL Error Number: %d", tds_tvb_get_xxtohl(tvb, offset, tds_little_endian));
1247     offset += 4;
1248     proto_tree_add_text(tree, tvb, offset, 1, "State: %u", tvb_get_guint8(tvb, offset));
1249     offset +=1;
1250     proto_tree_add_text(tree, tvb, offset, 1, "Severity Level: %u", tvb_get_guint8(tvb, offset));
1251     offset +=1;
1252
1253     msg_len = tds_tvb_get_xxtohs(tvb, offset, tds_little_endian);
1254     proto_tree_add_text(tree, tvb, offset, 1, "Error message length: %u characters", msg_len);
1255     offset +=2;
1256
1257     if(tvb_get_guint8(tvb, offset+1) == 0) /* FIXME: It's probably unicode, if the 2nd byte of the message is zero. It's not a good detection method, but it works */
1258         is_unicode = TRUE;
1259
1260     if(is_unicode) {
1261         msg = tvb_get_ephemeral_faked_unicode(tvb, offset, msg_len, TRUE);
1262         msg_len *= 2;
1263     } else {
1264         msg = (gchar*)tvb_get_ephemeral_string(tvb, offset, msg_len);
1265     }
1266     proto_tree_add_text(tree, tvb, offset, msg_len, "Error: %s", format_text((guchar*)msg, strlen(msg)));
1267     offset += msg_len;
1268
1269     srvr_len = tvb_get_guint8(tvb, offset);
1270
1271     proto_tree_add_text(tree, tvb, offset, 1, "Server name length: %u characters", srvr_len);
1272     offset +=1;
1273     if(srvr_len) {
1274         if (is_unicode) {
1275             msg = tvb_get_ephemeral_faked_unicode(tvb, offset, srvr_len, TRUE);
1276             srvr_len *=2;
1277         } else {
1278             msg = (gchar*)tvb_get_ephemeral_string(tvb, offset, srvr_len);
1279         }
1280         proto_tree_add_text(tree, tvb, offset, srvr_len, "Server name: %s", msg);
1281         offset += srvr_len;
1282     }
1283
1284     proc_len = tvb_get_guint8(tvb, offset);
1285
1286     proto_tree_add_text(tree, tvb, offset, 1, "Process name length: %u characters", proc_len);
1287     offset +=1;
1288     if(proc_len) {
1289         if (is_unicode) {
1290             msg = tvb_get_ephemeral_faked_unicode(tvb, offset, proc_len, TRUE);
1291             proc_len *=2;
1292         } else {
1293             msg = (gchar*)tvb_get_ephemeral_string(tvb, offset, proc_len);
1294         }
1295         proto_tree_add_text(tree, tvb, offset, proc_len, "Process name: %s", msg);
1296         offset += proc_len;
1297     }
1298
1299     proto_tree_add_text(tree, tvb, offset, 2, "line number: %d", tds_tvb_get_xxtohs(tvb, offset, tds_little_endian));
1300 }
1301
1302 static void
1303 dissect_tds_login_ack_token(tvbuff_t *tvb, guint offset, guint token_sz, proto_tree *tree)
1304 {
1305     guint8 msg_len;
1306     char *msg;
1307     gboolean is_unicode = FALSE;
1308
1309     proto_tree_add_text(tree, tvb, offset, 1, "Ack: %u", tvb_get_guint8(tvb, offset));
1310     offset +=1;
1311     proto_tree_add_text(tree, tvb, offset, 1, "Major version (may be incorrect): %d", tvb_get_guint8(tvb, offset));
1312     offset +=1;
1313     proto_tree_add_text(tree, tvb, offset, 1, "Minor version (may be incorrect): %d", tvb_get_guint8(tvb, offset));
1314     offset +=1;
1315     proto_tree_add_text(tree, tvb, offset, 2, "zero usually");
1316     offset +=2;
1317
1318     msg_len = tvb_get_guint8(tvb, offset);
1319     proto_tree_add_text(tree, tvb, offset, 1, "Text length: %u characters", msg_len);
1320     offset +=1;
1321
1322     if(msg_len + 6U + 3U != token_sz - 1) /* 6 is the length of ack(1), version (4), text length (1) fields */
1323         is_unicode = TRUE;
1324     proto_tree_add_text(tree, tvb, offset, 0, "msg_len: %d, token_sz: %d, total: %d",msg_len, token_sz, msg_len + 6U + 3U);
1325     if(is_unicode) {
1326         msg = tvb_get_ephemeral_faked_unicode(tvb, offset, msg_len, TRUE);
1327         msg_len *= 2;
1328     } else {
1329         msg = (gchar*)tvb_get_ephemeral_string(tvb, offset, msg_len);
1330     }
1331     proto_tree_add_text(tree, tvb, offset, msg_len, "Text: %s", format_text((guchar*)msg, strlen(msg)));
1332     offset += msg_len;
1333
1334     proto_tree_add_text(tree, tvb, offset, 4, "Server Version");
1335     offset += 4;
1336 }
1337
1338 static int
1339 dissect_tds7_results_token(tvbuff_t *tvb, guint offset, proto_tree *tree)
1340 {
1341     guint16 num_columns, table_len;
1342     guint8 type, msg_len;
1343     int i;
1344     char *msg;
1345     guint16 collate_codepage, collate_flags;
1346     guint8 collate_charset_id;
1347
1348     num_columns = tvb_get_letohs(tvb, offset);
1349     proto_tree_add_text(tree, tvb, offset, 2, "Columns: %u", tvb_get_letohs(tvb, offset));
1350     offset +=2;
1351     for(i=0; i != num_columns; i++) {
1352         proto_tree_add_text(tree, tvb, offset, 0, "Column %d", i + 1);
1353         proto_tree_add_text(tree, tvb, offset, 2, "usertype: %d", tvb_get_letohs(tvb, offset));
1354         offset +=2;
1355         proto_tree_add_text(tree, tvb, offset, 2, "flags: %d", tvb_get_letohs(tvb, offset));
1356         offset +=2;
1357         type  = tvb_get_guint8(tvb, offset);
1358         proto_tree_add_text(tree, tvb, offset, 1, "Type: %d", type);
1359         offset +=1;
1360         if(type == 38 || type == 104 || type == 109 || type == 111) { /* ugly, ugly hack. Wish I knew what it really means!*/
1361             proto_tree_add_text(tree, tvb, offset, 1, "unknown 1 byte (%x)", tvb_get_guint8(tvb, offset));
1362             offset +=1;
1363         }
1364         else if (type == 35) {
1365             proto_tree_add_text(tree, tvb, offset, 4, "unknown 4 bytes (%x)", tvb_get_letohl(tvb, offset));
1366             offset += 4;
1367             collate_codepage = tvb_get_letohs(tvb, offset);
1368             proto_tree_add_text(tree, tvb, offset, 2, "Codepage: %u" , collate_codepage);
1369             offset += 2;
1370             collate_flags = tvb_get_letohs(tvb, offset);
1371             proto_tree_add_text(tree, tvb, offset, 2, "Flags: 0x%x", collate_flags);
1372             offset += 2;
1373             collate_charset_id = tvb_get_guint8(tvb, offset);
1374             proto_tree_add_text(tree, tvb, offset, 1, "Charset ID: %u", collate_charset_id);
1375             offset +=1;
1376             table_len = tvb_get_letohs(tvb, offset);
1377             offset +=2;
1378             if(table_len != 0) {
1379                 msg = tvb_get_ephemeral_faked_unicode(tvb, offset, table_len, TRUE);
1380                 proto_tree_add_text(tree, tvb, offset, table_len*2, "Table name: %s", msg);
1381                 offset += table_len*2;
1382             }
1383         }
1384         else if (type == 106 || type == 108) {
1385             proto_tree_add_text(tree, tvb, offset, 3, "unknown 3 bytes");
1386             offset +=3;
1387         }
1388         else if(type > 128) {
1389             proto_tree_add_text(tree, tvb, offset, 2, "Large type size: 0x%x", tvb_get_letohs(tvb, offset));
1390             offset += 2;
1391             if (type != 165) {
1392                 collate_codepage = tvb_get_letohs(tvb, offset);
1393                 proto_tree_add_text(tree, tvb, offset, 2, "Codepage: %u" , collate_codepage);
1394                 offset += 2;
1395                 collate_flags = tvb_get_letohs(tvb, offset);
1396                 proto_tree_add_text(tree, tvb, offset, 2, "Flags: 0x%x", collate_flags);
1397                 offset += 2;
1398                 collate_charset_id = tvb_get_guint8(tvb, offset);
1399                 proto_tree_add_text(tree, tvb, offset, 1, "Charset ID: %u", collate_charset_id);
1400                 offset +=1;
1401             }
1402         }
1403         msg_len = tvb_get_guint8(tvb, offset);
1404         proto_tree_add_text(tree, tvb, offset, 1, "message length: %d",msg_len);
1405         offset += 1;
1406         if(msg_len != 0) {
1407             msg = tvb_get_ephemeral_faked_unicode(tvb, offset, msg_len, TRUE);
1408             proto_tree_add_text(tree, tvb, offset, msg_len*2, "Text: %s", msg);
1409             offset += msg_len*2;
1410         }
1411     }
1412     return offset;
1413 }
1414
1415 static void
1416 dissect_tds_done_token(tvbuff_t *tvb, guint offset, proto_tree *tree)
1417 {
1418     proto_tree_add_text(tree, tvb, offset, 2, "Status flags");
1419     offset += 2;
1420     proto_tree_add_text(tree, tvb, offset, 2, "Operation");
1421     offset += 2;
1422     proto_tree_add_text(tree, tvb, offset, 4, "row count: %u", tds_tvb_get_xxtohl(tvb, offset, tds_little_endian));
1423     offset += 2;
1424 }
1425
1426 static void
1427 dissect_tds_rpc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1428 {
1429     int offset = 0;
1430     guint len;
1431     guint16 sp_id;
1432     char *val;
1433
1434     /*
1435      * RPC name.
1436      */
1437     switch(tds_protocol_type) {
1438         case TDS_PROTOCOL_4:
1439             len = tvb_get_guint8(tvb, offset);
1440             proto_tree_add_text(tree, tvb, offset, 1, "RPC Name Length: %u", len);
1441             offset += 1;
1442             val = (gchar*)tvb_get_ephemeral_string(tvb, offset, len);
1443             proto_tree_add_text(tree, tvb, offset, len, "RPC Name: %s", val);
1444             offset += len;
1445             break;
1446
1447         case TDS_PROTOCOL_7:
1448         case TDS_PROTOCOL_8:
1449         default:        /* unspecified: try as if TDS7/TDS8 */
1450             len = tvb_get_letohs(tvb, offset);
1451             proto_tree_add_text(tree, tvb, offset, 2, "RPC Name Length: %u", len);
1452             offset += 2;
1453             if (len == 0xFFFF) {
1454                 sp_id = tvb_get_letohs(tvb, offset);
1455                 proto_tree_add_text(tree, tvb, offset, 2, "RPC Stored Proc ID: %u (%s)",
1456                                     sp_id,
1457                                     val_to_str(sp_id, internal_stored_proc_id_names, "Unknown"));
1458                 offset += 2;
1459             }
1460             else if (len != 0) {
1461                 val = tvb_get_ephemeral_faked_unicode(tvb, offset, len, TRUE);
1462                 len *= 2;
1463                 proto_tree_add_text(tree, tvb, offset, len, "RPC Name: %s", val);
1464                 offset += len;
1465             }
1466             break;
1467     }
1468     proto_tree_add_text(tree, tvb, offset, -1, "Params (not dissected)");
1469 }
1470
1471 static void
1472 dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1473 {
1474     int offset = 0;
1475     proto_item *token_item;
1476     proto_tree *token_tree;
1477     guint pos, token_sz = 0;
1478     guint token_len_field_size = 2;
1479     guint token_len_field_val = 0;
1480     guint8 token;
1481     struct _netlib_data nl_data;
1482     gint length_remaining;
1483
1484     memset(&nl_data, '\0', sizeof nl_data);
1485
1486     /*
1487      * Until we reach the end of the packet, read tokens.
1488      */
1489     pos = offset;
1490     while (tvb_reported_length_remaining(tvb, pos) > 0) {
1491         /* our token */
1492         token = tvb_get_guint8(tvb, pos);
1493
1494         /* TODO Handle TDS_PARAMFMT, TDS_PARAMS [similar to TDS_RESULTS, TDS_ROW] */
1495         if (tds_token_is_fixed_size(token)) {
1496             token_sz = tds_get_fixed_token_size(token) + 1;
1497         } else if (token == TDS_ROW_TOKEN) {
1498             /*
1499              * Rows are special; they have no size field and
1500              * aren't fixed length.
1501              */
1502             token_sz = tds_get_row_size(tvb, &nl_data, pos + 1);
1503         } else
1504             token_sz = tds_get_variable_token_size(tvb, pos + 1,
1505                                                    token, &token_len_field_size, &token_len_field_val);
1506
1507         length_remaining = tvb_ensure_length_remaining(tvb, pos);
1508
1509         if ((int) token_sz < 0) {
1510             proto_tree_add_text(tree, tvb, pos, 0, "Bogus token size: %u",
1511                                 token_sz);
1512             break;
1513         }
1514         if ((int) token_len_field_size < 0) {
1515             proto_tree_add_text(tree, tvb, pos, 0, "Bogus token length field size: %u",
1516                                 token_len_field_size);
1517             break;
1518         }
1519         token_item = proto_tree_add_text(tree, tvb, pos, token_sz,
1520                                          "Token 0x%02x %s", token,
1521                                          val_to_str(token, token_names, "Unknown Token Type"));
1522         token_tree = proto_item_add_subtree(token_item, ett_tds_token);
1523
1524         /*
1525          * If it's a variable token, put the length field in here
1526          * instead of replicating this for each token subdissector.
1527          */
1528         if (!tds_token_is_fixed_size(token) && token != TDS_ROW_TOKEN) {
1529             proto_tree_add_text(token_tree, tvb, pos + 1,
1530                                 token_len_field_size, "Length: %u",
1531                                 token_len_field_val);
1532         }
1533
1534         if (token_sz > (guint)length_remaining)
1535             token_sz = (guint)length_remaining;
1536
1537         switch (token) {
1538
1539             case TDS_COL_NAME_TOKEN:
1540                 /*
1541                  * TDS 4.2
1542                  * TODO dissect token to get "column names" to fill in _netlib_data
1543                  */
1544                 break;
1545
1546             case TDS_COL_INFO_TOKEN:
1547                 /*
1548                  * TDS 4.2: get the column info
1549                  */
1550                 dissect_tds_col_info_token(tvb, &nl_data, pos);
1551                 break;
1552
1553             case TDS_RESULT_TOKEN:
1554                 /*
1555                  * If it's a result token, we need to stash the
1556                  * column info.
1557                  */
1558                 read_results_tds5(tvb, &nl_data, pos + 3, token_sz - 3);
1559                 break;
1560
1561             case TDS_ENV_CHG_TOKEN:
1562                 dissect_tds_env_chg(tvb, pos + 3, token_sz - 3, token_tree);
1563                 break;
1564
1565             case TDS_AUTH_TOKEN:
1566                 dissect_tds_nt(tvb, pinfo, token_tree, pos + 3, token_sz - 3);
1567                 break;
1568             case TDS_ERR_TOKEN:
1569             case TDS_MSG_TOKEN:
1570                 dissect_tds_err_token(tvb, pos + 3, token_sz - 3, token_tree);
1571                 break;
1572
1573             case TDS_DONE_TOKEN:
1574             case TDS_DONEPROC_TOKEN:
1575             case TDS_DONEINPROC_TOKEN:
1576                 dissect_tds_done_token(tvb, pos + 1, token_tree);
1577                 break;
1578             case TDS_LOGIN_ACK_TOKEN:
1579                 dissect_tds_login_ack_token(tvb, pos + 3, token_sz - 3, token_tree);
1580                 break;
1581             case TDS7_RESULT_TOKEN:
1582                 pos = (dissect_tds7_results_token(tvb, pos + 1, token_tree)-1);
1583                 break;
1584         }
1585
1586         /* and step to the end of the token, rinse, lather, repeat */
1587         pos += token_sz;
1588     }
1589 }
1590
1591 static void
1592 dissect_netlib_buffer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1593 {
1594     int offset = 0;
1595     proto_item *tds_item = NULL;
1596     proto_tree *tds_tree = NULL;
1597     guint8 type;
1598     guint8 status;
1599     guint16 size;
1600     guint16 channel;
1601     guint8 packet_number;
1602     gboolean save_fragmented;
1603     int len;
1604     fragment_data *fd_head;
1605     tvbuff_t *next_tvb;
1606
1607     if (tree) {
1608         /* create display subtree for the protocol */
1609         tds_item = proto_tree_add_item(tree, proto_tds, tvb, offset, -1,
1610                                        FALSE);
1611
1612         tds_tree = proto_item_add_subtree(tds_item, ett_tds);
1613     }
1614     type = tvb_get_guint8(tvb, offset);
1615     if (tree) {
1616         proto_tree_add_uint(tds_tree, hf_tds_type, tvb, offset, 1,
1617                             type);
1618     }
1619     status = tvb_get_guint8(tvb, offset + 1);
1620     if (tree) {
1621         proto_tree_add_uint(tds_tree, hf_tds_status, tvb, offset + 1, 1,
1622                             status);
1623     }
1624     size = tvb_get_ntohs(tvb, offset + 2);
1625     if (tree) {
1626         proto_tree_add_uint(tds_tree, hf_tds_size, tvb, offset + 2, 2,
1627                             size);
1628     }
1629     channel = tvb_get_ntohs(tvb, offset + 4);
1630     if (tree) {
1631         proto_tree_add_uint(tds_tree, hf_tds_channel, tvb, offset + 4, 2,
1632                             channel);
1633     }
1634     packet_number = tvb_get_guint8(tvb, offset + 6);
1635     if (tree) {
1636         proto_tree_add_uint(tds_tree, hf_tds_packet_number, tvb, offset + 6, 1,
1637                             packet_number);
1638         proto_tree_add_item(tds_tree, hf_tds_window, tvb, offset + 7, 1,
1639                             FALSE);
1640     }
1641     offset += 8;        /* skip Netlib header */
1642
1643     /*
1644      * Deal with fragmentation.
1645      *
1646      * TODO: handle case where netlib headers 'packet-number'.is always 0
1647      *       use fragment_add_seq_next in this case ?
1648      *
1649      */
1650     save_fragmented = pinfo->fragmented;
1651     if (tds_defragment &&
1652         (packet_number > 1 || status == STATUS_NOT_LAST_BUFFER)) {
1653         if (status == STATUS_NOT_LAST_BUFFER) {
1654             col_append_str(pinfo->cinfo, COL_INFO,
1655                            " (Not last buffer)");
1656         }
1657         len = tvb_reported_length_remaining(tvb, offset);
1658         /*
1659          * XXX - I've seen captures that start with a login
1660          * packet with a sequence number of 2.
1661          */
1662         fd_head = fragment_add_seq_check(tvb, offset, pinfo, channel,
1663                                          tds_fragment_table, tds_reassembled_table,
1664                                          packet_number - 1, len, status == STATUS_NOT_LAST_BUFFER);
1665         next_tvb = process_reassembled_data(tvb, offset, pinfo,
1666                                             "Reassembled TDS", fd_head, &tds_frag_items, NULL,
1667                                             tds_tree);
1668     } else {
1669         /*
1670          * If this isn't the last buffer, just show it as a fragment.
1671          * (XXX - it'd be nice to dissect it if it's the first
1672          * buffer, but we'd need to do reassembly in order to
1673          * discover that.)
1674          *
1675          * If this is the last buffer, dissect it.
1676          * (XXX - it'd be nice to show it as a fragment if it's part
1677          * of a fragmented message, but we'd need to do reassembly
1678          * in order to discover that.)
1679          */
1680         if (status == STATUS_NOT_LAST_BUFFER)
1681             next_tvb = NULL;
1682         else {
1683             next_tvb = tvb_new_subset_remaining(tvb, offset);
1684         }
1685     }
1686
1687     if (next_tvb != NULL) {
1688
1689         switch (type) {
1690
1691             case TDS_RPC_PKT:
1692                 dissect_tds_rpc(next_tvb, pinfo, tds_tree);
1693                 break;
1694
1695             case TDS_RESP_PKT:
1696                 dissect_tds_resp(next_tvb, pinfo, tds_tree);
1697                 break;
1698
1699             case TDS_LOGIN7_PKT:
1700                 dissect_tds7_login(next_tvb, pinfo, tds_tree);
1701                 break;
1702             case TDS_QUERY_PKT:
1703                 dissect_tds_query_packet(next_tvb, pinfo, tds_tree);
1704                 break;
1705             case TDS_QUERY5_PKT:
1706                 dissect_tds_query5_packet(next_tvb, pinfo, tds_tree);
1707                 break;
1708             case TDS_NTLMAUTH_PKT:
1709                 dissect_tds_nt(next_tvb, pinfo, tds_tree, offset - 8, -1);
1710                 break;
1711             default:
1712                 proto_tree_add_text(tds_tree, next_tvb, 0, -1,
1713                                     "TDS Packet");
1714                 break;
1715         }
1716     } else {
1717         next_tvb = tvb_new_subset_remaining (tvb, offset);
1718         call_dissector(data_handle, next_tvb, pinfo, tds_tree);
1719     }
1720 }
1721
1722 static void
1723 dissect_tds_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1724 {
1725     volatile gboolean first_time = TRUE;
1726     volatile int offset = 0;
1727     guint length_remaining;
1728     guint8 type;
1729     guint16 plen;
1730     guint length;
1731     tvbuff_t *volatile next_tvb;
1732     proto_item *tds_item = NULL;
1733     proto_tree *tds_tree = NULL;
1734     void *pd_save;
1735
1736     while (tvb_reported_length_remaining(tvb, offset) != 0) {
1737         length_remaining = tvb_ensure_length_remaining(tvb, offset);
1738
1739         /*
1740          * Can we do reassembly?
1741          */
1742         if (tds_desegment && pinfo->can_desegment) {
1743             /*
1744              * Yes - is the fixed-length part of the PDU
1745              * split across segment boundaries?
1746              */
1747             if (length_remaining < 8) {
1748                 /*
1749                  * Yes.  Tell the TCP dissector where the
1750                  * data for this message starts in the data
1751                  * it handed us, and how many more bytes we
1752                  * need, and return.
1753                  */
1754                 pinfo->desegment_offset = offset;
1755                 pinfo->desegment_len = 8 - length_remaining;
1756                 return;
1757             }
1758         }
1759
1760         type = tvb_get_guint8(tvb, offset);
1761
1762         /*
1763          * Get the length of the PDU.
1764          */
1765         plen = tvb_get_ntohs(tvb, offset + 2);
1766         if (plen < 8) {
1767             /*
1768              * The length is less than the header length.
1769              * Put in the type, status, and length, and
1770              * report the length as bogus.
1771              */
1772             if (tree) {
1773                 /* create display subtree for the protocol */
1774                 tds_item = proto_tree_add_item(tree, proto_tds,
1775                                                tvb, offset, -1, FALSE);
1776
1777                 tds_tree = proto_item_add_subtree(tds_item,
1778                                                   ett_tds);
1779                 proto_tree_add_uint(tds_tree, hf_tds_type, tvb,
1780                                     offset, 1, type);
1781                 proto_tree_add_item(tds_tree, hf_tds_status,
1782                                     tvb, offset + 1, 1, FALSE);
1783                 proto_tree_add_uint_format(tds_tree,
1784                                            hf_tds_size, tvb, offset + 2, 2, plen,
1785                                            "Size: %u (bogus, should be >= 8)", plen);
1786             }
1787
1788             /*
1789              * Give up - we can't dissect any more of this
1790              * data.
1791              */
1792             break;
1793         }
1794
1795         /*
1796          * Can we do reassembly?
1797          */
1798         if (tds_desegment && pinfo->can_desegment) {
1799             /*
1800              * Yes - is the PDU split across segment boundaries?
1801              */
1802             if (length_remaining < plen) {
1803                 /*
1804                  * Yes.  Tell the TCP dissector where the
1805                  * data for this message starts in the data
1806                  * it handed us, and how many more bytes we
1807                  * need, and return.
1808                  */
1809                 pinfo->desegment_offset = offset;
1810                 pinfo->desegment_len = plen - length_remaining;
1811                 return;
1812             }
1813         }
1814
1815         if (first_time) {
1816             col_set_str(pinfo->cinfo, COL_PROTOCOL, "TDS");
1817
1818             /*
1819              * Set the packet description based on its TDS packet
1820              * type.
1821              */
1822             col_add_str(pinfo->cinfo, COL_INFO,
1823                         val_to_str(type, packet_type_names,
1824                                    "Unknown Packet Type: %u"));
1825             first_time = FALSE;
1826         }
1827
1828         /*
1829          * Construct a tvbuff containing the amount of the payload
1830          * we have available.  Make its reported length the amount
1831          * of data in the PDU.
1832          *
1833          * XXX - if reassembly isn't enabled. the subdissector will
1834          * throw a BoundsError exception, rather than a
1835          * ReportedBoundsError exception.  We really want a tvbuff
1836          * where the length is "length", the reported length is
1837          * "plen", and the "if the snapshot length were infinite"
1838          * length is the minimum of the reported length of the tvbuff
1839          * handed to us and "plen", with a new type of exception
1840          * thrown if the offset is within the reported length but
1841          * beyond that third length, with that exception getting the
1842          * "Unreassembled Packet" error.
1843          */
1844         length = length_remaining;
1845         if (length > plen)
1846             length = plen;
1847         next_tvb = tvb_new_subset(tvb, offset, length, plen);
1848
1849         /*
1850          * Dissect the Netlib buffer.
1851          *
1852          * Catch the ReportedBoundsError exception; if this
1853          * particular Netlib buffer happens to get a
1854          * ReportedBoundsError exception, that doesn't mean
1855          * that we should stop dissecting PDUs within this frame
1856          * or chunk of reassembled data.
1857          *
1858          * If it gets a BoundsError, we can stop, as there's nothing
1859          * more to see, so we just re-throw it.
1860          */
1861         pd_save = pinfo->private_data;
1862         TRY {
1863             dissect_netlib_buffer(next_tvb, pinfo, tree);
1864         }
1865         CATCH(BoundsError) {
1866             RETHROW;
1867         }
1868         CATCH(ReportedBoundsError) {
1869             /*  Restore the private_data structure in case one of the
1870              *  called dissectors modified it (and, due to the exception,
1871              *  was unable to restore it).
1872              */
1873             pinfo->private_data = pd_save;
1874
1875             show_reported_bounds_error(tvb, pinfo, tree);
1876         }
1877         ENDTRY;
1878
1879         /*
1880          * Step to the next Netlib buffer.
1881          */
1882         offset += plen;
1883     }
1884 }
1885
1886 static gboolean
1887 dissect_tds_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1888 {
1889     int offset = 0;
1890     guint8 type;
1891     guint8 status;
1892     guint16 plen;
1893     conversation_t *conv;
1894
1895     /*
1896      * If we don't have even enough data for a Netlib header,
1897      * just say it's not TDS.
1898      */
1899     if (tvb_length(tvb) < 8)
1900         return FALSE;
1901
1902     /*
1903      * Quickly scan all the data we have in order to see if
1904      * everything in it looks like Netlib traffic.
1905      */
1906     while (tvb_bytes_exist(tvb, offset, 1)) {
1907         /*
1908          * Check the type field.
1909          */
1910         type = tvb_get_guint8(tvb, offset);
1911         if (!is_valid_tds_type(type))
1912             return FALSE;
1913
1914         /*
1915          * Check the status field, if it's present.
1916          */
1917         if (!tvb_bytes_exist(tvb, offset + 1, 1))
1918             break;
1919         status = tvb_get_guint8(tvb, offset + 1);
1920         if (!is_valid_tds_status(status))
1921             return FALSE;
1922
1923         /*
1924          * Get the length of the PDU.
1925          */
1926         if (!tvb_bytes_exist(tvb, offset + 2, 2))
1927             break;
1928         plen = tvb_get_ntohs(tvb, offset + 2);
1929         if (plen < 8) {
1930             /*
1931              * The length is less than the header length.
1932              * That's bogus.
1933              */
1934             return FALSE;
1935         }
1936
1937         /*
1938          * If we're at the beginning of the segment, check the
1939          * payload if it's a login packet.
1940          */
1941         if (offset == 0) {
1942             if (!netlib_check_login_pkt(tvb, offset, pinfo, type))
1943                 return FALSE;
1944         }
1945
1946         /*
1947          * Step to the next Netlib buffer.
1948          */
1949         offset += plen;
1950     }
1951
1952     /*
1953      * OK, it passes the test; assume the rest of this conversation
1954      * is TDS.
1955      */
1956     conv = find_or_create_conversation(pinfo);
1957     conversation_set_dissector(conv, tds_tcp_handle);
1958
1959     /*
1960      * Now dissect it as TDS.
1961      */
1962     dissect_tds_tcp(tvb, pinfo, tree);
1963     return TRUE;
1964 }
1965
1966 static void
1967 tds_init(void)
1968 {
1969     /*
1970      * Initialize the fragment and reassembly tables.
1971      */
1972     fragment_table_init(&tds_fragment_table);
1973     reassembled_table_init(&tds_reassembled_table);
1974
1975 }
1976
1977 /* Register the protocol with Wireshark */
1978
1979 /* this format is required because a script is used to build the C function
1980    that calls all the protocol registration.
1981 */
1982
1983 void
1984 proto_register_tds(void)
1985 {
1986     static hf_register_info hf[] = {
1987         { &hf_tds_type,
1988           { "Type",             "tds.type",
1989             FT_UINT8, BASE_HEX, VALS(packet_type_names), 0x0,
1990             "Packet Type", HFILL }
1991         },
1992         { &hf_tds_status,
1993           { "Status",           "tds.status",
1994             FT_UINT8, BASE_DEC, VALS(status_names), 0x0,
1995             "Frame status", HFILL }
1996         },
1997         { &hf_tds_size,
1998           { "Size",             "tds.size",
1999             FT_UINT16, BASE_DEC, NULL, 0x0,
2000             "Packet Size", HFILL }
2001         },
2002         { &hf_tds_channel,
2003           { "Channel",          "tds.channel",
2004             FT_UINT16, BASE_DEC, NULL, 0x0,
2005             "Channel Number", HFILL }
2006         },
2007         { &hf_tds_packet_number,
2008           { "Packet Number",    "tds.packet_number",
2009             FT_UINT8, BASE_DEC, NULL, 0x0,
2010             NULL, HFILL }
2011         },
2012         { &hf_tds_window,
2013           { "Window",           "tds.window",
2014             FT_UINT8, BASE_DEC, NULL, 0x0,
2015             NULL, HFILL }
2016         },
2017         { &hf_tds_fragment_overlap,
2018           { "Segment overlap",  "tds.fragment.overlap",
2019             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2020             "Fragment overlaps with other fragments", HFILL }
2021         },
2022         { &hf_tds_fragment_overlap_conflict,
2023           { "Conflicting data in fragment overlap", "tds.fragment.overlap.conflict",
2024             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2025             "Overlapping fragments contained conflicting data", HFILL }
2026         },
2027         { &hf_tds_fragment_multiple_tails,
2028           { "Multiple tail fragments found", "tds.fragment.multipletails",
2029             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2030             "Several tails were found when defragmenting the packet", HFILL }
2031         },
2032         { &hf_tds_fragment_too_long_fragment,
2033           { "Segment too long", "tds.fragment.toolongfragment",
2034             FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2035             "Segment contained data past end of packet", HFILL }
2036         },
2037         { &hf_tds_fragment_error,
2038           { "Defragmentation error",    "tds.fragment.error",
2039             FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2040             "Defragmentation error due to illegal fragments", HFILL }
2041         },
2042         { &hf_tds_fragment,
2043           { "TDS Fragment",     "tds.fragment",
2044             FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2045             NULL, HFILL }
2046         },
2047         { &hf_tds_fragments,
2048           { "TDS Fragments",    "tds.fragments",
2049             FT_NONE, BASE_NONE, NULL, 0x0,
2050             NULL, HFILL }
2051         },
2052         { &hf_tds_reassembled_in,
2053           { "Reassembled TDS in frame", "tds.reassembled_in",
2054             FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2055             "This TDS packet is reassembled in this frame", HFILL }
2056         },
2057         { &hf_tds_reassembled_length,
2058           { "Reassembled TDS length", "tds.reassembled.length",
2059             FT_UINT32, BASE_DEC, NULL, 0x0,
2060             "The total length of the reassembled payload", HFILL }
2061         },
2062         { &hf_tds7_login_total_size,
2063           { "Total Packet Length", "tds7login.total_len",
2064             FT_UINT32, BASE_DEC, NULL, 0x0,
2065             "TDS7 Login Packet total packet length", HFILL }
2066         },
2067         { &hf_tds7_version,
2068           { "TDS version", "tds7login.version",
2069             FT_UINT32, BASE_HEX, NULL, 0x0,
2070             NULL, HFILL }
2071         },
2072         { &hf_tds7_packet_size,
2073           { "Packet Size", "tds7login.packet_size",
2074             FT_UINT32, BASE_DEC, NULL, 0x0,
2075             NULL, HFILL }
2076         },
2077         { &hf_tds7_client_version,
2078           { "Client version", "tds7login.client_version",
2079             FT_UINT32, BASE_DEC, NULL, 0x0,
2080             NULL, HFILL }
2081         },
2082         { &hf_tds7_client_pid,
2083           { "Client PID", "tds7login.client_pid",
2084             FT_UINT32, BASE_DEC, NULL, 0x0,
2085             NULL, HFILL }
2086         },
2087         { &hf_tds7_connection_id,
2088           { "Connection ID", "tds7login.connection_id",
2089             FT_UINT32, BASE_DEC, NULL, 0x0,
2090             NULL, HFILL }
2091         },
2092         { &hf_tds7_option_flags1,
2093           { "Option Flags 1", "tds7login.option_flags1",
2094             FT_UINT8, BASE_HEX, NULL, 0x0,
2095             NULL, HFILL }
2096         },
2097         { &hf_tds7_option_flags2,
2098           { "Option Flags 2", "tds7login.option_flags2",
2099             FT_UINT8, BASE_HEX, NULL, 0x0,
2100             NULL, HFILL }
2101         },
2102         { &hf_tds7_sql_type_flags,
2103           { "SQL Type Flags", "tds7login.sql_type_flags",
2104             FT_UINT8, BASE_HEX, NULL, 0x0,
2105             NULL, HFILL }
2106         },
2107         { &hf_tds7_reserved_flags,
2108           { "Reserved Flags", "tds7login.reserved_flags",
2109             FT_UINT8, BASE_HEX, NULL, 0x0,
2110             NULL, HFILL }
2111         },
2112         { &hf_tds7_time_zone,
2113           { "Time Zone", "tds7login.time_zone",
2114             FT_UINT32, BASE_HEX, NULL, 0x0,
2115             NULL, HFILL }
2116         },
2117         { &hf_tds7_collation,
2118           { "Collation", "tds7login.collation",
2119             FT_UINT32, BASE_HEX, NULL, 0x0,
2120             NULL, HFILL }
2121         },
2122         { &hf_tds7_message,
2123           { "Message", "tds7.message",
2124             FT_STRING, BASE_NONE, NULL, 0x0,
2125             NULL, HFILL }
2126         },
2127     };
2128
2129     static gint *ett[] = {
2130         &ett_tds,
2131         &ett_tds_fragments,
2132         &ett_tds_fragment,
2133         &ett_tds_token,
2134         &ett_tds7_login,
2135         &ett_tds7_hdr,
2136     };
2137     module_t *tds_module;
2138
2139 /* Register the protocol name and description */
2140     proto_tds = proto_register_protocol("Tabular Data Stream",
2141                                         "TDS", "tds");
2142
2143 /* Required function calls to register the header fields and subtrees used */
2144     proto_register_field_array(proto_tds, hf, array_length(hf));
2145     proto_register_subtree_array(ett, array_length(ett));
2146
2147 /* Allow dissector to be found by name. */
2148     register_dissector("tds", dissect_tds_tcp, proto_tds);
2149
2150     tds_module = prefs_register_protocol(proto_tds, NULL);
2151     prefs_register_bool_preference(tds_module, "desegment_buffers",
2152                                    "Reassemble TDS buffers spanning multiple TCP segments",
2153                                    "Whether the TDS dissector should reassemble TDS buffers spanning multiple TCP segments. "
2154                                    "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2155                                    &tds_desegment);
2156     prefs_register_bool_preference(tds_module, "defragment",
2157                                    "Reassemble fragmented TDS messages with multiple buffers",
2158                                    "Whether the TDS dissector should defragment messages spanning multiple Netlib buffers",
2159                                    &tds_defragment);
2160     prefs_register_enum_preference(tds_module, "protocol_type",
2161                                    "TDS Protocol Type",
2162                                    "Hint as to version of TDS protocol being decoded",
2163                                    &tds_protocol_type, tds_protocol_type_options, FALSE);
2164     prefs_register_enum_preference(tds_module, "endian_type",
2165                                    "TDS decode as",
2166                                    "Hint as to whether to decode TDS protocol as little-endian or big-endian. (TDS7/8 always decoded as little-endian)",
2167                                    &tds_little_endian, tds_endian_type_options, FALSE);
2168     prefs_register_range_preference(tds_module, "tcp_ports",
2169                                     "TDS TCP ports",
2170                                     "Additional TCP ports to decode as TDS",
2171                                     &tds_tcp_ports, 0xFFFF);
2172
2173     register_init_routine(tds_init);
2174 }
2175
2176 /* If this dissector uses sub-dissector registration add a registration routine.
2177    This format is required because a script is used to find these routines and
2178    create the code that calls these routines.
2179 */
2180 void
2181 proto_reg_handoff_tds(void)
2182 {
2183     tds_tcp_handle = create_dissector_handle(dissect_tds_tcp, proto_tds);
2184
2185     /* Initial TDS ports: MS SQL default ports */
2186     dissector_add("tcp.port", 1433, tds_tcp_handle);
2187     dissector_add("tcp.port", 2433, tds_tcp_handle);
2188
2189     heur_dissector_add("tcp", dissect_tds_tcp_heur, proto_tds);
2190
2191     ntlmssp_handle = find_dissector("ntlmssp");
2192     gssapi_handle = find_dissector("gssapi");
2193     data_handle = find_dissector("data");
2194 }