c751317f838f3af3b37a2818d695a3a9336ad6eb
[obnox/wireshark/wip.git] / epan / dissectors / packet-smb-pipe.c
1 /*
2 XXX  Fixme : shouldnt show [malformed frame] for long packets
3 */
4
5 /* packet-smb-pipe.c
6  * Routines for SMB named pipe packet dissection
7  * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
8  * significant rewrite to tvbuffify the dissector, Ronnie Sahlberg and
9  * Guy Harris 2001
10  *
11  * $Id$
12  *
13  * Ethereal - Network traffic analyzer
14  * By Gerald Combs <gerald@ethereal.com>
15  * Copyright 1998 Gerald Combs
16  *
17  * Copied from packet-pop.c
18  *
19  * This program is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU General Public License
21  * as published by the Free Software Foundation; either version 2
22  * of the License, or (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program; if not, write to the Free Software
31  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <stdio.h>
39
40 #include <time.h>
41 #include <string.h>
42 #include <glib.h>
43 #include <ctype.h>
44 #include <epan/packet.h>
45 #include "smb.h"
46 #include "packet-smb-pipe.h"
47 #include "packet-smb-browse.h"
48 #include "packet-smb-common.h"
49 #include "packet-windows-common.h"
50 #include "packet-dcerpc.h"
51 #include <epan/reassemble.h>
52
53 static int proto_smb_pipe = -1;
54 static int hf_pipe_function = -1;
55 static int hf_pipe_priority = -1;
56 static int hf_pipe_peek_available = -1;
57 static int hf_pipe_peek_remaining = -1;
58 static int hf_pipe_peek_status = -1;
59 static int hf_pipe_getinfo_info_level = -1;
60 static int hf_pipe_getinfo_output_buffer_size = -1;
61 static int hf_pipe_getinfo_input_buffer_size = -1;
62 static int hf_pipe_getinfo_maximum_instances = -1;
63 static int hf_pipe_getinfo_current_instances = -1;
64 static int hf_pipe_getinfo_pipe_name_length = -1;
65 static int hf_pipe_getinfo_pipe_name = -1;
66 static int hf_pipe_write_raw_bytes_written = -1;
67 static int hf_pipe_fragments = -1;
68 static int hf_pipe_fragment = -1;
69 static int hf_pipe_fragment_overlap = -1;
70 static int hf_pipe_fragment_overlap_conflict = -1;
71 static int hf_pipe_fragment_multiple_tails = -1;
72 static int hf_pipe_fragment_too_long_fragment = -1;
73 static int hf_pipe_fragment_error = -1;
74 static int hf_pipe_reassembled_in = -1;
75
76 static gint ett_smb_pipe = -1;
77 static gint ett_smb_pipe_fragment = -1;
78 static gint ett_smb_pipe_fragments = -1;
79
80 static const fragment_items smb_pipe_frag_items = {
81         &ett_smb_pipe_fragment,
82         &ett_smb_pipe_fragments,
83         &hf_pipe_fragments,
84         &hf_pipe_fragment,
85         &hf_pipe_fragment_overlap,
86         &hf_pipe_fragment_overlap_conflict,
87         &hf_pipe_fragment_multiple_tails,
88         &hf_pipe_fragment_too_long_fragment,
89         &hf_pipe_fragment_error,
90         NULL,
91         "fragments"
92 };
93
94 static int proto_smb_lanman = -1;
95 static int hf_function_code = -1;
96 static int hf_param_desc = -1;
97 static int hf_return_desc = -1;
98 static int hf_aux_data_desc = -1;
99 static int hf_detail_level = -1;
100 static int hf_recv_buf_len = -1;
101 static int hf_send_buf_len = -1;
102 static int hf_continuation_from = -1;
103 static int hf_status = -1;
104 static int hf_convert = -1;
105 static int hf_ecount = -1;
106 static int hf_acount = -1;
107 static int hf_share_name = -1;
108 static int hf_share_type = -1;
109 static int hf_share_comment = -1;
110 static int hf_share_permissions = -1;
111 static int hf_share_max_uses = -1;
112 static int hf_share_current_uses = -1;
113 static int hf_share_path = -1;
114 static int hf_share_password = -1;
115 static int hf_server_name = -1;
116 static int hf_server_major = -1;
117 static int hf_server_minor = -1;
118 static int hf_server_comment = -1;
119 static int hf_abytes = -1;
120 static int hf_current_time = -1;
121 static int hf_msecs = -1;
122 static int hf_hour = -1;
123 static int hf_minute = -1;
124 static int hf_second = -1;
125 static int hf_hundredths = -1;
126 static int hf_tzoffset = -1;
127 static int hf_timeinterval = -1;
128 static int hf_day = -1;
129 static int hf_month = -1;
130 static int hf_year = -1;
131 static int hf_weekday = -1;
132 static int hf_enumeration_domain = -1;
133 static int hf_last_entry = -1;
134 static int hf_computer_name = -1;
135 static int hf_user_name = -1;
136 static int hf_group_name = -1;
137 static int hf_workstation_domain = -1;
138 static int hf_workstation_major = -1;
139 static int hf_workstation_minor = -1;
140 static int hf_logon_domain = -1;
141 static int hf_other_domains = -1;
142 static int hf_password = -1;
143 static int hf_workstation_name = -1;
144 static int hf_ustruct_size = -1;
145 static int hf_logon_code = -1;
146 static int hf_privilege_level = -1;
147 static int hf_operator_privileges = -1;
148 static int hf_num_logons = -1;
149 static int hf_bad_pw_count = -1;
150 static int hf_last_logon = -1;
151 static int hf_last_logoff = -1;
152 static int hf_logoff_time = -1;
153 static int hf_kickoff_time = -1;
154 static int hf_password_age = -1;
155 static int hf_password_can_change = -1;
156 static int hf_password_must_change = -1;
157 static int hf_script_path = -1;
158 static int hf_logoff_code = -1;
159 static int hf_duration = -1;
160 static int hf_comment = -1;
161 static int hf_user_comment = -1;
162 static int hf_full_name = -1;
163 static int hf_homedir = -1;
164 static int hf_parameters = -1;
165 static int hf_logon_server = -1;
166 static int hf_country_code = -1;
167 static int hf_workstations = -1;
168 static int hf_max_storage = -1;
169 static int hf_units_per_week = -1;
170 static int hf_logon_hours = -1;
171 static int hf_code_page = -1;
172 static int hf_new_password = -1;
173 static int hf_old_password = -1;
174 static int hf_reserved = -1;
175
176 static gint ett_lanman = -1;
177 static gint ett_lanman_unknown_entries = -1;
178 static gint ett_lanman_unknown_entry = -1;
179 static gint ett_lanman_shares = -1;
180 static gint ett_lanman_share = -1;
181 static gint ett_lanman_groups = -1;
182 static gint ett_lanman_servers = -1;
183 static gint ett_lanman_server = -1;
184
185 static dissector_handle_t data_handle;
186
187 /*
188  * See
189  *
190  *      ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt
191  *
192  * among other documents.
193  */
194
195 static const value_string status_vals[] = {
196         {0,     "Success"},
197         {5,     "User has insufficient privilege"},
198         {65,    "Network access is denied"},
199         {86,    "The specified password is invalid"},
200         {SMBE_moredata, "Additional data is available"},
201         {2114,  "Service is not running on the remote computer"},
202         {2123,  "Supplied buffer is too small"},
203         {2141,  "Server is not configured for transactions (IPC$ not shared)"},
204         {2212,  "An error occurred while loading or running the logon script"},
205         {2214,  "The logon was not validated by any server"},
206         {2217,  "The logon server is running an older software version"},
207         {2221,  "The user name was not found"},
208         {2226,  "Operation not permitted on Backup Domain Controller"},
209         {2240,  "The user is not allowed to logon from this computer"},
210         {2241,  "The user is not allowed to logon at this time"},
211         {2242,  "The user password has expired"},
212         {2243,  "The password cannot be changed"},
213         {2246,  "The password is too short"},
214         {0,     NULL}
215 };
216
217 static const value_string privilege_vals[] = {
218         {0, "Guest"},
219         {1, "User"},
220         {2, "Administrator"},
221         {0, NULL}
222 };
223
224 static const value_string op_privilege_vals[] = {
225         {0, "Print operator"},
226         {1, "Communications operator"},
227         {2, "Server operator"},
228         {3, "Accounts operator"},
229         {0, NULL}
230 };
231
232 static const value_string weekday_vals[] = {
233         {0, "Sunday"},
234         {1, "Monday"},
235         {2, "Tuesday"},
236         {3, "Wednesday"},
237         {4, "Thursday"},
238         {5, "Friday"},
239         {6, "Saturday"},
240         {0, NULL}
241 };
242
243 static int
244 add_word_param(tvbuff_t *tvb, int offset, int count _U_,
245     packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
246 {
247         guint16 WParam;
248
249         if (hf_index != -1)
250                 proto_tree_add_item(tree, hf_index, tvb, offset, 2, TRUE);
251         else {
252                 WParam = tvb_get_letohs(tvb, offset);
253                 proto_tree_add_text(tree, tvb, offset, 2,
254                     "Word Param: %u (0x%04X)", WParam, WParam);
255         }
256         offset += 2;
257         return offset;
258 }
259
260 static int
261 add_dword_param(tvbuff_t *tvb, int offset, int count _U_,
262     packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
263 {
264         guint32 LParam;
265
266         if (hf_index != -1)
267                 proto_tree_add_item(tree, hf_index, tvb, offset, 4, TRUE);
268         else {
269                 LParam = tvb_get_letohl(tvb, offset);
270                 proto_tree_add_text(tree, tvb, offset, 4,
271                     "Doubleword Param: %u (0x%08X)", LParam, LParam);
272         }
273         offset += 4;
274         return offset;
275 }
276
277 static int
278 add_byte_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo _U_,
279     proto_tree *tree, int convert _U_, int hf_index)
280 {
281         guint8 BParam;
282         header_field_info *hfinfo;
283
284         if (hf_index != -1) {
285                 hfinfo = proto_registrar_get_nth(hf_index);
286                 if (hfinfo && count != 1 &&
287                                 (hfinfo->type == FT_INT8 || hfinfo->type == FT_UINT8)
288                                 && count != 1) {
289                         THROW(ReportedBoundsError);
290                 }
291                 proto_tree_add_item(tree, hf_index, tvb, offset, count, TRUE);
292         } else {
293                 if (count == 1) {
294                         BParam = tvb_get_guint8(tvb, offset);
295                         proto_tree_add_text(tree, tvb, offset, count,
296                             "Byte Param: %u (0x%02X)",
297                             BParam, BParam);
298                 } else {
299                         proto_tree_add_text(tree, tvb, offset, count,
300                             "Byte Param: %s",
301                             tvb_bytes_to_str(tvb, offset, count));
302                 }
303         }
304         offset += count;
305         return offset;
306 }
307
308 static int
309 add_pad_param(tvbuff_t *tvb _U_, int offset, int count, packet_info *pinfo _U_,
310     proto_tree *tree _U_, int convert _U_, int hf_index _U_)
311 {
312         /*
313          * This is for parameters that have descriptor entries but that
314          * are, in practice, just padding.
315          */
316         offset += count;
317         return offset;
318 }
319
320 static void
321 add_null_pointer_param(tvbuff_t *tvb, int offset, int count _U_,
322     packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
323 {
324         if (hf_index != -1) {
325                 proto_tree_add_text(tree, tvb, offset, 0,
326                   "%s (Null pointer)",
327                   proto_registrar_get_name(hf_index));
328         } else {
329                 proto_tree_add_text(tree, tvb, offset, 0,
330                     "String Param (Null pointer)");
331         }
332 }
333
334 static int
335 add_string_param(tvbuff_t *tvb, int offset, int count _U_,
336     packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
337 {
338         guint string_len;
339
340         string_len = tvb_strsize(tvb, offset);
341         if (hf_index != -1) {
342                 proto_tree_add_item(tree, hf_index, tvb, offset, string_len,
343                     TRUE);
344         } else {
345                 proto_tree_add_text(tree, tvb, offset, string_len,
346                     "String Param: %s",
347                     tvb_format_text(tvb, offset, string_len));
348         }
349         offset += string_len;
350         return offset;
351 }
352
353 static const char *
354 get_stringz_pointer_value(tvbuff_t *tvb, int offset, int convert, int *cptrp,
355     int *lenp)
356 {
357         int cptr;
358         gint string_len;
359
360         /* pointer to string */
361         cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
362         *cptrp = cptr;
363
364         /* string */
365         if (tvb_offset_exists(tvb, cptr) &&
366             (string_len = tvb_strnlen(tvb, cptr, -1)) != -1) {
367                 string_len++;   /* include the terminating '\0' */
368                 *lenp = string_len;
369                 return tvb_format_text(tvb, cptr, string_len - 1);
370         } else
371                 return NULL;
372 }
373
374 static int
375 add_stringz_pointer_param(tvbuff_t *tvb, int offset, int count _U_,
376     packet_info *pinfo _U_, proto_tree *tree, int convert, int hf_index)
377 {
378         int cptr;
379         const char *string;
380         gint string_len;
381
382         string = get_stringz_pointer_value(tvb, offset, convert, &cptr,
383             &string_len);
384         offset += 4;
385
386         /* string */
387         if (string != NULL) {
388                 if (hf_index != -1) {
389                         proto_tree_add_item(tree, hf_index, tvb, cptr,
390                             string_len, TRUE);
391                 } else {
392                         proto_tree_add_text(tree, tvb, cptr, string_len,
393                             "String Param: %s", string);
394                 }
395         } else {
396                 if (hf_index != -1) {
397                         proto_tree_add_text(tree, tvb, 0, 0,
398                             "%s: <String goes past end of frame>",
399                             proto_registrar_get_name(hf_index));
400                 } else {
401                         proto_tree_add_text(tree, tvb, 0, 0,
402                             "String Param: <String goes past end of frame>");
403                 }
404         }
405
406         return offset;
407 }
408
409 static int
410 add_bytes_pointer_param(tvbuff_t *tvb, int offset, int count,
411     packet_info *pinfo _U_, proto_tree *tree, int convert, int hf_index)
412 {
413         int cptr;
414
415         /* pointer to byte array */
416         cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
417         offset += 4;
418
419         /* bytes */
420         if (tvb_bytes_exist(tvb, cptr, count)) {
421                 if (hf_index != -1) {
422                         proto_tree_add_item(tree, hf_index, tvb, cptr,
423                             count, TRUE);
424                 } else {
425                         proto_tree_add_text(tree, tvb, cptr, count,
426                             "Byte Param: %s",
427                             tvb_bytes_to_str(tvb, cptr, count));
428                 }
429         } else {
430                 if (hf_index != -1) {
431                         proto_tree_add_text(tree, tvb, 0, 0,
432                             "%s: <Bytes go past end of frame>",
433                             proto_registrar_get_name(hf_index));
434                 } else {
435                         proto_tree_add_text(tree, tvb, 0, 0,
436                             "Byte Param: <Bytes goes past end of frame>");
437                 }
438         }
439
440         return offset;
441 }
442
443 static int
444 add_detail_level(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo,
445     proto_tree *tree, int convert _U_, int hf_index)
446 {
447         struct smb_info *smb_info = pinfo->private_data;
448         smb_transact_info_t *trp = NULL;
449         guint16 level;
450
451         if (smb_info->sip->extra_info_type == SMB_EI_TRI)
452                 trp = smb_info->sip->extra_info;
453
454         level = tvb_get_letohs(tvb, offset);
455         if (!pinfo->fd->flags.visited)
456                 trp->info_level = level;        /* remember this for the response */
457         proto_tree_add_uint(tree, hf_index, tvb, offset, 2, level);
458         offset += 2;
459         return offset;
460 }
461
462 static int
463 add_max_uses(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo _U_,
464     proto_tree *tree, int convert _U_, int hf_index)
465 {
466         guint16 WParam;
467
468         WParam = tvb_get_letohs(tvb, offset);
469         if (WParam == 0xffff) { /* -1 */
470                 proto_tree_add_uint_format(tree, hf_index, tvb,
471                     offset, 2, WParam,
472                     "%s: No limit",
473                     proto_registrar_get_name(hf_index));
474         } else {
475                 proto_tree_add_uint(tree, hf_index, tvb,
476                             offset, 2, WParam);
477         }
478         offset += 2;
479         return offset;
480 }
481
482 static int
483 add_server_type(tvbuff_t *tvb, int offset, int count _U_,
484     packet_info *pinfo, proto_tree *tree, int convert _U_, int hf_index _U_)
485 {
486         offset = dissect_smb_server_type_flags(
487                 tvb, offset, pinfo, tree, NULL, FALSE);
488         return offset;
489 }
490
491 static int
492 add_server_type_info(tvbuff_t *tvb, int offset, int count _U_,
493     packet_info *pinfo, proto_tree *tree, int convert _U_, int hf_index _U_)
494 {
495         offset = dissect_smb_server_type_flags(
496                 tvb, offset, pinfo, tree, NULL, TRUE);
497         return offset;
498 }
499
500 static int
501 add_reltime(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo _U_,
502     proto_tree *tree, int convert _U_, int hf_index)
503 {
504         nstime_t nstime;
505
506         nstime.secs = tvb_get_letohl(tvb, offset);
507         nstime.nsecs = 0;
508         proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
509             &nstime, "%s: %s", proto_registrar_get_name(hf_index),
510             time_secs_to_str(nstime.secs));
511         offset += 4;
512         return offset;
513 }
514
515 /*
516  * Sigh.  These are for handling Microsoft's annoying almost-UNIX-time-but-
517  * it's-local-time-not-UTC time.
518  */
519 static int
520 add_abstime_common(tvbuff_t *tvb, int offset, proto_tree *tree, int hf_index,
521     const char *absent_name)
522 {
523         nstime_t nstime;
524         struct tm *tmp;
525
526         nstime.secs = tvb_get_letohl(tvb, offset);
527         nstime.nsecs = 0;
528         /*
529          * Sigh.  Sometimes it appears that -1 means "unknown", and
530          * sometimes it appears that 0 means "unknown", for the last
531          * logoff date/time.
532          */
533         if (nstime.secs == -1 || nstime.secs == 0) {
534                 proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
535                     &nstime, "%s: %s", proto_registrar_get_name(hf_index),
536                     absent_name);
537         } else {
538                 /*
539                  * Run it through "gmtime()" to break it down, and then
540                  * run it through "mktime()" to put it back together
541                  * as UTC.
542                  */
543                 tmp = gmtime(&nstime.secs);
544                 tmp->tm_isdst = -1;     /* we don't know if it's DST or not */
545                 nstime.secs = mktime(tmp);
546                 proto_tree_add_time(tree, hf_index, tvb, offset, 4,
547                     &nstime);
548         }
549         offset += 4;
550         return offset;
551 }
552
553 static int
554 add_abstime_absent_never(tvbuff_t *tvb, int offset, int count _U_,
555     packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
556 {
557         return add_abstime_common(tvb, offset, tree, hf_index, "Never");
558 }
559
560 static int
561 add_abstime_absent_unknown(tvbuff_t *tvb, int offset, int count _U_,
562     packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
563 {
564         return add_abstime_common(tvb, offset, tree, hf_index, "Unknown");
565 }
566
567 static int
568 add_nlogons(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo _U_,
569     proto_tree *tree, int convert _U_, int hf_index)
570 {
571         guint16 nlogons;
572
573         nlogons = tvb_get_letohs(tvb, offset);
574         if (nlogons == 0xffff)  /* -1 */
575                 proto_tree_add_uint_format(tree, hf_index, tvb, offset, 2,
576                     nlogons, "%s: Unknown",
577                     proto_registrar_get_name(hf_index));
578         else
579                 proto_tree_add_uint(tree, hf_index, tvb, offset, 2,
580                     nlogons);
581         offset += 2;
582         return offset;
583 }
584
585 static int
586 add_max_storage(tvbuff_t *tvb, int offset, int count _U_,
587     packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
588 {
589         guint32 max_storage;
590
591         max_storage = tvb_get_letohl(tvb, offset);
592         if (max_storage == 0xffffffff)
593                 proto_tree_add_uint_format(tree, hf_index, tvb, offset, 4,
594                     max_storage, "%s: No limit",
595                     proto_registrar_get_name(hf_index));
596         else
597                 proto_tree_add_uint(tree, hf_index, tvb, offset, 4,
598                     max_storage);
599         offset += 4;
600         return offset;
601 }
602
603 static int
604 add_logon_hours(tvbuff_t *tvb, int offset, int count, packet_info *pinfo _U_,
605     proto_tree *tree, int convert, int hf_index)
606 {
607         int cptr;
608
609         /* pointer to byte array */
610         cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
611         offset += 4;
612
613         /* bytes */
614         if (tvb_bytes_exist(tvb, cptr, count)) {
615                 if (count == 21) {
616                         /*
617                          * The logon hours should be exactly 21 bytes long.
618                          *
619                          * XXX - should actually carve up the bits;
620                          * we need the units per week to do that, though.
621                          */
622                         proto_tree_add_item(tree, hf_index, tvb, cptr, count,
623                             TRUE);
624                 } else {
625                         proto_tree_add_bytes_format(tree, hf_index, tvb,
626                             cptr, count, tvb_get_ptr(tvb, cptr, count),
627                             "%s: %s (wrong length, should be 21, is %d",
628                             proto_registrar_get_name(hf_index),
629                             tvb_bytes_to_str(tvb, cptr, count), count);
630                 }
631         } else {
632                 proto_tree_add_text(tree, tvb, 0, 0,
633                     "%s: <Bytes go past end of frame>",
634                     proto_registrar_get_name(hf_index));
635         }
636
637         return offset;
638 }
639
640 static int
641 add_tzoffset(tvbuff_t *tvb, int offset, int count _U_, packet_info *pinfo _U_,
642     proto_tree *tree, int convert _U_, int hf_index)
643 {
644         gint16 tzoffset;
645
646         tzoffset = tvb_get_letohs(tvb, offset);
647         if (tzoffset < 0) {
648                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
649                     tzoffset, "%s: %s east of UTC",
650                     proto_registrar_get_name(hf_index),
651                     time_secs_to_str(-tzoffset*60));
652         } else if (tzoffset > 0) {
653                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
654                     tzoffset, "%s: %s west of UTC",
655                     proto_registrar_get_name(hf_index),
656                     time_secs_to_str(tzoffset*60));
657         } else {
658                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
659                     tzoffset, "%s: at UTC",
660                     proto_registrar_get_name(hf_index));
661         }
662         offset += 2;
663         return offset;
664 }
665
666 static int
667 add_timeinterval(tvbuff_t *tvb, int offset, int count _U_,
668     packet_info *pinfo _U_, proto_tree *tree, int convert _U_, int hf_index)
669 {
670         guint16 timeinterval;
671
672         timeinterval = tvb_get_letohs(tvb, offset);
673         proto_tree_add_uint_format(tree, hf_timeinterval, tvb, offset, 2,
674            timeinterval, "%s: %f seconds", proto_registrar_get_name(hf_index),
675            timeinterval*.0001);
676         offset += 2;
677         return offset;
678 }
679
680 static int
681 add_logon_args(tvbuff_t *tvb, int offset, int count, packet_info *pinfo _U_,
682     proto_tree *tree, int convert _U_, int hf_index _U_)
683 {
684         if (count != 54) {
685                 proto_tree_add_text(tree, tvb, offset, count,
686                    "Bogus NetWkstaUserLogon parameters: length is %d, should be 54",
687                    count);
688                 offset += count;
689                 return offset;
690         }
691
692         /* user name */
693         proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
694         offset += 21;
695
696         /* pad1 */
697         offset += 1;
698
699         /* password */
700         proto_tree_add_item(tree, hf_password, tvb, offset, 15, TRUE);
701         offset += 15;
702
703         /* pad2 */
704         offset += 1;
705
706         /* workstation name */
707         proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE);
708         offset += 16;
709         return offset;
710 }
711
712 /*
713  * The following data structure describes the Remote API requests we
714  * understand.
715  *
716  * Simply fill in the number and parameter information.
717  * Try to keep them in order.
718  *
719  * We will extend this data structure as we try to decode more.
720  */
721
722 /*
723  * This is a pointer to a function to process an item.
724  */
725 typedef int     (*item_func)(tvbuff_t *, int, int, packet_info *, proto_tree *,
726                              int, int);
727
728 /*
729  * Type of an item; determines what parameter strings are valid for
730  * the item.
731  */
732 typedef enum {
733         PARAM_NONE,     /* for the end-of-list stopper */
734         PARAM_WORD,     /* 'W' or 'h' - 16-bit word */
735         PARAM_DWORD,    /* 'D' or 'i' - 32-bit word */
736         PARAM_BYTES,    /* 'B' or 'b' or 'g' or 'O' - one or more bytes */
737         PARAM_STRINGZ   /* 'z' or 'O' - null-terminated string */
738 } param_type_t;
739
740 /*
741  * This structure describes an item; "hf_index" points to the index
742  * for the field corresponding to that item, "func" points to the
743  * function to use to add that item to the tree, and "type" is the
744  * type that the item is supposed to have.
745  */
746 typedef struct {
747         int             *hf_index;
748         item_func       func;
749         param_type_t    type;
750 } item_t;
751
752 /*
753  * This structure describes a list of items; each list of items
754  * has a corresponding detail level.
755  */
756 typedef struct {
757         int             level;
758         const item_t    *item_list;
759 } item_list_t;
760
761 struct lanman_desc {
762         int             lanman_num;
763         const item_t    *req;
764         proto_item      *(*req_data_item)(tvbuff_t *, packet_info *,
765                                           proto_tree *, int);
766         gint            *ett_req_data;
767         const item_t    *req_data;
768         const item_t    *req_aux_data;
769         const item_t    *resp;
770         const gchar     *resp_data_entry_list_label;
771         gint            *ett_data_entry_list;
772         proto_item      *(*resp_data_element_item)(tvbuff_t *, proto_tree *,
773                                                    int);
774         gint            *ett_resp_data_element_item;
775         const item_list_t *resp_data_list;
776         const item_t    *resp_aux_data;
777 };
778
779 static int no_hf = -1;  /* for padding crap */
780
781 static const item_t lm_params_req_netshareenum[] = {
782         { &hf_detail_level, add_detail_level, PARAM_WORD },
783         { &hf_recv_buf_len, add_word_param, PARAM_WORD },
784         { NULL, NULL, PARAM_NONE }
785 };
786
787 static const item_t lm_params_resp_netshareenum[] = {
788         { &hf_acount, add_word_param, PARAM_WORD },
789         { NULL, NULL, PARAM_NONE }
790 };
791
792 /*
793  * Create a subtree for a share.
794  */
795 static proto_item *
796 netshareenum_share_entry(tvbuff_t *tvb, proto_tree *tree, int offset)
797 {
798         if (tree) {
799                 return proto_tree_add_text(tree, tvb, offset, -1,
800                     "Share %.13s", tvb_get_ptr(tvb, offset, 13));
801         } else
802                 return NULL;
803 }
804
805 static const item_t lm_null[] = {
806         { NULL, NULL, PARAM_NONE }
807 };
808
809 static const item_list_t lm_null_list[] = {
810         { -1, lm_null }
811 };
812
813 static const item_t lm_data_resp_netshareenum_1[] = {
814         { &hf_share_name, add_byte_param, PARAM_BYTES },
815         { &no_hf, add_pad_param, PARAM_BYTES },
816         { &hf_share_type, add_word_param, PARAM_WORD },
817         { &hf_share_comment, add_stringz_pointer_param, PARAM_STRINGZ },
818         { NULL, NULL, PARAM_NONE }
819 };
820
821 static const item_list_t lm_data_resp_netshareenum[] = {
822         { 1, lm_data_resp_netshareenum_1 },
823         { -1, lm_null }
824 };
825
826 static const item_t lm_params_req_netsharegetinfo[] = {
827         { &hf_share_name, add_string_param, PARAM_STRINGZ },
828         { &hf_detail_level, add_detail_level, PARAM_WORD },
829         { NULL, NULL, PARAM_NONE }
830 };
831
832 static const item_t lm_params_resp_netsharegetinfo[] = {
833         { &hf_abytes, add_word_param, PARAM_WORD },
834         { NULL, NULL, PARAM_NONE }
835 };
836
837 static const item_t lm_data_resp_netsharegetinfo_0[] = {
838         { &hf_share_name, add_byte_param, PARAM_BYTES },
839         { NULL, NULL, PARAM_NONE }
840 };
841
842 static const item_t lm_data_resp_netsharegetinfo_1[] = {
843         { &hf_share_name, add_byte_param, PARAM_BYTES },
844         { &no_hf, add_pad_param, PARAM_BYTES },
845         { &hf_share_type, add_word_param, PARAM_WORD },
846         { &hf_share_comment, add_stringz_pointer_param, PARAM_STRINGZ },
847         { NULL, NULL, PARAM_NONE }
848 };
849
850 static const item_t lm_data_resp_netsharegetinfo_2[] = {
851         { &hf_share_name, add_byte_param, PARAM_BYTES },
852         { &no_hf, add_pad_param, PARAM_BYTES },
853         { &hf_share_type, add_word_param, PARAM_WORD },
854         { &hf_share_comment, add_stringz_pointer_param, PARAM_STRINGZ },
855         { &hf_share_permissions, add_word_param, PARAM_WORD }, /* XXX - do as bit fields */
856         { &hf_share_max_uses, add_max_uses, PARAM_WORD },
857         { &hf_share_current_uses, add_word_param, PARAM_WORD },
858         { &hf_share_path, add_stringz_pointer_param, PARAM_STRINGZ },
859         { &hf_share_password, add_byte_param, PARAM_BYTES },
860         { NULL, NULL, PARAM_NONE }
861 };
862
863 static const item_list_t lm_data_resp_netsharegetinfo[] = {
864         { 0, lm_data_resp_netsharegetinfo_0 },
865         { 1, lm_data_resp_netsharegetinfo_1 },
866         { 2, lm_data_resp_netsharegetinfo_2 },
867         { -1, lm_null }
868 };
869
870 static const item_t lm_params_req_netservergetinfo[] = {
871         { &hf_detail_level, add_detail_level, PARAM_WORD },
872         { NULL, NULL, PARAM_NONE }
873 };
874
875 static const item_t lm_params_resp_netservergetinfo[] = {
876         { &hf_abytes, add_word_param, PARAM_WORD },
877         { NULL, NULL, PARAM_NONE }
878 };
879
880 static const item_t lm_data_serverinfo_0[] = {
881         { &hf_server_name, add_byte_param, PARAM_BYTES },
882         { NULL, NULL, PARAM_NONE }
883 };
884
885 static const item_t lm_data_serverinfo_1[] = {
886         { &hf_server_name, add_byte_param, PARAM_BYTES },
887         { &hf_server_major, add_byte_param, PARAM_BYTES },
888         { &hf_server_minor, add_byte_param, PARAM_BYTES },
889         { &no_hf, add_server_type, PARAM_DWORD },
890         { &hf_server_comment, add_stringz_pointer_param, PARAM_STRINGZ },
891         { NULL, NULL, PARAM_NONE }
892 };
893
894 static const item_list_t lm_data_serverinfo[] = {
895         { 0, lm_data_serverinfo_0 },
896         { 1, lm_data_serverinfo_1 },
897         { -1, lm_null }
898 };
899
900 static const item_t lm_params_req_netusergetinfo[] = {
901         { &hf_user_name, add_string_param, PARAM_STRINGZ },
902         { &hf_detail_level, add_detail_level, PARAM_WORD },
903         { NULL, NULL, PARAM_NONE }
904 };
905
906 static const item_t lm_params_resp_netusergetinfo[] = {
907         { &hf_abytes, add_word_param, PARAM_WORD },
908         { NULL, NULL, PARAM_NONE }
909 };
910
911 static const item_t lm_data_resp_netusergetinfo_11[] = {
912         { &hf_user_name, add_byte_param, PARAM_BYTES },
913         { &no_hf, add_pad_param, PARAM_BYTES },
914         { &hf_comment, add_stringz_pointer_param, PARAM_STRINGZ },
915         { &hf_user_comment, add_stringz_pointer_param, PARAM_STRINGZ },
916         { &hf_full_name, add_stringz_pointer_param, PARAM_STRINGZ },
917         { &hf_privilege_level, add_word_param, PARAM_WORD },
918         { &hf_operator_privileges, add_dword_param, PARAM_DWORD },
919         { &hf_password_age, add_reltime, PARAM_DWORD },
920         { &hf_homedir, add_stringz_pointer_param, PARAM_STRINGZ },
921         { &hf_parameters, add_stringz_pointer_param, PARAM_STRINGZ },
922         { &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
923         { &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
924         { &hf_bad_pw_count, add_word_param, PARAM_WORD },
925         { &hf_num_logons, add_nlogons, PARAM_WORD },
926         { &hf_logon_server, add_stringz_pointer_param, PARAM_STRINGZ },
927         { &hf_country_code, add_word_param, PARAM_WORD },
928         { &hf_workstations, add_stringz_pointer_param, PARAM_STRINGZ },
929         { &hf_max_storage, add_max_storage, PARAM_DWORD },
930         { &hf_units_per_week, add_word_param, PARAM_WORD },
931         { &hf_logon_hours, add_logon_hours, PARAM_BYTES },
932         { &hf_code_page, add_word_param, PARAM_WORD },
933         { NULL, NULL, PARAM_NONE }
934 };
935
936 static const item_list_t lm_data_resp_netusergetinfo[] = {
937         { 11, lm_data_resp_netusergetinfo_11 },
938         { -1, lm_null }
939 };
940
941 static const item_t lm_params_req_netusergetgroups[] = {
942         { &hf_user_name, add_string_param, PARAM_STRINGZ },
943         { &hf_detail_level, add_detail_level, PARAM_WORD },
944         { NULL, NULL, PARAM_NONE }
945 };
946
947 static const item_t lm_params_resp_netusergetgroups[] = {
948         { &hf_abytes, add_word_param, PARAM_WORD },
949         { NULL, NULL, PARAM_NONE }
950 };
951
952 static const item_t lm_data_resp_netusergetgroups_0[] = {
953         { &hf_group_name, add_byte_param, PARAM_BYTES },
954         { NULL, NULL, PARAM_NONE }
955 };
956
957 static const item_list_t lm_data_resp_netusergetgroups[] = {
958         { 0, lm_data_resp_netusergetgroups_0 },
959         { -1, lm_null }
960 };
961
962 /*
963  * Has no detail level; make it the default.
964  */
965 static const item_t lm_data_resp_netremotetod_nolevel[] = {
966         { &hf_current_time, add_abstime_absent_unknown, PARAM_DWORD },
967         { &hf_msecs, add_dword_param, PARAM_DWORD },
968         { &hf_hour, add_byte_param, PARAM_BYTES },
969         { &hf_minute, add_byte_param, PARAM_BYTES },
970         { &hf_second, add_byte_param, PARAM_BYTES },
971         { &hf_hundredths, add_byte_param, PARAM_BYTES },
972         { &hf_tzoffset, add_tzoffset, PARAM_WORD },
973         { &hf_timeinterval, add_timeinterval, PARAM_WORD },
974         { &hf_day, add_byte_param, PARAM_BYTES },
975         { &hf_month, add_byte_param, PARAM_BYTES },
976         { &hf_year, add_word_param, PARAM_WORD },
977         { &hf_weekday, add_byte_param, PARAM_BYTES },
978         { NULL, NULL, PARAM_NONE }
979 };
980
981 static const item_list_t lm_data_resp_netremotetod[] = {
982         { -1, lm_data_resp_netremotetod_nolevel },
983 };
984
985 static const item_t lm_params_req_netserverenum2[] = {
986         { &hf_detail_level, add_detail_level, PARAM_WORD },
987         { &no_hf, add_server_type_info, PARAM_DWORD },
988         { &hf_enumeration_domain, add_string_param, PARAM_STRINGZ },
989         { NULL, NULL, PARAM_NONE }
990 };
991
992 /*
993  * Create a subtree for a server.
994  */
995 static proto_item *
996 netserverenum2_server_entry(tvbuff_t *tvb, proto_tree *tree, int offset)
997 {
998         if (tree) {
999                 return proto_tree_add_text(tree, tvb, offset, -1,
1000                             "Server %.16s", tvb_get_ptr(tvb, offset, 16));
1001         } else
1002                 return NULL;
1003 }
1004
1005 static const item_t lm_params_resp_netserverenum2[] = {
1006         { &hf_acount, add_word_param, PARAM_WORD },
1007         { NULL, NULL, PARAM_NONE }
1008 };
1009
1010
1011 static const item_t lm_params_req_netserverenum3[] = {
1012         { &hf_detail_level, add_detail_level, PARAM_WORD },
1013         { &no_hf, add_server_type_info, PARAM_DWORD },
1014         { &hf_enumeration_domain, add_string_param, PARAM_STRINGZ },
1015         { &hf_last_entry, add_string_param, PARAM_STRINGZ },
1016         { NULL, NULL, PARAM_NONE }
1017 };
1018
1019
1020 static const item_t lm_params_req_netwkstagetinfo[] = {
1021         { &hf_detail_level, add_detail_level, PARAM_WORD },
1022         { NULL, NULL, PARAM_NONE }
1023 };
1024
1025 static const item_t lm_params_resp_netwkstagetinfo[] = {
1026         { &hf_abytes, add_word_param, PARAM_WORD },
1027         { NULL, NULL, PARAM_NONE }
1028 };
1029
1030 static const item_t lm_data_resp_netwkstagetinfo_10[] = {
1031         { &hf_computer_name, add_stringz_pointer_param, PARAM_STRINGZ },
1032         { &hf_user_name, add_stringz_pointer_param, PARAM_STRINGZ },
1033         { &hf_workstation_domain, add_stringz_pointer_param, PARAM_STRINGZ },
1034         { &hf_workstation_major, add_byte_param, PARAM_BYTES },
1035         { &hf_workstation_minor, add_byte_param, PARAM_BYTES },
1036         { &hf_logon_domain, add_stringz_pointer_param, PARAM_STRINGZ },
1037         { &hf_other_domains, add_stringz_pointer_param, PARAM_STRINGZ },
1038         { NULL, NULL, PARAM_NONE }
1039 };
1040
1041 static const item_list_t lm_data_resp_netwkstagetinfo[] = {
1042         { 10, lm_data_resp_netwkstagetinfo_10 },
1043         { -1, lm_null }
1044 };
1045
1046 static const item_t lm_params_req_netwkstauserlogon[] = {
1047         { &no_hf, add_stringz_pointer_param, PARAM_STRINGZ },
1048         { &no_hf, add_stringz_pointer_param, PARAM_STRINGZ },
1049         { &hf_detail_level, add_detail_level, PARAM_WORD },
1050         { &no_hf, add_logon_args, PARAM_BYTES },
1051         { &hf_ustruct_size, add_word_param, PARAM_WORD },
1052         { NULL, NULL, PARAM_NONE }
1053 };
1054
1055 static const item_t lm_params_resp_netwkstauserlogon[] = {
1056         { &hf_abytes, add_word_param, PARAM_WORD },
1057         { NULL, NULL, PARAM_NONE }
1058 };
1059
1060 static const item_t lm_data_resp_netwkstauserlogon_1[] = {
1061         { &hf_logon_code, add_word_param, PARAM_WORD },
1062         { &hf_user_name, add_byte_param, PARAM_BYTES },
1063         { &no_hf, add_pad_param, PARAM_BYTES },
1064         { &hf_privilege_level, add_word_param, PARAM_WORD },
1065         { &hf_operator_privileges, add_dword_param, PARAM_DWORD },
1066         { &hf_num_logons, add_nlogons, PARAM_WORD },
1067         { &hf_bad_pw_count, add_word_param, PARAM_WORD },
1068         { &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
1069         { &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
1070         { &hf_logoff_time, add_abstime_absent_never, PARAM_DWORD },
1071         { &hf_kickoff_time, add_abstime_absent_never, PARAM_DWORD },
1072         { &hf_password_age, add_reltime, PARAM_DWORD },
1073         { &hf_password_can_change, add_abstime_absent_never, PARAM_DWORD },
1074         { &hf_password_must_change, add_abstime_absent_never, PARAM_DWORD },
1075         { &hf_server_name, add_stringz_pointer_param, PARAM_STRINGZ },
1076         { &hf_logon_domain, add_stringz_pointer_param, PARAM_STRINGZ },
1077         { &hf_script_path, add_stringz_pointer_param, PARAM_STRINGZ },
1078         { &hf_reserved, add_dword_param, PARAM_DWORD },
1079         { NULL, NULL, PARAM_NONE }
1080 };
1081
1082 static const item_list_t lm_data_resp_netwkstauserlogon[] = {
1083         { 1, lm_data_resp_netwkstauserlogon_1 },
1084         { -1, lm_null }
1085 };
1086
1087 static const item_t lm_params_req_netwkstauserlogoff[] = {
1088         { &hf_user_name, add_byte_param, PARAM_BYTES },
1089         { &no_hf, add_pad_param, PARAM_BYTES },
1090         { &hf_workstation_name, add_byte_param, PARAM_BYTES },
1091         { NULL, NULL, PARAM_NONE }
1092 };
1093
1094 static const item_t lm_params_resp_netwkstauserlogoff[] = {
1095         { &hf_abytes, add_word_param, PARAM_WORD },
1096         { NULL, NULL, PARAM_NONE }
1097 };
1098
1099 static const item_t lm_data_resp_netwkstauserlogoff_1[] = {
1100         { &hf_logoff_code, add_word_param, PARAM_WORD },
1101         { &hf_duration, add_reltime, PARAM_DWORD },
1102         { &hf_num_logons, add_nlogons, PARAM_WORD },
1103         { NULL, NULL, PARAM_NONE }
1104 };
1105
1106 static const item_list_t lm_data_resp_netwkstauserlogoff[] = {
1107         { 1, lm_data_resp_netwkstauserlogoff_1 },
1108         { -1, lm_null }
1109 };
1110
1111 static const item_t lm_params_req_samoemchangepassword[] = {
1112         { &hf_user_name, add_string_param, PARAM_STRINGZ },
1113         { NULL, NULL, PARAM_NONE }
1114 };
1115
1116 static const item_t lm_data_req_samoemchangepassword[] = {
1117         { &hf_new_password, add_byte_param, PARAM_BYTES },
1118         { &hf_old_password, add_byte_param, PARAM_BYTES },
1119         { NULL, NULL, PARAM_NONE }
1120 };
1121
1122 #define API_NetShareEnum                0
1123 #define API_NetShareGetInfo             1
1124 #define API_NetShareSetInfo             2
1125 #define API_NetShareAdd                 3
1126 #define API_NetShareDel                 4
1127 #define API_NetShareCheck               5
1128 #define API_NetSessionEnum              6
1129 #define API_NetSessionGetInfo           7
1130 #define API_NetSessionDel               8
1131 #define API_WconnectionEnum             9
1132 #define API_NetFileEnum                 10
1133 #define API_NetFileGetInfo              11
1134 #define API_NetFileClose                12
1135 #define API_NetServerGetInfo            13
1136 #define API_NetServerSetInfo            14
1137 #define API_NetServerDiskEnum           15
1138 #define API_NetServerAdminCommand       16
1139 #define API_NetAuditOpen                17
1140 #define API_NetAuditClear               18
1141 #define API_NetErrorLogOpen             19
1142 #define API_NetErrorLogClear            20
1143 #define API_NetCharDevEnum              21
1144 #define API_NetCharDevGetInfo           22
1145 #define API_NetCharDevControl           23
1146 #define API_NetCharDevQEnum             24
1147 #define API_NetCharDevQGetInfo          25
1148 #define API_NetCharDevQSetInfo          26
1149 #define API_NetCharDevQPurge            27
1150 #define API_NetCharDevQPurgeSelf        28
1151 #define API_NetMessageNameEnum          29
1152 #define API_NetMessageNameGetInfo       30
1153 #define API_NetMessageNameAdd           31
1154 #define API_NetMessageNameDel           32
1155 #define API_NetMessageNameFwd           33
1156 #define API_NetMessageNameUnFwd         34
1157 #define API_NetMessageBufferSend        35
1158 #define API_NetMessageFileSend          36
1159 #define API_NetMessageLogFileSet        37
1160 #define API_NetMessageLogFileGet        38
1161 #define API_NetServiceEnum              39
1162 #define API_NetServiceInstall           40
1163 #define API_NetServiceControl           41
1164 #define API_NetAccessEnum               42
1165 #define API_NetAccessGetInfo            43
1166 #define API_NetAccessSetInfo            44
1167 #define API_NetAccessAdd                45
1168 #define API_NetAccessDel                46
1169 #define API_NetGroupEnum                47
1170 #define API_NetGroupAdd                 48
1171 #define API_NetGroupDel                 49
1172 #define API_NetGroupAddUser             50
1173 #define API_NetGroupDelUser             51
1174 #define API_NetGroupGetUsers            52
1175 #define API_NetUserEnum                 53
1176 #define API_NetUserAdd                  54
1177 #define API_NetUserDel                  55
1178 #define API_NetUserGetInfo              56
1179 #define API_NetUserSetInfo              57
1180 #define API_NetUserPasswordSet          58
1181 #define API_NetUserGetGroups            59
1182 /*This line and number replaced a Dead Entry for 60 */
1183 /*This line and number replaced a Dead Entry for 61 */
1184 #define API_NetWkstaSetUID              62
1185 #define API_NetWkstaGetInfo             63
1186 #define API_NetWkstaSetInfo             64
1187 #define API_NetUseEnum                  65
1188 #define API_NetUseAdd                   66
1189 #define API_NetUseDel                   67
1190 #define API_NetUseGetInfo               68
1191 #define API_WPrintQEnum                 69
1192 #define API_WPrintQGetInfo              70
1193 #define API_WPrintQSetInfo              71
1194 #define API_WPrintQAdd                  72
1195 #define API_WPrintQDel                  73
1196 #define API_WPrintQPause                74
1197 #define API_WPrintQContinue             75
1198 #define API_WPrintJobEnum               76
1199 #define API_WPrintJobGetInfo            77
1200 #define API_WPrintJobSetInfo_OLD        78
1201 /* This line and number replaced a Dead Entry for 79 */
1202 /* This line and number replaced a Dead Entry for 80 */
1203 #define API_WPrintJobDel                81
1204 #define API_WPrintJobPause              82
1205 #define API_WPrintJobContinue           83
1206 #define API_WPrintDestEnum              84
1207 #define API_WPrintDestGetInfo           85
1208 #define API_WPrintDestControl           86
1209 #define API_NetProfileSave              87
1210 #define API_NetProfileLoad              88
1211 #define API_NetStatisticsGet            89
1212 #define API_NetStatisticsClear          90
1213 #define API_NetRemoteTOD                91
1214 #define API_WNetBiosEnum                92
1215 #define API_WNetBiosGetInfo             93
1216 #define API_NetServerEnum               94
1217 #define API_I_NetServerEnum             95
1218 #define API_NetServiceGetInfo           96
1219 /* This line and number replaced a Dead Entry for 97 */
1220 /* This line and number replaced a Dead Entry for 98 */
1221 /* This line and number replaced a Dead Entry for 99 */
1222 /* This line and number replaced a Dead Entry for 100 */
1223 /* This line and number replaced a Dead Entry for 101 */
1224 /* This line and number replaced a Dead Entry for 102 */
1225 #define API_WPrintQPurge                103
1226 #define API_NetServerEnum2              104
1227 #define API_NetAccessGetUserPerms       105
1228 #define API_NetGroupGetInfo             106
1229 #define API_NetGroupSetInfo             107
1230 #define API_NetGroupSetUsers            108
1231 #define API_NetUserSetGroups            109
1232 #define API_NetUserModalsGet            110
1233 #define API_NetUserModalsSet            111
1234 #define API_NetFileEnum2                112
1235 #define API_NetUserAdd2                 113
1236 #define API_NetUserSetInfo2             114
1237 #define API_NetUserPasswordSet2         115
1238 #define API_I_NetServerEnum2            116
1239 #define API_NetConfigGet2               117
1240 #define API_NetConfigGetAll2            118
1241 #define API_NetGetDCName                119
1242 #define API_NetHandleGetInfo            120
1243 #define API_NetHandleSetInfo            121
1244 #define API_NetStatisticsGet2           122
1245 #define API_WBuildGetInfo               123
1246 #define API_NetFileGetInfo2             124
1247 #define API_NetFileClose2               125
1248 #define API_NetServerReqChallenge       126
1249 #define API_NetServerAuthenticate       127
1250 #define API_NetServerPasswordSet        128
1251 #define API_WNetAccountDeltas           129
1252 #define API_WNetAccountSync             130
1253 #define API_NetUserEnum2                131
1254 #define API_NetWkstaUserLogon           132
1255 #define API_NetWkstaUserLogoff          133
1256 #define API_NetLogonEnum                134
1257 #define API_NetErrorLogRead             135
1258 #define API_I_NetPathType               136
1259 #define API_I_NetPathCanonicalize       137
1260 #define API_I_NetPathCompare            138
1261 #define API_I_NetNameValidate           139
1262 #define API_I_NetNameCanonicalize       140
1263 #define API_I_NetNameCompare            141
1264 #define API_NetAuditRead                142
1265 #define API_WPrintDestAdd               143
1266 #define API_WPrintDestSetInfo           144
1267 #define API_WPrintDestDel               145
1268 #define API_NetUserValidate2            146
1269 #define API_WPrintJobSetInfo            147
1270 #define API_TI_NetServerDiskEnum        148
1271 #define API_TI_NetServerDiskGetInfo     149
1272 #define API_TI_FTVerifyMirror           150
1273 #define API_TI_FTAbortVerify            151
1274 #define API_TI_FTGetInfo                152
1275 #define API_TI_FTSetInfo                153
1276 #define API_TI_FTLockDisk               154
1277 #define API_TI_FTFixError               155
1278 #define API_TI_FTAbortFix               156
1279 #define API_TI_FTDiagnoseError          157
1280 #define API_TI_FTGetDriveStats          158
1281 /* This line and number replaced a Dead Entry for 159 */
1282 #define API_TI_FTErrorGetInfo           160
1283 /* This line and number replaced a Dead Entry for 161 */
1284 /* This line and number replaced a Dead Entry for 162 */
1285 #define API_NetAccessCheck              163
1286 #define API_NetAlertRaise               164
1287 #define API_NetAlertStart               165
1288 #define API_NetAlertStop                166
1289 #define API_NetAuditWrite               167
1290 #define API_NetIRemoteAPI               168
1291 #define API_NetServiceStatus            169
1292 #define API_I_NetServerRegister         170
1293 #define API_I_NetServerDeregister       171
1294 #define API_I_NetSessionEntryMake       172
1295 #define API_I_NetSessionEntryClear      173
1296 #define API_I_NetSessionEntryGetInfo    174
1297 #define API_I_NetSessionEntrySetInfo    175
1298 #define API_I_NetConnectionEntryMake    176
1299 #define API_I_NetConnectionEntryClear   177
1300 #define API_I_NetConnectionEntrySetInfo 178
1301 #define API_I_NetConnectionEntryGetInfo 179
1302 #define API_I_NetFileEntryMake          180
1303 #define API_I_NetFileEntryClear         181
1304 #define API_I_NetFileEntrySetInfo       182
1305 #define API_I_NetFileEntryGetInfo       183
1306 #define API_AltSrvMessageBufferSend     184
1307 #define API_AltSrvMessageFileSend       185
1308 #define API_wI_NetRplWkstaEnum          186
1309 #define API_wI_NetRplWkstaGetInfo       187
1310 #define API_wI_NetRplWkstaSetInfo       188
1311 #define API_wI_NetRplWkstaAdd           189
1312 #define API_wI_NetRplWkstaDel           190
1313 #define API_wI_NetRplProfileEnum        191
1314 #define API_wI_NetRplProfileGetInfo     192
1315 #define API_wI_NetRplProfileSetInfo     193
1316 #define API_wI_NetRplProfileAdd         194
1317 #define API_wI_NetRplProfileDel         195
1318 #define API_wI_NetRplProfileClone       196
1319 #define API_wI_NetRplBaseProfileEnum    197
1320 /* This line and number replaced a Dead Entry for 198 */
1321 /* This line and number replaced a Dead Entry for 199 */
1322 /* This line and number replaced a Dead Entry for 200 */
1323 #define API_WIServerSetInfo             201
1324 /* This line and number replaced a Dead Entry for 202 */
1325 /* This line and number replaced a Dead Entry for 203 */
1326 /* This line and number replaced a Dead Entry for 204 */
1327 #define API_WPrintDriverEnum            205
1328 #define API_WPrintQProcessorEnum        206
1329 #define API_WPrintPortEnum              207
1330 #define API_WNetWriteUpdateLog          208
1331 #define API_WNetAccountUpdate           209
1332 #define API_WNetAccountConfirmUpdate    210
1333 #define API_NetConfigSet                211
1334 #define API_WAccountsReplicate          212
1335 /* 213 is used by WfW */
1336 #define API_SamOEMChgPasswordUser2_P    214
1337 #define API_NetServerEnum3              215
1338 /* XXX - what about 216 through 249? */
1339 #define API_WPrintDriverGetInfo         250
1340 #define API_WPrintDriverSetInfo         251
1341 #define API_NetAliasAdd                 252
1342 #define API_NetAliasDel                 253
1343 #define API_NetAliasGetInfo             254
1344 #define API_NetAliasSetInfo             255
1345 #define API_NetAliasEnum                256
1346 #define API_NetUserGetLogonAsn          257
1347 #define API_NetUserSetLogonAsn          258
1348 #define API_NetUserGetAppSel            259
1349 #define API_NetUserSetAppSel            260
1350 #define API_NetAppAdd                   261
1351 #define API_NetAppDel                   262
1352 #define API_NetAppGetInfo               263
1353 #define API_NetAppSetInfo               264
1354 #define API_NetAppEnum                  265
1355 #define API_NetUserDCDBInit             266
1356 #define API_NetDASDAdd                  267
1357 #define API_NetDASDDel                  268
1358 #define API_NetDASDGetInfo              269
1359 #define API_NetDASDSetInfo              270
1360 #define API_NetDASDEnum                 271
1361 #define API_NetDASDCheck                272
1362 #define API_NetDASDCtl                  273
1363 #define API_NetUserRemoteLogonCheck     274
1364 #define API_NetUserPasswordSet3         275
1365 #define API_NetCreateRIPLMachine        276
1366 #define API_NetDeleteRIPLMachine        277
1367 #define API_NetGetRIPLMachineInfo       278
1368 #define API_NetSetRIPLMachineInfo       279
1369 #define API_NetEnumRIPLMachine          280
1370 #define API_I_ShareAdd                  281
1371 #define API_I_AliasEnum                 282
1372 #define API_NetAccessApply              283
1373 #define API_WPrt16Query                 284
1374 #define API_WPrt16Set                   285
1375 #define API_NetUserDel100               286
1376 #define API_NetUserRemoteLogonCheck2    287
1377 #define API_WRemoteTODSet               294
1378 #define API_WPrintJobMoveAll            295
1379 #define API_W16AppParmAdd               296
1380 #define API_W16AppParmDel               297
1381 #define API_W16AppParmGet               298
1382 #define API_W16AppParmSet               299
1383 #define API_W16RIPLMachineCreate        300
1384 #define API_W16RIPLMachineGetInfo       301
1385 #define API_W16RIPLMachineSetInfo       302
1386 #define API_W16RIPLMachineEnum          303
1387 #define API_W16RIPLMachineListParmEnum  304
1388 #define API_W16RIPLMachClassGetInfo     305
1389 #define API_W16RIPLMachClassEnum        306
1390 #define API_W16RIPLMachClassCreate      307
1391 #define API_W16RIPLMachClassSetInfo     308
1392 #define API_W16RIPLMachClassDelete      309
1393 #define API_W16RIPLMachClassLPEnum      310
1394 #define API_W16RIPLMachineDelete        311
1395 #define API_W16WSLevelGetInfo           312
1396 #define API_NetServerNameAdd            313
1397 #define API_NetServerNameDel            314
1398 #define API_NetServerNameEnum           315
1399 #define API_I_WDASDEnum                 316
1400 #define API_I_WDASDEnumTerminate        317
1401 #define API_I_WDASDSetInfo2             318
1402
1403 static const struct lanman_desc lmd[] = {
1404         { API_NetShareEnum,
1405           lm_params_req_netshareenum,
1406           NULL,
1407           NULL,
1408           lm_null,
1409           lm_null,
1410           lm_params_resp_netshareenum,
1411           "Available Shares",
1412           &ett_lanman_shares,
1413           netshareenum_share_entry,
1414           &ett_lanman_share,
1415           lm_data_resp_netshareenum,
1416           lm_null },
1417
1418         { API_NetShareGetInfo,
1419           lm_params_req_netsharegetinfo,
1420           NULL,
1421           NULL,
1422           lm_null,
1423           lm_null,
1424           lm_params_resp_netsharegetinfo,
1425           NULL,
1426           NULL,
1427           NULL,
1428           NULL,
1429           lm_data_resp_netsharegetinfo,
1430           lm_null },
1431
1432         { API_NetServerGetInfo,
1433           lm_params_req_netservergetinfo,
1434           NULL,
1435           NULL,
1436           lm_null,
1437           lm_null,
1438           lm_params_resp_netservergetinfo,
1439           NULL,
1440           NULL,
1441           NULL,
1442           NULL,
1443           lm_data_serverinfo,
1444           lm_null },
1445
1446         { API_NetUserGetInfo,
1447           lm_params_req_netusergetinfo,
1448           NULL,
1449           NULL,
1450           lm_null,
1451           lm_null,
1452           lm_params_resp_netusergetinfo,
1453           NULL,
1454           NULL,
1455           NULL,
1456           NULL,
1457           lm_data_resp_netusergetinfo,
1458           lm_null },
1459
1460         { API_NetUserGetGroups,
1461           lm_params_req_netusergetgroups,
1462           NULL,
1463           NULL,
1464           lm_null,
1465           lm_null,
1466           lm_params_resp_netusergetgroups,
1467           "Groups",
1468           &ett_lanman_groups,
1469           NULL,
1470           NULL,
1471           lm_data_resp_netusergetgroups,
1472           lm_null },
1473
1474         { API_NetRemoteTOD,
1475           lm_null,
1476           NULL,
1477           NULL,
1478           lm_null,
1479           lm_null,
1480           lm_null,
1481           NULL,
1482           NULL,
1483           NULL,
1484           NULL,
1485           lm_data_resp_netremotetod,
1486           lm_null },
1487
1488         { API_NetServerEnum2,
1489           lm_params_req_netserverenum2,
1490           NULL,
1491           NULL,
1492           lm_null,
1493           lm_null,
1494           lm_params_resp_netserverenum2,
1495           "Servers",
1496           &ett_lanman_servers,
1497           netserverenum2_server_entry,
1498           &ett_lanman_server,
1499           lm_data_serverinfo,
1500           lm_null },
1501
1502         { API_NetWkstaGetInfo,
1503           lm_params_req_netwkstagetinfo,
1504           NULL,
1505           NULL,
1506           lm_null,
1507           lm_null,
1508           lm_params_resp_netwkstagetinfo,
1509           NULL,
1510           NULL,
1511           NULL,
1512           NULL,
1513           lm_data_resp_netwkstagetinfo,
1514           lm_null },
1515
1516         { API_NetWkstaUserLogon,
1517           lm_params_req_netwkstauserlogon,
1518           NULL,
1519           NULL,
1520           lm_null,
1521           lm_null,
1522           lm_params_resp_netwkstauserlogon,
1523           NULL,
1524           NULL,
1525           NULL,
1526           NULL,
1527           lm_data_resp_netwkstauserlogon,
1528           lm_null },
1529
1530         { API_NetWkstaUserLogoff,
1531           lm_params_req_netwkstauserlogoff,
1532           NULL,
1533           NULL,
1534           lm_null,
1535           lm_null,
1536           lm_params_resp_netwkstauserlogoff,
1537           NULL,
1538           NULL,
1539           NULL,
1540           NULL,
1541           lm_data_resp_netwkstauserlogoff,
1542           lm_null },
1543
1544         { API_SamOEMChgPasswordUser2_P,
1545           lm_params_req_samoemchangepassword,
1546           NULL,
1547           NULL,
1548           lm_data_req_samoemchangepassword,
1549           lm_null,
1550           lm_null,
1551           NULL,
1552           NULL,
1553           NULL,
1554           NULL,
1555           lm_null_list,
1556           lm_null },
1557
1558         { API_NetServerEnum3,
1559           lm_params_req_netserverenum3,
1560           NULL,
1561           NULL,
1562           lm_null,
1563           lm_null,
1564           lm_params_resp_netserverenum2,
1565           "Servers",
1566           &ett_lanman_servers,
1567           netserverenum2_server_entry,
1568           &ett_lanman_server,
1569           lm_data_serverinfo,
1570           lm_null },
1571
1572         { -1,
1573           lm_null,
1574           NULL,
1575           NULL,
1576           lm_null,
1577           lm_null,
1578           lm_null,
1579           NULL,
1580           NULL,
1581           NULL,
1582           &ett_lanman_unknown_entry,
1583           lm_null_list,
1584           lm_null }
1585 };
1586
1587 static const struct lanman_desc *
1588 find_lanman(int lanman_num)
1589 {
1590         int i;
1591
1592         for (i = 0; lmd[i].lanman_num != -1; i++) {
1593                 if (lmd[i].lanman_num == lanman_num)
1594                         break;
1595         }
1596         return &lmd[i];
1597 }
1598
1599 static const guchar *
1600 get_count(const guchar *desc, int *countp)
1601 {
1602         int count = 0;
1603         guchar c;
1604
1605         if (!isdigit(*desc)) {
1606                 *countp = 1;    /* no count was supplied */
1607                 return desc;
1608         }
1609
1610         while ((c = *desc) != '\0' && isdigit(c)) {
1611                 count = (count * 10) + c - '0';
1612                 desc++;
1613         }
1614
1615         *countp = count;        /* XXX - what if it's 0? */
1616         return desc;
1617 }
1618
1619 static int
1620 dissect_request_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
1621     proto_tree *tree, const guchar *desc, const item_t *items,
1622     gboolean *has_data_p)
1623 {
1624         guint c;
1625         guint16 WParam;
1626         guint32 LParam;
1627         guint string_len;
1628         int count;
1629
1630         *has_data_p = FALSE;
1631         while ((c = *desc++) != '\0') {
1632                 switch (c) {
1633
1634                 case 'W':
1635                         /*
1636                          * A 16-bit word value in the request.
1637                          */
1638                         if (items->func == NULL) {
1639                                 /*
1640                                  * We've run out of items in the table;
1641                                  * fall back on the default.
1642                                  */
1643                                 offset = add_word_param(tvb, offset, 0, pinfo,
1644                                     tree, 0, -1);
1645                         } else if (items->type != PARAM_WORD) {
1646                                 /*
1647                                  * Descriptor character is 'W', but this
1648                                  * isn't a word parameter.
1649                                  */
1650                                 WParam = tvb_get_letohs(tvb, offset);
1651                                 proto_tree_add_text(tree, tvb, offset, 2,
1652                                     "%s: Value is %u (0x%04X), type is wrong (W)",
1653                                     (*items->hf_index == -1) ?
1654                                       "Word Param" :
1655                                       proto_registrar_get_name(*items->hf_index),
1656                                     WParam, WParam);
1657                                 offset += 2;
1658                                 items++;
1659                         } else {
1660                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1661                                     tree, 0, *items->hf_index);
1662                                 items++;
1663                         }
1664                         break;
1665
1666                 case 'D':
1667                         /*
1668                          * A 32-bit doubleword value in the request.
1669                          */
1670                         if (items->func == NULL) {
1671                                 /*
1672                                  * We've run out of items in the table;
1673                                  * fall back on the default.
1674                                  */
1675                                 offset = add_dword_param(tvb, offset, 0, pinfo,
1676                                     tree, 0, -1);
1677                         } else if (items->type != PARAM_DWORD) {
1678                                 /*
1679                                  * Descriptor character is 'D', but this
1680                                  * isn't a doubleword parameter.
1681                                  */
1682                                 LParam = tvb_get_letohl(tvb, offset);
1683                                 proto_tree_add_text(tree, tvb, offset, 2,
1684                                     "%s: Value is %u (0x%08X), type is wrong (D)",
1685                                     (*items->hf_index == -1) ?
1686                                       "Doubleword Param" :
1687                                       proto_registrar_get_name(*items->hf_index),
1688                                     LParam, LParam);
1689                                 offset += 4;
1690                                 items++;
1691                         } else {
1692                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1693                                     tree, 0, *items->hf_index);
1694                                 items++;
1695                         }
1696                         break;
1697
1698                 case 'b':
1699                         /*
1700                          * A byte or multi-byte value in the request.
1701                          */
1702                         desc = get_count(desc, &count);
1703                         if (items->func == NULL) {
1704                                 /*
1705                                  * We've run out of items in the table;
1706                                  * fall back on the default.
1707                                  */
1708                                 offset = add_byte_param(tvb, offset, count,
1709                                     pinfo, tree, 0, -1);
1710                         } else if (items->type != PARAM_BYTES) {
1711                                 /*
1712                                  * Descriptor character is 'b', but this
1713                                  * isn't a byte/bytes parameter.
1714                                  */
1715                                 proto_tree_add_text(tree, tvb, offset, count,
1716                                     "%s: Value is %s, type is wrong (b)",
1717                                     (*items->hf_index == -1) ?
1718                                       "Byte Param" :
1719                                       proto_registrar_get_name(*items->hf_index),
1720                                     tvb_bytes_to_str(tvb, offset, count));
1721                                 offset += count;
1722                                 items++;
1723                         } else {
1724                                 offset = (*items->func)(tvb, offset, count,
1725                                     pinfo, tree, 0, *items->hf_index);
1726                                 items++;
1727                         }
1728                         break;
1729
1730                 case 'O':
1731                         /*
1732                          * A null pointer.
1733                          */
1734                         if (items->func == NULL) {
1735                                 /*
1736                                  * We've run out of items in the table;
1737                                  * fall back on the default.
1738                                  */
1739                                 add_null_pointer_param(tvb, offset, 0,
1740                                     pinfo, tree, 0, -1);
1741                         } else {
1742                                 /*
1743                                  * If "*items->hf_index" is -1, this is
1744                                  * a reserved must-be-null field; don't
1745                                  * clutter the protocol tree by putting
1746                                  * it in.
1747                                  */
1748                                 if (*items->hf_index != -1) {
1749                                         add_null_pointer_param(tvb,
1750                                             offset, 0, pinfo, tree, 0,
1751                                             *items->hf_index);
1752                                 }
1753                                 items++;
1754                         }
1755                         break;
1756
1757                 case 'z':
1758                         /*
1759                          * A null-terminated ASCII string.
1760                          */
1761                         if (items->func == NULL) {
1762                                 /*
1763                                  * We've run out of items in the table;
1764                                  * fall back on the default.
1765                                  */
1766                                 offset = add_string_param(tvb, offset, 0,
1767                                     pinfo, tree, 0, -1);
1768                         } else if (items->type != PARAM_STRINGZ) {
1769                                 /*
1770                                  * Descriptor character is 'z', but this
1771                                  * isn't a string parameter.
1772                                  */
1773                                 string_len = tvb_strsize(tvb, offset);
1774                                 proto_tree_add_text(tree, tvb, offset, string_len,
1775                                     "%s: Value is %s, type is wrong (z)",
1776                                     (*items->hf_index == -1) ?
1777                                       "String Param" :
1778                                       proto_registrar_get_name(*items->hf_index),
1779                                     tvb_format_text(tvb, offset, string_len));
1780                                 offset += string_len;
1781                                 items++;
1782                         } else {
1783                                 offset = (*items->func)(tvb, offset, 0,
1784                                     pinfo, tree, 0, *items->hf_index);
1785                                 items++;
1786                         }
1787                         break;
1788
1789                 case 'F':
1790                         /*
1791                          * One or more pad bytes.
1792                          */
1793                         desc = get_count(desc, &count);
1794                         proto_tree_add_text(tree, tvb, offset, count,
1795                             "%s", "Padding");
1796                         offset += count;
1797                         break;
1798
1799                 case 'L':
1800                         /*
1801                          * 16-bit receive buffer length.
1802                          */
1803                         proto_tree_add_item(tree, hf_recv_buf_len, tvb,
1804                             offset, 2, TRUE);
1805                         offset += 2;
1806                         break;
1807
1808                 case 's':
1809                         /*
1810                          * 32-bit send buffer offset.
1811                          * This appears not to be sent over the wire.
1812                          */
1813                         *has_data_p = TRUE;
1814                         break;
1815
1816                 case 'T':
1817                         /*
1818                          * 16-bit send buffer length.
1819                          */
1820                         proto_tree_add_item(tree, hf_send_buf_len, tvb,
1821                             offset, 2, TRUE);
1822                         offset += 2;
1823                         break;
1824
1825                 default:
1826                         break;
1827                 }
1828         }
1829         return offset;
1830 }
1831
1832 static int
1833 dissect_response_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
1834     proto_tree *tree, const guchar *desc, const item_t *items,
1835     gboolean *has_data_p, gboolean *has_ent_count_p, guint16 *ent_count_p)
1836 {
1837         guint c;
1838         guint16 WParam;
1839         guint32 LParam;
1840         int count;
1841
1842         *has_data_p = FALSE;
1843         *has_ent_count_p = FALSE;
1844         while ((c = *desc++) != '\0') {
1845                 switch (c) {
1846
1847                 case 'r':
1848                         /*
1849                          * 32-bit receive buffer offset.
1850                          */
1851                         *has_data_p = TRUE;
1852                         break;
1853
1854                 case 'g':
1855                         /*
1856                          * A byte or series of bytes is returned.
1857                          */
1858                         desc = get_count(desc, &count);
1859                         if (items->func == NULL) {
1860                                 /*
1861                                  * We've run out of items in the table;
1862                                  * fall back on the default.
1863                                  */
1864                                 offset = add_byte_param(tvb, offset, count,
1865                                     pinfo, tree, 0, -1);
1866                         } else if (items->type != PARAM_BYTES) {
1867                                 /*
1868                                  * Descriptor character is 'b', but this
1869                                  * isn't a byte/bytes parameter.
1870                                  */
1871                                 proto_tree_add_text(tree, tvb, offset, count,
1872                                     "%s: Value is %s, type is wrong (g)",
1873                                     (*items->hf_index == -1) ?
1874                                       "Byte Param" :
1875                                       proto_registrar_get_name(*items->hf_index),
1876                                     tvb_bytes_to_str(tvb, offset, count));
1877                                 offset += count;
1878                                 items++;
1879                         } else {
1880                                 offset = (*items->func)(tvb, offset, count,
1881                                     pinfo, tree, 0, *items->hf_index);
1882                                 items++;
1883                         }
1884                         break;
1885
1886                 case 'h':
1887                         /*
1888                          * A 16-bit word is received.
1889                          */
1890                         if (items->func == NULL) {
1891                                 /*
1892                                  * We've run out of items in the table;
1893                                  * fall back on the default.
1894                                  */
1895                                 offset = add_word_param(tvb, offset, 0, pinfo,
1896                                     tree, 0, -1);
1897                         } else if (items->type != PARAM_WORD) {
1898                                 /*
1899                                  * Descriptor character is 'h', but this
1900                                  * isn't a word parameter.
1901                                  */
1902                                 WParam = tvb_get_letohs(tvb, offset);
1903                                 proto_tree_add_text(tree, tvb, offset, 2,
1904                                     "%s: Value is %u (0x%04X), type is wrong (W)",
1905                                     (*items->hf_index == -1) ?
1906                                       "Word Param" :
1907                                       proto_registrar_get_name(*items->hf_index),
1908                                     WParam, WParam);
1909                                 offset += 2;
1910                                 items++;
1911                         } else {
1912                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1913                                     tree, 0, *items->hf_index);
1914                                 items++;
1915                         }
1916                         break;
1917
1918                 case 'i':
1919                         /*
1920                          * A 32-bit doubleword is received.
1921                          */
1922                         if (items->func == NULL) {
1923                                 /*
1924                                  * We've run out of items in the table;
1925                                  * fall back on the default.
1926                                  */
1927                                 offset = add_dword_param(tvb, offset, 0, pinfo,
1928                                     tree, 0, -1);
1929                         } else if (items->type != PARAM_DWORD) {
1930                                 /*
1931                                  * Descriptor character is 'i', but this
1932                                  * isn't a doubleword parameter.
1933                                  */
1934                                 LParam = tvb_get_letohl(tvb, offset);
1935                                 proto_tree_add_text(tree, tvb, offset, 2,
1936                                     "%s: Value is %u (0x%08X), type is wrong (i)",
1937                                     (*items->hf_index == -1) ?
1938                                       "Doubleword Param" :
1939                                       proto_registrar_get_name(*items->hf_index),
1940                                     LParam, LParam);
1941                                 offset += 4;
1942                                 items++;
1943                         } else {
1944                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1945                                     tree, 0, *items->hf_index);
1946                                 items++;
1947                         }
1948                         break;
1949
1950                 case 'e':
1951                         /*
1952                          * A 16-bit entry count is returned.
1953                          */
1954                         WParam = tvb_get_letohs(tvb, offset);
1955                         proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2,
1956                             WParam);
1957                         offset += 2;
1958                         *has_ent_count_p = TRUE;
1959                         *ent_count_p = WParam;  /* Save this for later retrieval */
1960                         break;
1961
1962                 default:
1963                         break;
1964                 }
1965         }
1966         return offset;
1967 }
1968
1969 static int
1970 dissect_transact_data(tvbuff_t *tvb, int offset, int convert,
1971     packet_info *pinfo, proto_tree *tree, const guchar *desc,
1972     const item_t *items, guint16 *aux_count_p)
1973 {
1974         guint c;
1975         guint16 WParam;
1976         guint32 LParam;
1977         int count;
1978         int cptr;
1979         const char *string;
1980         gint string_len;
1981
1982         if (aux_count_p != NULL)
1983                 *aux_count_p = 0;
1984
1985         while ((c = *desc++) != '\0') {
1986                 switch (c) {
1987
1988                 case 'W':
1989                         /*
1990                          * A 16-bit word value.
1991                          * XXX - handle the count?
1992                          */
1993                         desc = get_count(desc, &count);
1994                         if (items->func == NULL) {
1995                                 /*
1996                                  * We've run out of items in the table;
1997                                  * fall back on the default.
1998                                  */
1999                                 offset = add_word_param(tvb, offset, 0, pinfo,
2000                                     tree, convert, -1);
2001                         } else if (items->type != PARAM_WORD) {
2002                                 /*
2003                                  * Descriptor character is 'W', but this
2004                                  * isn't a word parameter.
2005                                  */
2006                                 WParam = tvb_get_letohs(tvb, offset);
2007                                 proto_tree_add_text(tree, tvb, offset, 2,
2008                                     "%s: Value is %u (0x%04X), type is wrong (W)",
2009                                     (*items->hf_index == -1) ?
2010                                       "Word Param" :
2011                                       proto_registrar_get_name(*items->hf_index),
2012                                     WParam, WParam);
2013                                 offset += 2;
2014                                 items++;
2015                         } else {
2016                                 offset = (*items->func)(tvb, offset, 0, pinfo,
2017                                     tree, convert, *items->hf_index);
2018                                 items++;
2019                         }
2020                         break;
2021
2022                 case 'D':
2023                         /*
2024                          * A 32-bit doubleword value.
2025                          * XXX - handle the count?
2026                          */
2027                         desc = get_count(desc, &count);
2028                         if (items->func == NULL) {
2029                                 /*
2030                                  * We've run out of items in the table;
2031                                  * fall back on the default.
2032                                  */
2033                                 offset = add_dword_param(tvb, offset, 0, pinfo,
2034                                     tree, convert, -1);
2035                         } else if (items->type != PARAM_DWORD) {
2036                                 /*
2037                                  * Descriptor character is 'D', but this
2038                                  * isn't a doubleword parameter.
2039                                  */
2040                                 LParam = tvb_get_letohl(tvb, offset);
2041                                 proto_tree_add_text(tree, tvb, offset, 2,
2042                                     "%s: Value is %u (0x%08X), type is wrong (D)",
2043                                     (*items->hf_index == -1) ?
2044                                       "Doubleword Param" :
2045                                       proto_registrar_get_name(*items->hf_index),
2046                                     LParam, LParam);
2047                                 offset += 4;
2048                                 items++;
2049                         } else {
2050                                 offset = (*items->func)(tvb, offset, 0, pinfo,
2051                                     tree, convert, *items->hf_index);
2052                                 items++;
2053                         }
2054                         break;
2055
2056                 case 'B':
2057                         /*
2058                          * A byte or multi-byte value.
2059                          */
2060                         desc = get_count(desc, &count);
2061                         if (items->func == NULL) {
2062                                 /*
2063                                  * We've run out of items in the table;
2064                                  * fall back on the default.
2065                                  */
2066                                 offset = add_byte_param(tvb, offset, count,
2067                                     pinfo, tree, convert, -1);
2068                         } else if (items->type != PARAM_BYTES) {
2069                                 /*
2070                                  * Descriptor character is 'B', but this
2071                                  * isn't a byte/bytes parameter.
2072                                  */
2073                                 proto_tree_add_text(tree, tvb, offset, count,
2074                                     "%s: Value is %s, type is wrong (B)",
2075                                     (*items->hf_index == -1) ?
2076                                       "Byte Param" :
2077                                       proto_registrar_get_name(*items->hf_index),
2078                                     tvb_bytes_to_str(tvb, offset, count));
2079                                 offset += count;
2080                                 items++;
2081                         } else {
2082                                 offset = (*items->func)(tvb, offset, count,
2083                                     pinfo, tree, convert, *items->hf_index);
2084                                 items++;
2085                         }
2086                         break;
2087
2088                 case 'O':
2089                         /*
2090                          * A null pointer.
2091                          */
2092                         if (items->func == NULL) {
2093                                 /*
2094                                  * We've run out of items in the table;
2095                                  * fall back on the default.
2096                                  */
2097                                 add_null_pointer_param(tvb, offset, 0,
2098                                     pinfo, tree, convert, -1);
2099                         } else {
2100                                 /*
2101                                  * If "*items->hf_index" is -1, this is
2102                                  * a reserved must-be-null field; don't
2103                                  * clutter the protocol tree by putting
2104                                  * it in.
2105                                  */
2106                                 if (*items->hf_index != -1) {
2107                                         add_null_pointer_param(tvb,
2108                                             offset, 0, pinfo, tree, convert,
2109                                             *items->hf_index);
2110                                 }
2111                                 items++;
2112                         }
2113                         break;
2114
2115                 case 'z':
2116                         /*
2117                          * A pointer to a null-terminated ASCII string.
2118                          */
2119                         if (items->func == NULL) {
2120                                 /*
2121                                  * We've run out of items in the table;
2122                                  * fall back on the default.
2123                                  */
2124                                 offset = add_stringz_pointer_param(tvb, offset,
2125                                     0, pinfo, tree, convert, -1);
2126                         } else if (items->type != PARAM_STRINGZ) {
2127                                 /*
2128                                  * Descriptor character is 'z', but this
2129                                  * isn't a string parameter.
2130                                  */
2131                                 string = get_stringz_pointer_value(tvb, offset,
2132                                     convert, &cptr, &string_len);
2133                                 offset += 4;
2134                                 proto_tree_add_text(tree, tvb, cptr, string_len,
2135                                     "%s: Value is %s, type is wrong (z)",
2136                                     (*items->hf_index == -1) ?
2137                                       "String Param" :
2138                                       proto_registrar_get_name(*items->hf_index),
2139                                     string);
2140                                 items++;
2141                         } else {
2142                                 offset = (*items->func)(tvb, offset, 0,
2143                                     pinfo, tree, convert, *items->hf_index);
2144                                 items++;
2145                         }
2146                         break;
2147
2148                 case 'b':
2149                         /*
2150                          * A pointer to a byte or multi-byte value.
2151                          */
2152                         desc = get_count(desc, &count);
2153                         if (items->func == NULL) {
2154                                 /*
2155                                  * We've run out of items in the table;
2156                                  * fall back on the default.
2157                                  */
2158                                 offset = add_bytes_pointer_param(tvb, offset,
2159                                     count, pinfo, tree, convert, -1);
2160                         } else if (items->type != PARAM_BYTES) {
2161                                 /*
2162                                  * Descriptor character is 'b', but this
2163                                  * isn't a byte/bytes parameter.
2164                                  */
2165                                 cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
2166                                 offset += 4;
2167                                 proto_tree_add_text(tree, tvb, offset, count,
2168                                     "%s: Value is %s, type is wrong (b)",
2169                                     (*items->hf_index == -1) ?
2170                                       "Byte Param" :
2171                                       proto_registrar_get_name(*items->hf_index),
2172                                     tvb_bytes_to_str(tvb, cptr, count));
2173                                 items++;
2174                         } else {
2175                                 offset = (*items->func)(tvb, offset, count,
2176                                     pinfo, tree, convert, *items->hf_index);
2177                                 items++;
2178                         }
2179                         break;
2180
2181                 case 'N':
2182                         /*
2183                          * 16-bit auxiliary data structure count.
2184                          * XXX - hf_acount?
2185                          */
2186                         WParam = tvb_get_letohs(tvb, offset);
2187                         proto_tree_add_text(tree, tvb, offset, 2,
2188                             "%s: %u (0x%04X)",
2189                             "Auxiliary data structure count",
2190                             WParam, WParam);
2191                         offset += 2;
2192                         if (aux_count_p != NULL)
2193                                 *aux_count_p = WParam;  /* Save this for later retrieval */
2194                         break;
2195
2196                 default:
2197                         break;
2198                 }
2199         }
2200         return offset;
2201 }
2202
2203 static const value_string commands[] = {
2204         {API_NetShareEnum,                      "NetShareEnum"},
2205         {API_NetShareGetInfo,                   "NetShareGetInfo"},
2206         {API_NetShareSetInfo,                   "NetShareSetInfo"},
2207         {API_NetShareAdd,                       "NetShareAdd"},
2208         {API_NetShareDel,                       "NetShareDel"},
2209         {API_NetShareCheck,                     "NetShareCheck"},
2210         {API_NetSessionEnum,                    "NetSessionEnum"},
2211         {API_NetSessionGetInfo,                 "NetSessionGetInfo"},
2212         {API_NetSessionDel,                     "NetSessionDel"},
2213         {API_WconnectionEnum,                   "NetConnectionEnum"},
2214         {API_NetFileEnum,                       "NetFileEnum"},
2215         {API_NetFileGetInfo,                    "NetFileGetInfo"},
2216         {API_NetFileClose,                      "NetFileClose"},
2217         {API_NetServerGetInfo,                  "NetServerGetInfo"},
2218         {API_NetServerSetInfo,                  "NetServerSetInfo"},
2219         {API_NetServerDiskEnum,                 "NetServerDiskEnum"},
2220         {API_NetServerAdminCommand,             "NetServerAdminCommand"},
2221         {API_NetAuditOpen,                      "NetAuditOpen"},
2222         {API_NetAuditClear,                     "NetAuditClear"},
2223         {API_NetErrorLogOpen,                   "NetErrorLogOpen"},
2224         {API_NetErrorLogClear,                  "NetErrorLogClear"},
2225         {API_NetCharDevEnum,                    "NetCharDevEnum"},
2226         {API_NetCharDevGetInfo,                 "NetCharDevGetInfo"},
2227         {API_NetCharDevControl,                 "NetCharDevControl"},
2228         {API_NetCharDevQEnum,                   "NetCharDevQEnum"},
2229         {API_NetCharDevQGetInfo,                "NetCharDevQGetInfo"},
2230         {API_NetCharDevQSetInfo,                "NetCharDevQSetInfo"},
2231         {API_NetCharDevQPurge,                  "NetCharDevQPurge"},
2232         {API_NetCharDevQPurgeSelf,              "NetCharDevQPurgeSelf"},
2233         {API_NetMessageNameEnum,                "NetMessageNameEnum"},
2234         {API_NetMessageNameGetInfo,             "NetMessageNameGetInfo"},
2235         {API_NetMessageNameAdd,                 "NetMessageNameAdd"},
2236         {API_NetMessageNameDel,                 "NetMessageNameDel"},
2237         {API_NetMessageNameFwd,                 "NetMessageNameFwd"},
2238         {API_NetMessageNameUnFwd,               "NetMessageNameUnFwd"},
2239         {API_NetMessageBufferSend,              "NetMessageBufferSend"},
2240         {API_NetMessageFileSend,                "NetMessageFileSend"},
2241         {API_NetMessageLogFileSet,              "NetMessageLogFileSet"},
2242         {API_NetMessageLogFileGet,              "NetMessageLogFileGet"},
2243         {API_NetServiceEnum,                    "NetServiceEnum"},
2244         {API_NetServiceInstall,                 "NetServiceInstall"},
2245         {API_NetServiceControl,                 "NetServiceControl"},
2246         {API_NetAccessEnum,                     "NetAccessEnum"},
2247         {API_NetAccessGetInfo,                  "NetAccessGetInfo"},
2248         {API_NetAccessSetInfo,                  "NetAccessSetInfo"},
2249         {API_NetAccessAdd,                      "NetAccessAdd"},
2250         {API_NetAccessDel,                      "NetAccessDel"},
2251         {API_NetGroupEnum,                      "NetGroupEnum"},
2252         {API_NetGroupAdd,                       "NetGroupAdd"},
2253         {API_NetGroupDel,                       "NetGroupDel"},
2254         {API_NetGroupAddUser,                   "NetGroupAddUser"},
2255         {API_NetGroupDelUser,                   "NetGroupDelUser"},
2256         {API_NetGroupGetUsers,                  "NetGroupGetUsers"},
2257         {API_NetUserEnum,                       "NetUserEnum"},
2258         {API_NetUserAdd,                        "NetUserAdd"},
2259         {API_NetUserDel,                        "NetUserDel"},
2260         {API_NetUserGetInfo,                    "NetUserGetInfo"},
2261         {API_NetUserSetInfo,                    "NetUserSetInfo"},
2262         {API_NetUserPasswordSet,                "NetUserPasswordSet"},
2263         {API_NetUserGetGroups,                  "NetUserGetGroups"},
2264         {API_NetWkstaSetUID,                    "NetWkstaSetUID"},
2265         {API_NetWkstaGetInfo,                   "NetWkstaGetInfo"},
2266         {API_NetWkstaSetInfo,                   "NetWkstaSetInfo"},
2267         {API_NetUseEnum,                        "NetUseEnum"},
2268         {API_NetUseAdd,                         "NetUseAdd"},
2269         {API_NetUseDel,                         "NetUseDel"},
2270         {API_NetUseGetInfo,                     "NetUseGetInfo"},
2271         {API_WPrintQEnum,                       "WPrintQEnum"},
2272         {API_WPrintQGetInfo,                    "WPrintQGetInfo"},
2273         {API_WPrintQSetInfo,                    "WPrintQSetInfo"},
2274         {API_WPrintQAdd,                        "WPrintQAdd"},
2275         {API_WPrintQDel,                        "WPrintQDel"},
2276         {API_WPrintQPause,                      "WPrintQPause"},
2277         {API_WPrintQContinue,                   "WPrintQContinue"},
2278         {API_WPrintJobEnum,                     "WPrintJobEnum"},
2279         {API_WPrintJobGetInfo,                  "WPrintJobGetInfo"},
2280         {API_WPrintJobSetInfo_OLD,              "WPrintJobSetInfo_OLD"},
2281         {API_WPrintJobDel,                      "WPrintJobDel"},
2282         {API_WPrintJobPause,                    "WPrintJobPause"},
2283         {API_WPrintJobContinue,                 "WPrintJobContinue"},
2284         {API_WPrintDestEnum,                    "WPrintDestEnum"},
2285         {API_WPrintDestGetInfo,                 "WPrintDestGetInfo"},
2286         {API_WPrintDestControl,                 "WPrintDestControl"},
2287         {API_NetProfileSave,                    "NetProfileSave"},
2288         {API_NetProfileLoad,                    "NetProfileLoad"},
2289         {API_NetStatisticsGet,                  "NetStatisticsGet"},
2290         {API_NetStatisticsClear,                "NetStatisticsClear"},
2291         {API_NetRemoteTOD,                      "NetRemoteTOD"},
2292         {API_WNetBiosEnum,                      "WNetBiosEnum"},
2293         {API_WNetBiosGetInfo,                   "WNetBiosGetInfo"},
2294         {API_NetServerEnum,                     "NetServerEnum"},
2295         {API_I_NetServerEnum,                   "I_NetServerEnum"},
2296         {API_NetServiceGetInfo,                 "NetServiceGetInfo"},
2297         {API_WPrintQPurge,                      "WPrintQPurge"},
2298         {API_NetServerEnum2,                    "NetServerEnum2"},
2299         {API_NetAccessGetUserPerms,             "NetAccessGetUserPerms"},
2300         {API_NetGroupGetInfo,                   "NetGroupGetInfo"},
2301         {API_NetGroupSetInfo,                   "NetGroupSetInfo"},
2302         {API_NetGroupSetUsers,                  "NetGroupSetUsers"},
2303         {API_NetUserSetGroups,                  "NetUserSetGroups"},
2304         {API_NetUserModalsGet,                  "NetUserModalsGet"},
2305         {API_NetUserModalsSet,                  "NetUserModalsSet"},
2306         {API_NetFileEnum2,                      "NetFileEnum2"},
2307         {API_NetUserAdd2,                       "NetUserAdd2"},
2308         {API_NetUserSetInfo2,                   "NetUserSetInfo2"},
2309         {API_NetUserPasswordSet2,               "SetUserPassword"},
2310         {API_I_NetServerEnum2,                  "I_NetServerEnum2"},
2311         {API_NetConfigGet2,                     "NetConfigGet2"},
2312         {API_NetConfigGetAll2,                  "NetConfigGetAll2"},
2313         {API_NetGetDCName,                      "NetGetDCName"},
2314         {API_NetHandleGetInfo,                  "NetHandleGetInfo"},
2315         {API_NetHandleSetInfo,                  "NetHandleSetInfo"},
2316         {API_NetStatisticsGet2,                 "NetStatisticsGet2"},
2317         {API_WBuildGetInfo,                     "WBuildGetInfo"},
2318         {API_NetFileGetInfo2,                   "NetFileGetInfo2"},
2319         {API_NetFileClose2,                     "NetFileClose2"},
2320         {API_NetServerReqChallenge,             "NetServerReqChallenge"},
2321         {API_NetServerAuthenticate,             "NetServerAuthenticate"},
2322         {API_NetServerPasswordSet,              "NetServerPasswordSet"},
2323         {API_WNetAccountDeltas,                 "WNetAccountDeltas"},
2324         {API_WNetAccountSync,                   "WNetAccountSync"},
2325         {API_NetUserEnum2,                      "NetUserEnum2"},
2326         {API_NetWkstaUserLogon,                 "NetWkstaUserLogon"},
2327         {API_NetWkstaUserLogoff,                "NetWkstaUserLogoff"},
2328         {API_NetLogonEnum,                      "NetLogonEnum"},
2329         {API_NetErrorLogRead,                   "NetErrorLogRead"},
2330         {API_I_NetPathType,                     "I_NetPathType"},
2331         {API_I_NetPathCanonicalize,             "I_NetPathCanonicalize"},
2332         {API_I_NetPathCompare,                  "I_NetPathCompare"},
2333         {API_I_NetNameValidate,                 "I_NetNameValidate"},
2334         {API_I_NetNameCanonicalize,             "I_NetNameCanonicalize"},
2335         {API_I_NetNameCompare,                  "I_NetNameCompare"},
2336         {API_NetAuditRead,                      "NetAuditRead"},
2337         {API_WPrintDestAdd,                     "WPrintDestAdd"},
2338         {API_WPrintDestSetInfo,                 "WPrintDestSetInfo"},
2339         {API_WPrintDestDel,                     "WPrintDestDel"},
2340         {API_NetUserValidate2,                  "NetUserValidate2"},
2341         {API_WPrintJobSetInfo,                  "WPrintJobSetInfo"},
2342         {API_TI_NetServerDiskEnum,              "TI_NetServerDiskEnum"},
2343         {API_TI_NetServerDiskGetInfo,           "TI_NetServerDiskGetInfo"},
2344         {API_TI_FTVerifyMirror,                 "TI_FTVerifyMirror"},
2345         {API_TI_FTAbortVerify,                  "TI_FTAbortVerify"},
2346         {API_TI_FTGetInfo,                      "TI_FTGetInfo"},
2347         {API_TI_FTSetInfo,                      "TI_FTSetInfo"},
2348         {API_TI_FTLockDisk,                     "TI_FTLockDisk"},
2349         {API_TI_FTFixError,                     "TI_FTFixError"},
2350         {API_TI_FTAbortFix,                     "TI_FTAbortFix"},
2351         {API_TI_FTDiagnoseError,                "TI_FTDiagnoseError"},
2352         {API_TI_FTGetDriveStats,                "TI_FTGetDriveStats"},
2353         {API_TI_FTErrorGetInfo,                 "TI_FTErrorGetInfo"},
2354         {API_NetAccessCheck,                    "NetAccessCheck"},
2355         {API_NetAlertRaise,                     "NetAlertRaise"},
2356         {API_NetAlertStart,                     "NetAlertStart"},
2357         {API_NetAlertStop,                      "NetAlertStop"},
2358         {API_NetAuditWrite,                     "NetAuditWrite"},
2359         {API_NetIRemoteAPI,                     "NetIRemoteAPI"},
2360         {API_NetServiceStatus,                  "NetServiceStatus"},
2361         {API_I_NetServerRegister,               "I_NetServerRegister"},
2362         {API_I_NetServerDeregister,             "I_NetServerDeregister"},
2363         {API_I_NetSessionEntryMake,             "I_NetSessionEntryMake"},
2364         {API_I_NetSessionEntryClear,            "I_NetSessionEntryClear"},
2365         {API_I_NetSessionEntryGetInfo,          "I_NetSessionEntryGetInfo"},
2366         {API_I_NetSessionEntrySetInfo,          "I_NetSessionEntrySetInfo"},
2367         {API_I_NetConnectionEntryMake,          "I_NetConnectionEntryMake"},
2368         {API_I_NetConnectionEntryClear,         "I_NetConnectionEntryClear"},
2369         {API_I_NetConnectionEntrySetInfo,       "I_NetConnectionEntrySetInfo"},
2370         {API_I_NetConnectionEntryGetInfo,       "I_NetConnectionEntryGetInfo"},
2371         {API_I_NetFileEntryMake,                "I_NetFileEntryMake"},
2372         {API_I_NetFileEntryClear,               "I_NetFileEntryClear"},
2373         {API_I_NetFileEntrySetInfo,             "I_NetFileEntrySetInfo"},
2374         {API_I_NetFileEntryGetInfo,             "I_NetFileEntryGetInfo"},
2375         {API_AltSrvMessageBufferSend,           "AltSrvMessageBufferSend"},
2376         {API_AltSrvMessageFileSend,             "AltSrvMessageFileSend"},
2377         {API_wI_NetRplWkstaEnum,                "wI_NetRplWkstaEnum"},
2378         {API_wI_NetRplWkstaGetInfo,             "wI_NetRplWkstaGetInfo"},
2379         {API_wI_NetRplWkstaSetInfo,             "wI_NetRplWkstaSetInfo"},
2380         {API_wI_NetRplWkstaAdd,                 "wI_NetRplWkstaAdd"},
2381         {API_wI_NetRplWkstaDel,                 "wI_NetRplWkstaDel"},
2382         {API_wI_NetRplProfileEnum,              "wI_NetRplProfileEnum"},
2383         {API_wI_NetRplProfileGetInfo,           "wI_NetRplProfileGetInfo"},
2384         {API_wI_NetRplProfileSetInfo,           "wI_NetRplProfileSetInfo"},
2385         {API_wI_NetRplProfileAdd,               "wI_NetRplProfileAdd"},
2386         {API_wI_NetRplProfileDel,               "wI_NetRplProfileDel"},
2387         {API_wI_NetRplProfileClone,             "wI_NetRplProfileClone"},
2388         {API_wI_NetRplBaseProfileEnum,          "wI_NetRplBaseProfileEnum"},
2389         {API_WIServerSetInfo,                   "WIServerSetInfo"},
2390         {API_WPrintDriverEnum,                  "WPrintDriverEnum"},
2391         {API_WPrintQProcessorEnum,              "WPrintQProcessorEnum"},
2392         {API_WPrintPortEnum,                    "WPrintPortEnum"},
2393         {API_WNetWriteUpdateLog,                "WNetWriteUpdateLog"},
2394         {API_WNetAccountUpdate,                 "WNetAccountUpdate"},
2395         {API_WNetAccountConfirmUpdate,          "WNetAccountConfirmUpdate"},
2396         {API_NetConfigSet,                      "NetConfigSet"},
2397         {API_WAccountsReplicate,                "WAccountsReplicate"},
2398         {API_SamOEMChgPasswordUser2_P,          "SamOEMChangePassword"},
2399         {API_NetServerEnum3,                    "NetServerEnum3"},
2400         {API_WPrintDriverGetInfo,               "WPrintDriverGetInfo"},
2401         {API_WPrintDriverSetInfo,               "WPrintDriverSetInfo"},
2402         {API_NetAliasAdd,                       "NetAliasAdd"},
2403         {API_NetAliasDel,                       "NetAliasDel"},
2404         {API_NetAliasGetInfo,                   "NetAliasGetInfo"},
2405         {API_NetAliasSetInfo,                   "NetAliasSetInfo"},
2406         {API_NetAliasEnum,                      "NetAliasEnum"},
2407         {API_NetUserGetLogonAsn,                "NetUserGetLogonAsn"},
2408         {API_NetUserSetLogonAsn,                "NetUserSetLogonAsn"},
2409         {API_NetUserGetAppSel,                  "NetUserGetAppSel"},
2410         {API_NetUserSetAppSel,                  "NetUserSetAppSel"},
2411         {API_NetAppAdd,                         "NetAppAdd"},
2412         {API_NetAppDel,                         "NetAppDel"},
2413         {API_NetAppGetInfo,                     "NetAppGetInfo"},
2414         {API_NetAppSetInfo,                     "NetAppSetInfo"},
2415         {API_NetAppEnum,                        "NetAppEnum"},
2416         {API_NetUserDCDBInit,                   "NetUserDCDBInit"},
2417         {API_NetDASDAdd,                        "NetDASDAdd"},
2418         {API_NetDASDDel,                        "NetDASDDel"},
2419         {API_NetDASDGetInfo,                    "NetDASDGetInfo"},
2420         {API_NetDASDSetInfo,                    "NetDASDSetInfo"},
2421         {API_NetDASDEnum,                       "NetDASDEnum"},
2422         {API_NetDASDCheck,                      "NetDASDCheck"},
2423         {API_NetDASDCtl,                        "NetDASDCtl"},
2424         {API_NetUserRemoteLogonCheck,           "NetUserRemoteLogonCheck"},
2425         {API_NetUserPasswordSet3,               "NetUserPasswordSet3"},
2426         {API_NetCreateRIPLMachine,              "NetCreateRIPLMachine"},
2427         {API_NetDeleteRIPLMachine,              "NetDeleteRIPLMachine"},
2428         {API_NetGetRIPLMachineInfo,             "NetGetRIPLMachineInfo"},
2429         {API_NetSetRIPLMachineInfo,             "NetSetRIPLMachineInfo"},
2430         {API_NetEnumRIPLMachine,                "NetEnumRIPLMachine"},
2431         {API_I_ShareAdd,                        "I_ShareAdd"},
2432         {API_I_AliasEnum,                       "I_AliasEnum"},
2433         {API_NetAccessApply,                    "NetAccessApply"},
2434         {API_WPrt16Query,                       "WPrt16Query"},
2435         {API_WPrt16Set,                         "WPrt16Set"},
2436         {API_NetUserDel100,                     "NetUserDel100"},
2437         {API_NetUserRemoteLogonCheck2,          "NetUserRemoteLogonCheck2"},
2438         {API_WRemoteTODSet,                     "WRemoteTODSet"},
2439         {API_WPrintJobMoveAll,                  "WPrintJobMoveAll"},
2440         {API_W16AppParmAdd,                     "W16AppParmAdd"},
2441         {API_W16AppParmDel,                     "W16AppParmDel"},
2442         {API_W16AppParmGet,                     "W16AppParmGet"},
2443         {API_W16AppParmSet,                     "W16AppParmSet"},
2444         {API_W16RIPLMachineCreate,              "W16RIPLMachineCreate"},
2445         {API_W16RIPLMachineGetInfo,             "W16RIPLMachineGetInfo"},
2446         {API_W16RIPLMachineSetInfo,             "W16RIPLMachineSetInfo"},
2447         {API_W16RIPLMachineEnum,                "W16RIPLMachineEnum"},
2448         {API_W16RIPLMachineListParmEnum,        "W16RIPLMachineListParmEnum"},
2449         {API_W16RIPLMachClassGetInfo,           "W16RIPLMachClassGetInfo"},
2450         {API_W16RIPLMachClassEnum,              "W16RIPLMachClassEnum"},
2451         {API_W16RIPLMachClassCreate,            "W16RIPLMachClassCreate"},
2452         {API_W16RIPLMachClassSetInfo,           "W16RIPLMachClassSetInfo"},
2453         {API_W16RIPLMachClassDelete,            "W16RIPLMachClassDelete"},
2454         {API_W16RIPLMachClassLPEnum,            "W16RIPLMachClassLPEnum"},
2455         {API_W16RIPLMachineDelete,              "W16RIPLMachineDelete"},
2456         {API_W16WSLevelGetInfo,                 "W16WSLevelGetInfo"},
2457         {API_NetServerNameAdd,                  "NetServerNameAdd"},
2458         {API_NetServerNameDel,                  "NetServerNameDel"},
2459         {API_NetServerNameEnum,                 "NetServerNameEnum"},
2460         {API_I_WDASDEnum,                       "I_WDASDEnum"},
2461         {API_I_WDASDEnumTerminate,              "I_WDASDEnumTerminate"},
2462         {API_I_WDASDSetInfo2,                   "I_WDASDSetInfo2"},
2463         {0,                                     NULL}
2464 };
2465
2466 static void
2467 dissect_response_data(tvbuff_t *tvb, packet_info *pinfo, int convert,
2468     proto_tree *tree, struct smb_info *smb_info,
2469     const struct lanman_desc *lanman, gboolean has_ent_count,
2470     guint16 ent_count)
2471 {
2472         smb_transact_info_t *trp = NULL;
2473         const item_list_t *resp_data_list;
2474         int offset, start_offset;
2475         const char *label;
2476         gint ett;
2477         const item_t *resp_data;
2478         proto_item *data_item;
2479         proto_tree *data_tree;
2480         proto_item *entry_item;
2481         proto_tree *entry_tree;
2482         guint i, j;
2483         guint16 aux_count;
2484
2485         if (smb_info->sip->extra_info_type == SMB_EI_TRI)
2486                 trp = smb_info->sip->extra_info;
2487
2488         /*
2489          * Find the item table for the matching request's detail level.
2490          */
2491         for (resp_data_list = lanman->resp_data_list;
2492             resp_data_list->level != -1; resp_data_list++) {
2493                 if (resp_data_list->level == trp->info_level)
2494                         break;
2495         }
2496         resp_data = resp_data_list->item_list;
2497
2498         offset = 0;
2499         if (has_ent_count) {
2500                 /*
2501                  * The data is a list of entries; create a protocol tree item
2502                  * for it.
2503                  */
2504                 if (tree) {
2505                         label = lanman->resp_data_entry_list_label;
2506                         if (label == NULL)
2507                                 label = "Entries";
2508                         if (lanman->ett_data_entry_list != NULL)
2509                                 ett = *lanman->ett_data_entry_list;
2510                         else
2511                                 ett = ett_lanman_unknown_entries;
2512                         data_item = proto_tree_add_text(tree, tvb, offset, -1,
2513                             label);
2514                         data_tree = proto_item_add_subtree(data_item, ett);
2515                 } else {
2516                         data_item = NULL;
2517                         data_tree = NULL;
2518                 }
2519         } else {
2520                 /*
2521                  * Just leave it at the top level.
2522                  */
2523                 data_item = NULL;
2524                 data_tree = tree;
2525         }
2526
2527         if (trp->data_descrip == NULL) {
2528                 /*
2529                  * This could happen if we only dissected
2530                  * part of the request to which this is a
2531                  * reply, e.g. if the request was split
2532                  * across TCP segments and we weren't doing
2533                  * TCP desegmentation, or if we had a snapshot
2534                  * length that was too short.
2535                  *
2536                  * We can't dissect the data; just show it as raw data or,
2537                  * if we've already created a top-level item, note that
2538                  * no descriptor is available.
2539                  */
2540                 if (has_ent_count) {
2541                         if (data_item != NULL) {
2542                                 proto_item_append_text(data_item,
2543                                     " (No descriptor available)");
2544                         }
2545                 } else {
2546                         proto_tree_add_text(data_tree, tvb, offset, -1,
2547                             "Data (no descriptor available)");
2548                 }
2549                 offset += tvb_length_remaining(tvb, offset);
2550         } else {
2551                 /*
2552                  * If we have an entry count, show all the entries,
2553                  * with each one having a protocol tree item.
2554                  *
2555                  * Otherwise, we just show one returned item, with
2556                  * no protocol tree item.
2557                  */
2558                 if (!has_ent_count)
2559                         ent_count = 1;
2560                 for (i = 0; i < ent_count; i++) {
2561                         start_offset = offset;
2562                         if (has_ent_count &&
2563                             lanman->resp_data_element_item != NULL) {
2564                                 /*
2565                                  * Create a protocol tree item for the
2566                                  * entry.
2567                                  */
2568                                 entry_item =
2569                                     (*lanman->resp_data_element_item)
2570                                       (tvb, data_tree, offset);
2571                                 entry_tree = proto_item_add_subtree(
2572                                     entry_item,
2573                                     *lanman->ett_resp_data_element_item);
2574                         } else {
2575                                 /*
2576                                  * Just leave it at the current
2577                                  * level.
2578                                  */
2579                                 entry_item = NULL;
2580                                 entry_tree = data_tree;
2581                         }
2582
2583                         offset = dissect_transact_data(tvb, offset,
2584                             convert, pinfo, entry_tree,
2585                             trp->data_descrip, resp_data, &aux_count);
2586
2587                         /* auxiliary data */
2588                         if (trp->aux_data_descrip != NULL) {
2589                                 for (j = 0; j < aux_count; j++) {
2590                                         offset = dissect_transact_data(
2591                                             tvb, offset, convert,
2592                                             pinfo, entry_tree,
2593                                             trp->data_descrip,
2594                                             lanman->resp_aux_data, NULL);
2595                                 }
2596                         }
2597
2598                         if (entry_item != NULL) {
2599                                 /*
2600                                  * Set the length of the protocol tree
2601                                  * item for the entry.
2602                                  */
2603                                 proto_item_set_len(entry_item,
2604                                     offset - start_offset);
2605                         }
2606                 }
2607         }
2608
2609         if (data_item != NULL) {
2610                 /*
2611                  * Set the length of the protocol tree item
2612                  * for the data.
2613                  */
2614                 proto_item_set_len(data_item, offset);
2615         }
2616 }
2617
2618 static gboolean
2619 dissect_pipe_lanman(tvbuff_t *pd_tvb, tvbuff_t *p_tvb, tvbuff_t *d_tvb,
2620                     packet_info *pinfo, proto_tree *parent_tree)
2621 {
2622         smb_info_t *smb_info = pinfo->private_data;
2623         smb_transact_info_t *trp = NULL;
2624         int offset = 0, start_offset;
2625         guint16 cmd;
2626         guint16 status;
2627         int convert;
2628         const struct lanman_desc *lanman;
2629         proto_item *item = NULL;
2630         proto_tree *tree = NULL;
2631         guint descriptor_len;
2632         const gchar *param_descrip, *data_descrip, *aux_data_descrip = NULL;
2633         gboolean has_data;
2634         gboolean has_ent_count;
2635         guint16 ent_count, aux_count;
2636         guint i;
2637         proto_item *data_item;
2638         proto_tree *data_tree;
2639
2640         if (smb_info->sip->extra_info_type == SMB_EI_TRI)
2641                 trp = smb_info->sip->extra_info;
2642
2643         if (!proto_is_protocol_enabled(find_protocol_by_id(proto_smb_lanman)))
2644                 return FALSE;
2645         if (p_tvb == NULL) {
2646                 /*
2647                  * Requests must have parameters.
2648                  */
2649                 return FALSE;
2650         }
2651         pinfo->current_proto = "LANMAN";
2652
2653         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2654                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LANMAN");
2655         }
2656
2657         if (parent_tree) {
2658                 item = proto_tree_add_item(parent_tree, proto_smb_lanman,
2659                         pd_tvb, 0, -1, FALSE);
2660                 tree = proto_item_add_subtree(item, ett_lanman);
2661         }
2662
2663         if (smb_info->request) { /* this is a request */
2664                 /* function code */
2665                 cmd = tvb_get_letohs(p_tvb, offset);
2666                 if (check_col(pinfo->cinfo, COL_INFO)) {
2667                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s Request", val_to_str(cmd, commands, "Unknown Command (%u)"));
2668                 }
2669                 proto_tree_add_uint(tree, hf_function_code, p_tvb, offset, 2,
2670                     cmd);
2671                 offset += 2;
2672
2673                 /*
2674                  * If we haven't already done so, save the function code in
2675                  * the structure we were handed, so that it's available to
2676                  * the code parsing the reply, and initialize the detail
2677                  * level to -1, meaning "unknown".
2678                  */
2679                 if (!pinfo->fd->flags.visited) {
2680                         trp->lanman_cmd = cmd;
2681                         trp->info_level = -1;
2682                         trp->param_descrip=NULL;
2683                         trp->data_descrip=NULL;
2684                         trp->aux_data_descrip=NULL;
2685                 }
2686
2687                 /* parameter descriptor */
2688                 descriptor_len = tvb_strsize(p_tvb, offset);
2689                 proto_tree_add_item(tree, hf_param_desc, p_tvb, offset,
2690                     descriptor_len, TRUE);
2691                 param_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2692                 if (!pinfo->fd->flags.visited) {
2693                         /*
2694                          * Save the parameter descriptor for future use.
2695                          */
2696                         DISSECTOR_ASSERT(trp->param_descrip == NULL);
2697                         trp->param_descrip = g_strdup(param_descrip);
2698                 }
2699                 offset += descriptor_len;
2700
2701                 /* return descriptor */
2702                 descriptor_len = tvb_strsize(p_tvb, offset);
2703                 proto_tree_add_item(tree, hf_return_desc, p_tvb, offset,
2704                     descriptor_len, TRUE);
2705                 data_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2706                 if (!pinfo->fd->flags.visited) {
2707                         /*
2708                          * Save the return descriptor for future use.
2709                          */
2710                         DISSECTOR_ASSERT(trp->data_descrip == NULL);
2711                         trp->data_descrip = g_strdup(data_descrip);
2712                 }
2713                 offset += descriptor_len;
2714
2715                 lanman = find_lanman(cmd);
2716
2717                 /* request parameters */
2718                 start_offset = offset;
2719                 offset = dissect_request_parameters(p_tvb, offset, pinfo, tree,
2720                     param_descrip, lanman->req, &has_data);
2721
2722                 /* auxiliary data descriptor */
2723                 if (tvb_reported_length_remaining(p_tvb, offset) > 0){
2724                         /*
2725                          * There are more parameters left, so the next
2726                          * item is the auxiliary data descriptor.
2727                          */
2728                         descriptor_len = tvb_strsize(p_tvb, offset);
2729                         proto_tree_add_item(tree, hf_aux_data_desc, p_tvb, offset,
2730                             descriptor_len, TRUE);
2731                         aux_data_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2732                         if (!pinfo->fd->flags.visited) {
2733                                 /*
2734                                  * Save the auxiliary data descriptor for
2735                                  * future use.
2736                                  */
2737                                 DISSECTOR_ASSERT(trp->aux_data_descrip == NULL);
2738                                 trp->aux_data_descrip =
2739                                     g_strdup(aux_data_descrip);
2740                         }
2741                         offset += descriptor_len;
2742                 }
2743
2744                 /* reset offset, we now start dissecting the data area */
2745                 offset = 0;
2746                 if (has_data && d_tvb && tvb_reported_length(d_tvb) != 0) {
2747                         /*
2748                          * There's a send buffer item in the descriptor
2749                          * string, and the data count in the transaction
2750                          * is non-zero, so there's data to dissect.
2751                          */
2752
2753                         if (lanman->req_data_item != NULL) {
2754                                 /*
2755                                  * Create a protocol tree item for the data.
2756                                  */
2757                                 data_item = (*lanman->req_data_item)(d_tvb,
2758                                     pinfo, tree, offset);
2759                                 data_tree = proto_item_add_subtree(data_item,
2760                                     *lanman->ett_req_data);
2761                         } else {
2762                                 /*
2763                                  * Just leave it at the top level.
2764                                  */
2765                                 data_item = NULL;
2766                                 data_tree = tree;
2767                         }
2768
2769                         /* data */
2770                         offset = dissect_transact_data(d_tvb, offset, -1,
2771                             pinfo, data_tree, data_descrip, lanman->req_data,
2772                             &aux_count);        /* XXX - what about strings? */
2773
2774                         /* auxiliary data */
2775                         if (aux_data_descrip != NULL) {
2776                                 for (i = 0; i < aux_count; i++) {
2777                                         offset = dissect_transact_data(d_tvb,
2778                                             offset, -1, pinfo, data_tree,
2779                                             aux_data_descrip,
2780                                             lanman->req_aux_data, NULL);
2781                                 }
2782                         }
2783
2784                         if (data_item != NULL) {
2785                                 /*
2786                                  * Set the length of the protocol tree item
2787                                  * for the data.
2788                                  */
2789                                 proto_item_set_len(data_item, offset);
2790                         }
2791                 }
2792         } else {
2793                 /*
2794                  * This is a response.
2795                  * Have we seen the request to which it's a response?
2796                  */
2797                 if (trp == NULL)
2798                         return FALSE;   /* no - can't dissect it */
2799
2800                 /* ok we have seen this one before */
2801
2802                 /* if it looks like an interim response, update COL_INFO and return */
2803                 if( ( (p_tvb==NULL) || (tvb_reported_length(p_tvb)==0) )
2804                 &&  ( (d_tvb==NULL) || (tvb_reported_length(d_tvb)==0) ) ){
2805                         /* command */
2806                         if (check_col(pinfo->cinfo, COL_INFO)) {
2807                                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Interim Response",
2808                                              val_to_str(trp->lanman_cmd, commands, "Unknown Command (%u)"));
2809                         }
2810                         proto_tree_add_uint(tree, hf_function_code, p_tvb, 0, 0, trp->lanman_cmd);
2811                         return TRUE;
2812                 }
2813
2814                 /* command */
2815                 if (check_col(pinfo->cinfo, COL_INFO)) {
2816                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s Response",
2817                                      val_to_str(trp->lanman_cmd, commands, "Unknown Command (%u)"));
2818                 }
2819                 proto_tree_add_uint(tree, hf_function_code, p_tvb, 0, 0,
2820                     trp->lanman_cmd);
2821
2822                 lanman = find_lanman(trp->lanman_cmd);
2823
2824                 /* response parameters */
2825
2826                 /* status */
2827                 status = tvb_get_letohs(p_tvb, offset);
2828                 proto_tree_add_uint(tree, hf_status, p_tvb, offset, 2, status);
2829                 offset += 2;
2830
2831                 /* convert */
2832                 convert = tvb_get_letohs(p_tvb, offset);
2833                 proto_tree_add_uint(tree, hf_convert, p_tvb, offset, 2, convert);
2834                 offset += 2;
2835
2836                 if (trp->param_descrip == NULL) {
2837                         /*
2838                          * This could happen if we only dissected
2839                          * part of the request to which this is a
2840                          * reply, e.g. if the request was split
2841                          * across TCP segments and we weren't doing
2842                          * TCP desegmentation, or if we had a snapshot
2843                          * length that was too short.
2844                          *
2845                          * We can't dissect the parameters; just show them
2846                          * as raw data.
2847                          */
2848                         proto_tree_add_text(tree, p_tvb, offset, -1,
2849                             "Parameters (no descriptor available)");
2850
2851                         /*
2852                          * We don't know whether we have a receive buffer,
2853                          * as we don't have the descriptor; just show what
2854                          * bytes purport to be data.
2855                          */
2856                         if (d_tvb && tvb_reported_length(d_tvb) > 0) {
2857                                 proto_tree_add_text(tree, d_tvb, 0, -1,
2858                                     "Data (no descriptor available)");
2859                         }
2860                 } else {
2861                         /* rest of the parameters */
2862                         offset = dissect_response_parameters(p_tvb, offset,
2863                             pinfo, tree, trp->param_descrip, lanman->resp,
2864                             &has_data, &has_ent_count, &ent_count);
2865
2866                         /* reset offset, we now start dissecting the data area */
2867                         offset = 0;
2868                         /* data */
2869                         if (d_tvb && tvb_reported_length(d_tvb) > 0) {
2870                                 /*
2871                                  * Well, there are bytes that purport to
2872                                  * be data, at least.
2873                                  */
2874                                 if (has_data) {
2875                                         /*
2876                                          * There's a receive buffer item
2877                                          * in the descriptor string, so
2878                                          * dissect it as response data.
2879                                          */
2880                                         dissect_response_data(d_tvb, pinfo,
2881                                             convert, tree, smb_info, lanman,
2882                                             has_ent_count, ent_count);
2883                                 } else {
2884                                         /*
2885                                          * There's no receive buffer item,
2886                                          * but we do have data, so just
2887                                          * show what bytes are data.
2888                                          */
2889                                         proto_tree_add_text(tree, d_tvb, 0, -1,
2890                                             "Data (no receive buffer)");
2891                                 }
2892                         }
2893                 }
2894         }
2895
2896         return TRUE;
2897 }
2898
2899 void
2900 proto_register_pipe_lanman(void)
2901 {
2902         static hf_register_info hf[] = {
2903                 { &hf_function_code,
2904                         { "Function Code", "lanman.function_code", FT_UINT16, BASE_DEC,
2905                         VALS(commands), 0, "LANMAN Function Code/Command", HFILL }},
2906
2907                 { &hf_param_desc,
2908                         { "Parameter Descriptor", "lanman.param_desc", FT_STRING, BASE_NONE,
2909                         NULL, 0, "LANMAN Parameter Descriptor", HFILL }},
2910
2911                 { &hf_return_desc,
2912                         { "Return Descriptor", "lanman.ret_desc", FT_STRING, BASE_NONE,
2913                         NULL, 0, "LANMAN Return Descriptor", HFILL }},
2914
2915                 { &hf_aux_data_desc,
2916                         { "Auxiliary Data Descriptor", "lanman.aux_data_desc", FT_STRING, BASE_NONE,
2917                         NULL, 0, "LANMAN Auxiliary Data Descriptor", HFILL }},
2918
2919                 { &hf_detail_level,
2920                         { "Detail Level", "lanman.level", FT_UINT16, BASE_DEC,
2921                         NULL, 0, "LANMAN Detail Level", HFILL }},
2922
2923                 { &hf_recv_buf_len,
2924                         { "Receive Buffer Length", "lanman.recv_buf_len", FT_UINT16, BASE_DEC,
2925                         NULL, 0, "LANMAN Receive Buffer Length", HFILL }},
2926
2927                 { &hf_send_buf_len,
2928                         { "Send Buffer Length", "lanman.send_buf_len", FT_UINT16, BASE_DEC,
2929                         NULL, 0, "LANMAN Send Buffer Length", HFILL }},
2930
2931                 { &hf_continuation_from,
2932                         { "Continuation from message in frame", "lanman.continuation_from", FT_UINT32, BASE_DEC,
2933                         NULL, 0, "This is a LANMAN continuation from the message in the frame in question", HFILL }},
2934
2935                 { &hf_status,
2936                         { "Status", "lanman.status", FT_UINT16, BASE_DEC,
2937                         VALS(status_vals), 0, "LANMAN Return status", HFILL }},
2938
2939                 { &hf_convert,
2940                         { "Convert", "lanman.convert", FT_UINT16, BASE_DEC,
2941                         NULL, 0, "LANMAN Convert", HFILL }},
2942
2943                 { &hf_ecount,
2944                         { "Entry Count", "lanman.entry_count", FT_UINT16, BASE_DEC,
2945                         NULL, 0, "LANMAN Number of Entries", HFILL }},
2946
2947                 { &hf_acount,
2948                         { "Available Entries", "lanman.available_count", FT_UINT16, BASE_DEC,
2949                         NULL, 0, "LANMAN Number of Available Entries", HFILL }},
2950
2951                 { &hf_share_name,
2952                         { "Share Name", "lanman.share.name", FT_STRING, BASE_NONE,
2953                         NULL, 0, "LANMAN Name of Share", HFILL }},
2954
2955                 { &hf_share_type,
2956                         { "Share Type", "lanman.share.type", FT_UINT16, BASE_DEC,
2957                         VALS(share_type_vals), 0, "LANMAN Type of Share", HFILL }},
2958
2959                 { &hf_share_comment,
2960                         { "Share Comment", "lanman.share.comment", FT_STRING, BASE_NONE,
2961                         NULL, 0, "LANMAN Share Comment", HFILL }},
2962
2963                 { &hf_share_permissions,
2964                         { "Share Permissions", "lanman.share.permissions", FT_UINT16, BASE_DEC,
2965                         NULL, 0, "LANMAN Permissions on share", HFILL }},
2966
2967                 { &hf_share_max_uses,
2968                         { "Share Max Uses", "lanman.share.max_uses", FT_UINT16, BASE_DEC,
2969                         NULL, 0, "LANMAN Max connections allowed to share", HFILL }},
2970
2971                 { &hf_share_current_uses,
2972                         { "Share Current Uses", "lanman.share.current_uses", FT_UINT16, BASE_DEC,
2973                         NULL, 0, "LANMAN Current connections to share", HFILL }},
2974
2975                 { &hf_share_path,
2976                         { "Share Path", "lanman.share.path", FT_STRING, BASE_NONE,
2977                         NULL, 0, "LANMAN Share Path", HFILL }},
2978
2979                 { &hf_share_password,
2980                         { "Share Password", "lanman.share.password", FT_STRING, BASE_NONE,
2981                         NULL, 0, "LANMAN Share Password", HFILL }},
2982
2983                 { &hf_server_name,
2984                         { "Server Name", "lanman.server.name", FT_STRING, BASE_NONE,
2985                         NULL, 0, "LANMAN Name of Server", HFILL }},
2986
2987                 { &hf_server_major,
2988                         { "Major Version", "lanman.server.major", FT_UINT8, BASE_DEC,
2989                         NULL, 0, "LANMAN Server Major Version", HFILL }},
2990
2991                 { &hf_server_minor,
2992                         { "Minor Version", "lanman.server.minor", FT_UINT8, BASE_DEC,
2993                         NULL, 0, "LANMAN Server Minor Version", HFILL }},
2994
2995                 { &hf_server_comment,
2996                         { "Server Comment", "lanman.server.comment", FT_STRING, BASE_NONE,
2997                         NULL, 0, "LANMAN Server Comment", HFILL }},
2998
2999                 { &hf_abytes,
3000                         { "Available Bytes", "lanman.available_bytes", FT_UINT16, BASE_DEC,
3001                         NULL, 0, "LANMAN Number of Available Bytes", HFILL }},
3002
3003                 { &hf_current_time,
3004                         { "Current Date/Time", "lanman.current_time", FT_ABSOLUTE_TIME, BASE_NONE,
3005                         NULL, 0, "LANMAN Current date and time, in seconds since 00:00:00, January 1, 1970", HFILL }},
3006
3007                 { &hf_msecs,
3008                         { "Milliseconds", "lanman.msecs", FT_UINT32, BASE_DEC,
3009                         NULL, 0, "LANMAN Milliseconds since arbitrary time in the past (typically boot time)", HFILL }},
3010
3011                 { &hf_hour,
3012                         { "Hour", "lanman.hour", FT_UINT8, BASE_DEC,
3013                         NULL, 0, "LANMAN Current hour", HFILL }},
3014
3015                 { &hf_minute,
3016                         { "Minute", "lanman.minute", FT_UINT8, BASE_DEC,
3017                         NULL, 0, "LANMAN Current minute", HFILL }},
3018
3019                 { &hf_second,
3020                         { "Second", "lanman.second", FT_UINT8, BASE_DEC,
3021                         NULL, 0, "LANMAN Current second", HFILL }},
3022
3023                 { &hf_hundredths,
3024                         { "Hundredths of a second", "lanman.hundredths", FT_UINT8, BASE_DEC,
3025                         NULL, 0, "LANMAN Current hundredths of a second", HFILL }},
3026
3027                 { &hf_tzoffset,
3028                         { "Time Zone Offset", "lanman.tzoffset", FT_INT16, BASE_DEC,
3029                         NULL, 0, "LANMAN Offset of time zone from GMT, in minutes", HFILL }},
3030
3031                 { &hf_timeinterval,
3032                         { "Time Interval", "lanman.timeinterval", FT_UINT16, BASE_DEC,
3033                         NULL, 0, "LANMAN .0001 second units per clock tick", HFILL }},
3034
3035                 { &hf_day,
3036                         { "Day", "lanman.day", FT_UINT8, BASE_DEC,
3037                         NULL, 0, "LANMAN Current day", HFILL }},
3038
3039                 { &hf_month,
3040                         { "Month", "lanman.month", FT_UINT8, BASE_DEC,
3041                         NULL, 0, "LANMAN Current month", HFILL }},
3042
3043                 { &hf_year,
3044                         { "Year", "lanman.year", FT_UINT16, BASE_DEC,
3045                         NULL, 0, "LANMAN Current year", HFILL }},
3046
3047                 { &hf_weekday,
3048                         { "Weekday", "lanman.weekday", FT_UINT8, BASE_DEC,
3049                         VALS(weekday_vals), 0, "LANMAN Current day of the week", HFILL }},
3050
3051                 { &hf_enumeration_domain,
3052                         { "Enumeration Domain", "lanman.enumeration_domain", FT_STRING, BASE_NONE,
3053                         NULL, 0, "LANMAN Domain in which to enumerate servers", HFILL }},
3054
3055                 { &hf_last_entry,
3056                         { "Last Entry", "lanman.last_entry", FT_STRING, BASE_NONE,
3057                         NULL, 0, "LANMAN last reported entry of the enumerated servers", HFILL }},
3058
3059                 { &hf_computer_name,
3060                         { "Computer Name", "lanman.computer_name", FT_STRING, BASE_NONE,
3061                         NULL, 0, "LANMAN Computer Name", HFILL }},
3062
3063                 { &hf_user_name,
3064                         { "User Name", "lanman.user_name", FT_STRING, BASE_NONE,
3065                         NULL, 0, "LANMAN User Name", HFILL }},
3066
3067                 { &hf_group_name,
3068                         { "Group Name", "lanman.group_name", FT_STRING, BASE_NONE,
3069                         NULL, 0, "LANMAN Group Name", HFILL }},
3070
3071                 { &hf_workstation_domain,
3072                         { "Workstation Domain", "lanman.workstation_domain", FT_STRING, BASE_NONE,
3073                         NULL, 0, "LANMAN Workstation Domain", HFILL }},
3074
3075                 { &hf_workstation_major,
3076                         { "Workstation Major Version", "lanman.workstation_major", FT_UINT8, BASE_DEC,
3077                         NULL, 0, "LANMAN Workstation Major Version", HFILL }},
3078
3079                 { &hf_workstation_minor,
3080                         { "Workstation Minor Version", "lanman.workstation_minor", FT_UINT8, BASE_DEC,
3081                         NULL, 0, "LANMAN Workstation Minor Version", HFILL }},
3082
3083                 { &hf_logon_domain,
3084                         { "Logon Domain", "lanman.logon_domain", FT_STRING, BASE_NONE,
3085                         NULL, 0, "LANMAN Logon Domain", HFILL }},
3086
3087                 { &hf_other_domains,
3088                         { "Other Domains", "lanman.other_domains", FT_STRING, BASE_NONE,
3089                         NULL, 0, "LANMAN Other Domains", HFILL }},
3090
3091                 { &hf_password,
3092                         { "Password", "lanman.password", FT_STRING, BASE_NONE,
3093                         NULL, 0, "LANMAN Password", HFILL }},
3094
3095                 { &hf_workstation_name,
3096                         { "Workstation Name", "lanman.workstation_name", FT_STRING, BASE_NONE,
3097                         NULL, 0, "LANMAN Workstation Name", HFILL }},
3098
3099                 { &hf_ustruct_size,
3100                         { "Length of UStruct", "lanman.ustruct_size", FT_UINT16, BASE_DEC,
3101                         NULL, 0, "LANMAN UStruct Length", HFILL }},
3102
3103                 { &hf_logon_code,
3104                         { "Logon Code", "lanman.logon_code", FT_UINT16, BASE_DEC,
3105                         VALS(status_vals), 0, "LANMAN Logon Code", HFILL }},
3106
3107                 { &hf_privilege_level,
3108                         { "Privilege Level", "lanman.privilege_level", FT_UINT16, BASE_DEC,
3109                         VALS(privilege_vals), 0, "LANMAN Privilege Level", HFILL }},
3110
3111                 { &hf_operator_privileges,
3112                         { "Operator Privileges", "lanman.operator_privileges", FT_UINT32, BASE_DEC,
3113                         VALS(op_privilege_vals), 0, "LANMAN Operator Privileges", HFILL }},
3114
3115                 { &hf_num_logons,
3116                         { "Number of Logons", "lanman.num_logons", FT_UINT16, BASE_DEC,
3117                         NULL, 0, "LANMAN Number of Logons", HFILL }},
3118
3119                 { &hf_bad_pw_count,
3120                         { "Bad Password Count", "lanman.bad_pw_count", FT_UINT16, BASE_DEC,
3121                         NULL, 0, "LANMAN Number of incorrect passwords entered since last successful login", HFILL }},
3122
3123                 { &hf_last_logon,
3124                         { "Last Logon Date/Time", "lanman.last_logon", FT_ABSOLUTE_TIME, BASE_NONE,
3125                         NULL, 0, "LANMAN Date and time of last logon", HFILL }},
3126
3127                 { &hf_last_logoff,
3128                         { "Last Logoff Date/Time", "lanman.last_logoff", FT_ABSOLUTE_TIME, BASE_NONE,
3129                         NULL, 0, "LANMAN Date and time of last logoff", HFILL }},
3130
3131                 { &hf_logoff_time,
3132                         { "Logoff Date/Time", "lanman.logoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
3133                         NULL, 0, "LANMAN Date and time when user should log off", HFILL }},
3134
3135                 { &hf_kickoff_time,
3136                         { "Kickoff Date/Time", "lanman.kickoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
3137                         NULL, 0, "LANMAN Date and time when user will be logged off", HFILL }},
3138
3139                 { &hf_password_age,
3140                         { "Password Age", "lanman.password_age", FT_RELATIVE_TIME, BASE_NONE,
3141                         NULL, 0, "LANMAN Time since user last changed his/her password", HFILL }},
3142
3143                 { &hf_password_can_change,
3144                         { "Password Can Change", "lanman.password_can_change", FT_ABSOLUTE_TIME, BASE_NONE,
3145                         NULL, 0, "LANMAN Date and time when user can change their password", HFILL }},
3146
3147                 { &hf_password_must_change,
3148                         { "Password Must Change", "lanman.password_must_change", FT_ABSOLUTE_TIME, BASE_NONE,
3149                         NULL, 0, "LANMAN Date and time when user must change their password", HFILL }},
3150
3151                 { &hf_script_path,
3152                         { "Script Path", "lanman.script_path", FT_STRING, BASE_NONE,
3153                         NULL, 0, "LANMAN Pathname of user's logon script", HFILL }},
3154
3155                 { &hf_logoff_code,
3156                         { "Logoff Code", "lanman.logoff_code", FT_UINT16, BASE_DEC,
3157                         VALS(status_vals), 0, "LANMAN Logoff Code", HFILL }},
3158
3159                 { &hf_duration,
3160                         { "Duration of Session", "lanman.duration", FT_RELATIVE_TIME, BASE_NONE,
3161                         NULL, 0, "LANMAN Number of seconds the user was logged on", HFILL }},
3162
3163                 { &hf_comment,
3164                         { "Comment", "lanman.comment", FT_STRING, BASE_NONE,
3165                         NULL, 0, "LANMAN Comment", HFILL }},
3166
3167                 { &hf_user_comment,
3168                         { "User Comment", "lanman.user_comment", FT_STRING, BASE_NONE,
3169                         NULL, 0, "LANMAN User Comment", HFILL }},
3170
3171                 { &hf_full_name,
3172                         { "Full Name", "lanman.full_name", FT_STRING, BASE_NONE,
3173                         NULL, 0, "LANMAN Full Name", HFILL }},
3174
3175                 { &hf_homedir,
3176                         { "Home Directory", "lanman.homedir", FT_STRING, BASE_NONE,
3177                         NULL, 0, "LANMAN Home Directory", HFILL }},
3178
3179                 { &hf_parameters,
3180                         { "Parameters", "lanman.parameters", FT_STRING, BASE_NONE,
3181                         NULL, 0, "LANMAN Parameters", HFILL }},
3182
3183                 { &hf_logon_server,
3184                         { "Logon Server", "lanman.logon_server", FT_STRING, BASE_NONE,
3185                         NULL, 0, "LANMAN Logon Server", HFILL }},
3186
3187                 /* XXX - we should have a value_string table for this */
3188                 { &hf_country_code,
3189                         { "Country Code", "lanman.country_code", FT_UINT16, BASE_DEC,
3190                         VALS(ms_country_codes), 0, "LANMAN Country Code", HFILL }},
3191
3192                 { &hf_workstations,
3193                         { "Workstations", "lanman.workstations", FT_STRING, BASE_NONE,
3194                         NULL, 0, "LANMAN Workstations", HFILL }},
3195
3196                 { &hf_max_storage,
3197                         { "Max Storage", "lanman.max_storage", FT_UINT32, BASE_DEC,
3198                         NULL, 0, "LANMAN Max Storage", HFILL }},
3199
3200                 { &hf_units_per_week,
3201                         { "Units Per Week", "lanman.units_per_week", FT_UINT16, BASE_DEC,
3202                         NULL, 0, "LANMAN Units Per Week", HFILL }},
3203
3204                 { &hf_logon_hours,
3205                         { "Logon Hours", "lanman.logon_hours", FT_BYTES, BASE_NONE,
3206                         NULL, 0, "LANMAN Logon Hours", HFILL }},
3207
3208                 /* XXX - we should have a value_string table for this */
3209                 { &hf_code_page,
3210                         { "Code Page", "lanman.code_page", FT_UINT16, BASE_DEC,
3211                         NULL, 0, "LANMAN Code Page", HFILL }},
3212
3213                 { &hf_new_password,
3214                         { "New Password", "lanman.new_password", FT_BYTES, BASE_HEX,
3215                         NULL, 0, "LANMAN New Password (encrypted)", HFILL }},
3216
3217                 { &hf_old_password,
3218                         { "Old Password", "lanman.old_password", FT_BYTES, BASE_HEX,
3219                         NULL, 0, "LANMAN Old Password (encrypted)", HFILL }},
3220
3221                 { &hf_reserved,
3222                         { "Reserved", "lanman.reserved", FT_UINT32, BASE_HEX,
3223                         NULL, 0, "LANMAN Reserved", HFILL }},
3224
3225         };
3226         static gint *ett[] = {
3227                 &ett_lanman,
3228                 &ett_lanman_unknown_entries,
3229                 &ett_lanman_unknown_entry,
3230                 &ett_lanman_servers,
3231                 &ett_lanman_server,
3232                 &ett_lanman_groups,
3233                 &ett_lanman_shares,
3234                 &ett_lanman_share,
3235         };
3236
3237         proto_smb_lanman = proto_register_protocol(
3238                 "Microsoft Windows Lanman Remote API Protocol", "LANMAN", "lanman");
3239         proto_register_field_array(proto_smb_lanman, hf, array_length(hf));
3240         proto_register_subtree_array(ett, array_length(ett));
3241 }
3242
3243 static heur_dissector_list_t smb_transact_heur_subdissector_list;
3244
3245 static GHashTable *dcerpc_fragment_table = NULL;
3246 static GHashTable *dcerpc_reassembled_table = NULL;
3247
3248 static void
3249 smb_dcerpc_reassembly_init(void)
3250 {
3251         fragment_table_init(&dcerpc_fragment_table);
3252         reassembled_table_init(&dcerpc_reassembled_table);
3253 }
3254
3255 gboolean
3256 dissect_pipe_dcerpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree,
3257     proto_tree *tree, guint32 fid)
3258 {
3259         smb_info_t *smb_priv = (smb_info_t *)pinfo->private_data;
3260         gboolean result=0;
3261         gboolean save_fragmented;
3262         guint reported_len;
3263         guint32 hash_key;
3264         fragment_data *fd_head;
3265         tvbuff_t *new_tvb;
3266     proto_item *frag_tree_item;
3267
3268         pinfo->dcetransportsalt = fid;
3269
3270         /*
3271          * Offer desegmentation service to DCERPC if we have all the
3272          * data.  Otherwise, reassembly is (probably) impossible.
3273          */
3274         pinfo->can_desegment=0;
3275         pinfo->desegment_offset = 0;
3276         pinfo->desegment_len = 0;
3277         reported_len = tvb_reported_length(d_tvb);
3278         if(smb_dcerpc_reassembly && tvb_bytes_exist(d_tvb, 0, reported_len)){
3279                 pinfo->can_desegment=2;
3280         }
3281
3282         save_fragmented = pinfo->fragmented;
3283
3284
3285         /* if we are not offering desegmentation, just try the heuristics
3286            and bail out
3287         */
3288         if(!pinfo->can_desegment){
3289                 result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
3290                 goto clean_up_and_exit;
3291         }
3292
3293
3294         /* below this line, we know we are doing reassembly */
3295         
3296         /*
3297          * We have to keep track of reassemblies by FID, because
3298          * we could have more than one pipe operation in a frame
3299          * with NetBIOS-over-TCP.
3300          *
3301          * We also have to keep track of them by direction, as
3302          * we might have reassemblies in progress in both directions.
3303          *
3304          * We do that by combining the FID and the direction and
3305          * using that as the reassembly ID.
3306          *
3307          * The direction is indicated by the SMB request/reply flag - data
3308          * from client to server is carried in requests, data from server
3309          * to client is carried in replies.
3310          *
3311          * We know that the FID is only 16 bits long, so we put the
3312          * direction in bit 17.
3313          */
3314         hash_key = fid;
3315         if (smb_priv->request)
3316                 hash_key |= 0x10000;
3317
3318         /* this is a new packet, see if we are already reassembling this
3319            pdu and if not, check if the dissector wants us
3320            to reassemble it
3321         */
3322         if(!pinfo->fd->flags.visited){
3323                 /*
3324                  * This is the first pass.
3325                  *
3326                  * Check if we are already reassembling this PDU or not;
3327                  * we check for an in-progress reassembly for this FID
3328                  * in this direction, by searching for its reassembly
3329                  * structure.
3330                  */
3331                 fd_head=fragment_get(pinfo, fid, dcerpc_fragment_table);
3332                 if(!fd_head){
3333                         /* No reassembly, so this is a new pdu. check if the
3334                            dissector wants us to reassemble it or if we
3335                            already got the full pdu in this tvb.
3336                         */
3337
3338                         /*
3339                          * First, just check if it looks like dcerpc or not.
3340                          *
3341                          * XXX - this assumes that the dissector is idempotent,
3342                          * as it's doing a "trial" dissection building no
3343                          * tree; that's not necessarily the case.
3344                          */
3345                         result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, NULL);
3346                         
3347                         /* no this didnt look like something we know */
3348                         if(!result){
3349                                 goto clean_up_and_exit;
3350                         }
3351
3352                         /* did the subdissector want us to reassemble any
3353                            more data ?
3354                         */
3355                         if(pinfo->desegment_len){
3356                                 fragment_add_check(d_tvb, 0, pinfo, fid,
3357                                         dcerpc_fragment_table,
3358                                         dcerpc_reassembled_table,
3359                                         0, reported_len, TRUE);
3360                                 fragment_set_tot_len(pinfo, fid,
3361                                         dcerpc_fragment_table,
3362                                         pinfo->desegment_len+reported_len);
3363                                 goto clean_up_and_exit;
3364                         }
3365
3366                         /* guess we have the full pdu in this tvb then,
3367                            just dissect it and continue.
3368                         */
3369                         result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
3370                         goto clean_up_and_exit;
3371                 }
3372
3373                 /* OK, we're already doing a reassembly for this FID.
3374                    skip to last segment in the existing reassembly structure
3375                    and add this fragment there
3376
3377                    XXX we might add code here to use any offset values
3378                    we might pick up from the Read/Write calls instead of
3379                    assuming we always get them in the correct order
3380                 */
3381                 while(fd_head->next){
3382                         fd_head=fd_head->next;
3383                 }
3384                 fd_head=fragment_add_check(d_tvb, 0, pinfo, fid,
3385                         dcerpc_fragment_table, dcerpc_reassembled_table,
3386                         fd_head->offset+fd_head->len,
3387                         reported_len, TRUE);
3388
3389                 /* if we completed reassembly */
3390                 if(fd_head){
3391                         new_tvb = tvb_new_real_data(fd_head->data,
3392                                   fd_head->datalen, fd_head->datalen);
3393                         tvb_set_child_real_data_tvbuff(d_tvb, new_tvb);
3394                         add_new_data_source(pinfo, new_tvb,
3395                                   "DCERPC over SMB");
3396                         pinfo->fragmented=FALSE;
3397
3398                         d_tvb=new_tvb;
3399
3400                         /* list what segments we have */
3401                         show_fragment_tree(fd_head, &smb_pipe_frag_items,
3402                             tree, pinfo, d_tvb, &frag_tree_item);
3403
3404                         /* dissect the full PDU */
3405                         result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
3406                 }
3407                 goto clean_up_and_exit;
3408         }
3409
3410         /*
3411          * This is not the first pass; see if it's in the table of
3412          * reassembled packets.
3413          *
3414          * XXX - we know that several of the arguments aren't going to
3415          * be used, so we pass bogus variables.  Can we clean this
3416          * up so that we don't have to distinguish between the first
3417          * pass and subsequent passes?
3418          */
3419         fd_head=fragment_add_check(d_tvb, 0, pinfo, fid, dcerpc_fragment_table,
3420             dcerpc_reassembled_table, 0, 0, TRUE);
3421         if(!fd_head){
3422                 /* we didnt find it, try any of the heuristic dissectors
3423                    and bail out 
3424                 */
3425                 result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
3426                 goto clean_up_and_exit;
3427         }
3428         if(!fd_head->flags&FD_DEFRAGMENTED){
3429                 /* we dont have a fully reassembled frame */
3430                 result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
3431                 goto clean_up_and_exit;
3432         }
3433
3434         /* it is reassembled but it was reassembled in a different frame */
3435         if(pinfo->fd->num!=fd_head->reassembled_in){
3436                 proto_tree_add_uint(parent_tree, hf_pipe_reassembled_in, d_tvb, 0, 0, fd_head->reassembled_in);
3437                 goto clean_up_and_exit;
3438         }
3439
3440
3441         /* display the reassembled pdu */
3442         new_tvb = tvb_new_real_data(fd_head->data,
3443                   fd_head->datalen, fd_head->datalen);
3444         tvb_set_child_real_data_tvbuff(d_tvb, new_tvb);
3445         add_new_data_source(pinfo, new_tvb,
3446                   "DCERPC over SMB");
3447         pinfo->fragmented=FALSE;
3448
3449         d_tvb=new_tvb;
3450
3451         /* list what segments we have */
3452         show_fragment_tree(fd_head, &smb_pipe_frag_items,
3453                     tree, pinfo, d_tvb, &frag_tree_item);
3454
3455         /* dissect the full PDU */
3456         result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree);
3457         
3458
3459
3460 clean_up_and_exit:
3461         /* clear out the variables */
3462         pinfo->private_data = smb_priv;
3463         pinfo->can_desegment=0;
3464         pinfo->desegment_offset = 0;
3465         pinfo->desegment_len = 0;
3466
3467         if (!result)
3468                 call_dissector(data_handle, d_tvb, pinfo, parent_tree);
3469
3470         pinfo->fragmented = save_fragmented;
3471         return TRUE;
3472 }
3473
3474 void
3475 proto_register_pipe_dcerpc(void)
3476 {
3477         register_heur_dissector_list("smb_transact", &smb_transact_heur_subdissector_list);
3478         register_init_routine(smb_dcerpc_reassembly_init);
3479 }
3480
3481 #define CALL_NAMED_PIPE         0x54
3482 #define WAIT_NAMED_PIPE         0x53
3483 #define PEEK_NAMED_PIPE         0x23
3484 #define Q_NM_P_HAND_STATE       0x21
3485 #define SET_NM_P_HAND_STATE     0x01
3486 #define Q_NM_PIPE_INFO          0x22
3487 #define TRANSACT_NM_PIPE        0x26
3488 #define RAW_READ_NM_PIPE        0x11
3489 #define RAW_WRITE_NM_PIPE       0x31
3490
3491 static const value_string functions[] = {
3492         {CALL_NAMED_PIPE,       "CallNamedPipe"},
3493         {WAIT_NAMED_PIPE,       "WaitNamedPipe"},
3494         {PEEK_NAMED_PIPE,       "PeekNamedPipe"},
3495         {Q_NM_P_HAND_STATE,     "QNmPHandState"},
3496         {SET_NM_P_HAND_STATE,   "SetNmPHandState"},
3497         {Q_NM_PIPE_INFO,        "QNmPipeInfo"},
3498         {TRANSACT_NM_PIPE,      "TransactNmPipe"},
3499         {RAW_READ_NM_PIPE,      "RawReadNmPipe"},
3500         {RAW_WRITE_NM_PIPE,     "RawWriteNmPipe"},
3501         {0,                     NULL}
3502 };
3503
3504 static const value_string pipe_status[] = {
3505         {1,     "Disconnected by server"},
3506         {2,     "Listening"},
3507         {3,     "Connection to server is OK"},
3508         {4,     "Server end of pipe is closed"},
3509         {0,     NULL}
3510 };
3511
3512 #define PIPE_LANMAN     1
3513 #define PIPE_DCERPC     2
3514
3515 /* decode the SMB pipe protocol
3516    for requests
3517     pipe is the name of the pipe, e.g. LANMAN
3518     smb_info->trans_subcmd is set to the symbolic constant matching the mailslot name
3519   for responses
3520     pipe is NULL
3521     smb_info->trans_subcmd gives us which pipe this response is for
3522 */
3523 gboolean
3524 dissect_pipe_smb(tvbuff_t *sp_tvb, tvbuff_t *s_tvb, tvbuff_t *pd_tvb,
3525                  tvbuff_t *p_tvb, tvbuff_t *d_tvb, const char *pipe,
3526                  packet_info *pinfo, proto_tree *tree)
3527 {
3528         smb_info_t *smb_info;
3529         smb_transact_info_t *tri;
3530         guint sp_len;
3531         proto_item *pipe_item = NULL;
3532         proto_tree *pipe_tree = NULL;
3533         int offset;
3534         int trans_subcmd;
3535         int function;
3536         int fid = -1;
3537         guint16 info_level;
3538
3539         if (!proto_is_protocol_enabled(find_protocol_by_id(proto_smb_pipe)))
3540                 return FALSE;
3541         pinfo->current_proto = "SMB Pipe";
3542
3543         smb_info = pinfo->private_data;
3544
3545         /*
3546          * Set the columns.
3547          */
3548         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
3549                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMB Pipe");
3550         }
3551         if (check_col(pinfo->cinfo, COL_INFO)) {
3552                 col_set_str(pinfo->cinfo, COL_INFO,
3553                     smb_info->request ? "Request" : "Response");
3554         }
3555
3556         if (smb_info->sip != NULL && smb_info->sip->extra_info_type == SMB_EI_TRI)
3557                 tri = smb_info->sip->extra_info;
3558         else
3559                 tri = NULL;
3560
3561         /*
3562          * Set up a subtree for the pipe protocol.  (It might not contain
3563          * anything.)
3564          */
3565         if (sp_tvb != NULL)
3566                 sp_len = tvb_length(sp_tvb);
3567         else
3568                 sp_len = 0;
3569         if (tree) {
3570                 pipe_item = proto_tree_add_item(tree, proto_smb_pipe,
3571                     sp_tvb, 0, sp_len, FALSE);
3572                 pipe_tree = proto_item_add_subtree(pipe_item, ett_smb_pipe);
3573         }
3574         offset = 0;
3575
3576         /*
3577          * Do we have any setup words at all?
3578          */
3579         if (s_tvb != NULL && tvb_length(s_tvb) != 0) {
3580                 /*
3581                  * Yes.  The first of them is the function.
3582                  */
3583                 function = tvb_get_letohs(s_tvb, offset);
3584                 proto_tree_add_uint(pipe_tree, hf_pipe_function, s_tvb,
3585                     offset, 2, function);
3586                 offset += 2;
3587                 if (check_col(pinfo->cinfo, COL_INFO)) {
3588                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
3589                             val_to_str(function, functions, "Unknown function (0x%04x)"),
3590                             smb_info->request ? "Request" : "Response");
3591                 }
3592                 if (tri != NULL)
3593                         tri->function = function;
3594
3595                 /*
3596                  * The second of them depends on the function.
3597                  */
3598                 switch (function) {
3599
3600                 case CALL_NAMED_PIPE:
3601                 case WAIT_NAMED_PIPE:
3602                         /*
3603                          * It's a priority.
3604                          */
3605                         proto_tree_add_item(pipe_tree, hf_pipe_priority, s_tvb,
3606                             offset, 2, TRUE);
3607                         break;
3608
3609                 case PEEK_NAMED_PIPE:
3610                 case Q_NM_P_HAND_STATE:
3611                 case SET_NM_P_HAND_STATE:
3612                 case Q_NM_PIPE_INFO:
3613                 case TRANSACT_NM_PIPE:
3614                 case RAW_READ_NM_PIPE:
3615                 case RAW_WRITE_NM_PIPE:
3616                         /*
3617                          * It's a FID.
3618                          */
3619                         fid = tvb_get_letohs(s_tvb, 2);
3620                         add_fid(s_tvb, pinfo, pipe_tree, offset, 2, (guint16) fid);
3621                         if (tri != NULL)
3622                                 tri->fid = fid;
3623                         break;
3624
3625                 default:
3626                         /*
3627                          * It's something unknown.
3628                          * XXX - put it into the tree?
3629                          */
3630                         break;
3631                 }
3632                 offset += 2;
3633         } else {
3634                 /*
3635                  * This is either a response or a pipe transaction with
3636                  * no setup information.
3637                  *
3638                  * In the former case, we can get that information from
3639                  * the matching request, if we saw it.
3640                  *
3641                  * In the latter case, there is no function or FID.
3642                  */
3643                 if (tri != NULL && tri->function != -1) {
3644                         function = tri->function;
3645                         proto_tree_add_uint(pipe_tree, hf_pipe_function, NULL,
3646                             0, 0, function);
3647                         if (check_col(pinfo->cinfo, COL_INFO)) {
3648                                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
3649                                     val_to_str(function, functions, "Unknown function (0x%04x)"),
3650                                     smb_info->request ? "Request" : "Response");
3651                         }
3652                         fid = tri->fid;
3653                         if (fid != -1)
3654                                 add_fid(NULL, pinfo, pipe_tree, 0, 0, (guint16) fid);
3655                 } else {
3656                         function = -1;
3657                         fid = -1;
3658                 }
3659         }
3660
3661         /*
3662          * XXX - put the byte count and the pipe name into the tree as well;
3663          * that requires us to fetch a possibly-Unicode string.
3664          */
3665
3666         if(smb_info->request){
3667                 if(strncmp(pipe,"LANMAN",6) == 0){
3668                         trans_subcmd=PIPE_LANMAN;
3669                 } else {
3670                         /* assume it is DCERPC */
3671                         trans_subcmd=PIPE_DCERPC;
3672                 }
3673
3674                 if (!pinfo->fd->flags.visited)
3675                         tri->trans_subcmd = trans_subcmd;
3676         } else
3677                 trans_subcmd = tri->trans_subcmd;
3678
3679         if (tri == NULL) {
3680                 /*
3681                  * We don't know what type of pipe transaction this
3682                  * was, so indicate that we didn't dissect it.
3683                  */
3684                 return FALSE;
3685         }
3686
3687         switch (function) {
3688
3689         case CALL_NAMED_PIPE:
3690         case TRANSACT_NM_PIPE:
3691                 switch(trans_subcmd){
3692
3693                 case PIPE_LANMAN:
3694                         return dissect_pipe_lanman(pd_tvb, p_tvb, d_tvb, pinfo,
3695                             tree);
3696                         break;
3697
3698                 case PIPE_DCERPC:
3699                         /*
3700                          * Only dissect this if we know the FID.
3701                          */
3702                         if (fid != -1) {
3703                                 if (d_tvb == NULL)
3704                                         return FALSE;
3705                                 return dissect_pipe_dcerpc(d_tvb, pinfo, tree,
3706                                     pipe_tree, fid);
3707                         }
3708                         break;
3709                 }
3710                 break;
3711
3712         case -1:
3713                 /*
3714                  * We don't know the function; we dissect only LANMAN
3715                  * pipe messages, not RPC pipe messages, in that case.
3716                  */
3717                 switch(trans_subcmd){
3718                 case PIPE_LANMAN:
3719                         return dissect_pipe_lanman(pd_tvb, p_tvb, d_tvb, pinfo,
3720                             tree);
3721                         break;
3722                 }
3723                 break;
3724
3725         case WAIT_NAMED_PIPE:
3726                 break;
3727
3728         case PEEK_NAMED_PIPE:
3729                 /*
3730                  * Request contains no parameters or data.
3731                  */
3732                 if (!smb_info->request) {
3733                         if (p_tvb == NULL)
3734                                 return FALSE;
3735                         offset = 0;
3736                         proto_tree_add_item(pipe_tree, hf_pipe_peek_available,
3737                             p_tvb, offset, 2, TRUE);
3738                         offset += 2;
3739                         proto_tree_add_item(pipe_tree, hf_pipe_peek_remaining,
3740                             p_tvb, offset, 2, TRUE);
3741                         offset += 2;
3742                         proto_tree_add_item(pipe_tree, hf_pipe_peek_status,
3743                             p_tvb, offset, 2, TRUE);
3744                         offset += 2;
3745                 }
3746                 break;
3747
3748         case Q_NM_P_HAND_STATE:
3749                 /*
3750                  * Request contains no parameters or data.
3751                  */
3752                 if (!smb_info->request) {
3753                         if (p_tvb == NULL)
3754                                 return FALSE;
3755                         offset = dissect_ipc_state(p_tvb, pipe_tree, 0, FALSE);
3756                 }
3757                 break;
3758
3759         case SET_NM_P_HAND_STATE:
3760                 /*
3761                  * Response contains no parameters or data.
3762                  */
3763                 if (smb_info->request) {
3764                         if (p_tvb == NULL)
3765                                 return FALSE;
3766                         offset = dissect_ipc_state(p_tvb, pipe_tree, 0, TRUE);
3767                 }
3768                 break;
3769
3770         case Q_NM_PIPE_INFO:
3771                 offset = 0;
3772                 if (smb_info->request) {
3773                         if (p_tvb == NULL)
3774                                 return FALSE;
3775
3776                         /*
3777                          * Request contains an information level.
3778                          */
3779                         info_level = tvb_get_letohs(p_tvb, offset);
3780                         proto_tree_add_uint(pipe_tree, hf_pipe_getinfo_info_level,
3781                             p_tvb, offset, 2, info_level);
3782                         offset += 2;
3783                         if (!pinfo->fd->flags.visited)
3784                                 tri->info_level = info_level;
3785                 } else {
3786                         guint8 pipe_namelen;
3787
3788                         if (d_tvb == NULL)
3789                                 return FALSE;
3790
3791                         switch (tri->info_level) {
3792
3793                         case 1:
3794                                 proto_tree_add_item(pipe_tree,
3795                                     hf_pipe_getinfo_output_buffer_size,
3796                                     d_tvb, offset, 2, TRUE);
3797                                 offset += 2;
3798                                 proto_tree_add_item(pipe_tree,
3799                                     hf_pipe_getinfo_input_buffer_size,
3800                                     d_tvb, offset, 2, TRUE);
3801                                 offset += 2;
3802                                 proto_tree_add_item(pipe_tree,
3803                                     hf_pipe_getinfo_maximum_instances,
3804                                     d_tvb, offset, 1, TRUE);
3805                                 offset += 1;
3806                                 proto_tree_add_item(pipe_tree,
3807                                     hf_pipe_getinfo_current_instances,
3808                                     d_tvb, offset, 1, TRUE);
3809                                 offset += 1;
3810                                 pipe_namelen = tvb_get_guint8(d_tvb, offset);
3811                                 proto_tree_add_uint(pipe_tree,
3812                                     hf_pipe_getinfo_pipe_name_length,
3813                                     d_tvb, offset, 1, pipe_namelen);
3814                                 offset += 1;
3815                                 /* XXX - can this be Unicode? */
3816                                 proto_tree_add_item(pipe_tree,
3817                                     hf_pipe_getinfo_pipe_name,
3818                                     d_tvb, offset, pipe_namelen, TRUE);
3819                                 break;
3820                         }
3821                 }
3822                 break;
3823
3824         case RAW_READ_NM_PIPE:
3825                 /*
3826                  * Request contains no parameters or data.
3827                  */
3828                 if (!smb_info->request) {
3829                         if (d_tvb == NULL)
3830                                 return FALSE;
3831
3832                         offset = dissect_file_data(d_tvb, pipe_tree, 0,
3833                             (guint16) tvb_reported_length(d_tvb),
3834                             (guint16) tvb_reported_length(d_tvb));
3835                 }
3836                 break;
3837
3838         case RAW_WRITE_NM_PIPE:
3839                 offset = 0;
3840                 if (smb_info->request) {
3841                         if (d_tvb == NULL)
3842                                 return FALSE;
3843
3844                         offset = dissect_file_data(d_tvb, pipe_tree,
3845                             offset, (guint16) tvb_reported_length(d_tvb),
3846                             (guint16) tvb_reported_length(d_tvb));
3847                 } else {
3848                         if (p_tvb == NULL)
3849                                 return FALSE;
3850                         proto_tree_add_item(pipe_tree,
3851                             hf_pipe_write_raw_bytes_written,
3852                             p_tvb, offset, 2, TRUE);
3853                         offset += 2;
3854                 }
3855                 break;
3856         }
3857         return TRUE;
3858 }
3859
3860 void
3861 proto_register_smb_pipe(void)
3862 {
3863         static hf_register_info hf[] = {
3864                 { &hf_pipe_function,
3865                         { "Function", "pipe.function", FT_UINT16, BASE_HEX,
3866                         VALS(functions), 0, "SMB Pipe Function Code", HFILL }},
3867                 { &hf_pipe_priority,
3868                         { "Priority", "pipe.priority", FT_UINT16, BASE_DEC,
3869                         NULL, 0, "SMB Pipe Priority", HFILL }},
3870                 { &hf_pipe_peek_available,
3871                         { "Available Bytes", "pipe.peek.available_bytes", FT_UINT16, BASE_DEC,
3872                         NULL, 0, "Total number of bytes available to be read from the pipe", HFILL }},
3873                 { &hf_pipe_peek_remaining,
3874                         { "Bytes Remaining", "pipe.peek.remaining_bytes", FT_UINT16, BASE_DEC,
3875                         NULL, 0, "Total number of bytes remaining in the message at the head of the pipe", HFILL }},
3876                 { &hf_pipe_peek_status,
3877                         { "Pipe Status", "pipe.peek.status", FT_UINT16, BASE_DEC,
3878                         VALS(pipe_status), 0, "Pipe status", HFILL }},
3879                 { &hf_pipe_getinfo_info_level,
3880                         { "Information Level", "pipe.getinfo.info_level", FT_UINT16, BASE_DEC,
3881                         NULL, 0, "Information level of information to return", HFILL }},
3882                 { &hf_pipe_getinfo_output_buffer_size,
3883                         { "Output Buffer Size", "pipe.getinfo.output_buffer_size", FT_UINT16, BASE_DEC,
3884                         NULL, 0, "Actual size of buffer for outgoing (server) I/O", HFILL }},
3885                 { &hf_pipe_getinfo_input_buffer_size,
3886                         { "Input Buffer Size", "pipe.getinfo.input_buffer_size", FT_UINT16, BASE_DEC,
3887                         NULL, 0, "Actual size of buffer for incoming (client) I/O", HFILL }},
3888                 { &hf_pipe_getinfo_maximum_instances,
3889                         { "Maximum Instances", "pipe.getinfo.maximum_instances", FT_UINT8, BASE_DEC,
3890                         NULL, 0, "Maximum allowed number of instances", HFILL }},
3891                 { &hf_pipe_getinfo_current_instances,
3892                         { "Current Instances", "pipe.getinfo.current_instances", FT_UINT8, BASE_DEC,
3893                         NULL, 0, "Current number of instances", HFILL }},
3894                 { &hf_pipe_getinfo_pipe_name_length,
3895                         { "Pipe Name Length", "pipe.getinfo.pipe_name_length", FT_UINT8, BASE_DEC,
3896                         NULL, 0, "Length of pipe name", HFILL }},
3897                 { &hf_pipe_getinfo_pipe_name,
3898                         { "Pipe Name", "pipe.getinfo.pipe_name", FT_STRING, BASE_NONE,
3899                         NULL, 0, "Name of pipe", HFILL }},
3900                 { &hf_pipe_write_raw_bytes_written,
3901                         { "Bytes Written", "pipe.write_raw.bytes_written", FT_UINT16, BASE_DEC,
3902                         NULL, 0, "Number of bytes written to the pipe", HFILL }},
3903                 { &hf_pipe_fragment_overlap,
3904                         { "Fragment overlap",   "pipe.fragment.overlap", FT_BOOLEAN, BASE_NONE,
3905                         NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
3906                 { &hf_pipe_fragment_overlap_conflict,
3907                         { "Conflicting data in fragment overlap",       "pipe.fragment.overlap.conflict", FT_BOOLEAN,
3908                         BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
3909                 { &hf_pipe_fragment_multiple_tails,
3910                         { "Multiple tail fragments found",      "pipe.fragment.multipletails", FT_BOOLEAN,
3911                         BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
3912                 { &hf_pipe_fragment_too_long_fragment,
3913                         { "Fragment too long",  "pipe.fragment.toolongfragment", FT_BOOLEAN,
3914                         BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
3915                 { &hf_pipe_fragment_error,
3916                         { "Defragmentation error", "pipe.fragment.error", FT_FRAMENUM,
3917                         BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
3918                 { &hf_pipe_fragment,
3919                         { "Fragment", "pipe.fragment", FT_FRAMENUM,
3920                         BASE_NONE, NULL, 0x0, "Pipe Fragment", HFILL }},
3921                 { &hf_pipe_fragments,
3922                         { "Fragments", "pipe.fragments", FT_NONE,
3923                         BASE_NONE, NULL, 0x0, "Pipe Fragments", HFILL }},
3924                 { &hf_pipe_reassembled_in,
3925                         { "This PDU is reassembled in", "pipe.reassembled_in", FT_FRAMENUM,
3926                         BASE_NONE, NULL, 0x0, "The DCE/RPC PDU is completely reassembled in this frame", HFILL }},
3927         };
3928         static gint *ett[] = {
3929                 &ett_smb_pipe,
3930                 &ett_smb_pipe_fragment,
3931                 &ett_smb_pipe_fragments,
3932         };
3933
3934         proto_smb_pipe = proto_register_protocol(
3935                 "SMB Pipe Protocol", "SMB Pipe", "pipe");
3936
3937         proto_register_field_array(proto_smb_pipe, hf, array_length(hf));
3938         proto_register_subtree_array(ett, array_length(ett));
3939 }
3940
3941 void
3942 proto_reg_handoff_smb_pipe(void)
3943 {
3944         data_handle = find_dissector("data");
3945 }