From Ronnie Sahlberg:
[obnox/wireshark/wip.git] / 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: packet-smb-pipe.c,v 1.66 2002/01/21 07:36:42 guy Exp $
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 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
42 #endif
43
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
46 #endif
47
48 #include <time.h>
49 #include <string.h>
50 #include <glib.h>
51 #include <ctype.h>
52 #include <epan/packet.h>
53 #include <epan/conversation.h>
54 #include "smb.h"
55 #include "packet-smb-pipe.h"
56 #include "packet-smb-browse.h"
57 #include "packet-dcerpc.h"
58 #include "reassemble.h"
59
60 static int proto_smb_pipe = -1;
61 static int hf_pipe_function = -1;
62 static int hf_pipe_priority = -1;
63 static int hf_pipe_peek_available = -1;
64 static int hf_pipe_peek_remaining = -1;
65 static int hf_pipe_peek_status = -1;
66 static int hf_pipe_getinfo_info_level = -1;
67 static int hf_pipe_getinfo_output_buffer_size = -1;
68 static int hf_pipe_getinfo_input_buffer_size = -1;
69 static int hf_pipe_getinfo_maximum_instances = -1;
70 static int hf_pipe_getinfo_current_instances = -1;
71 static int hf_pipe_getinfo_pipe_name_length = -1;
72 static int hf_pipe_getinfo_pipe_name = -1;
73 static int hf_pipe_write_raw_bytes_written = -1;
74
75 static gint ett_smb_pipe = -1;
76 static gint ett_smb_pipe_fragments = -1;
77
78 static int proto_smb_lanman = -1;
79 static int hf_function_code = -1;
80 static int hf_param_desc = -1;
81 static int hf_return_desc = -1;
82 static int hf_aux_data_desc = -1;
83 static int hf_detail_level = -1;
84 static int hf_recv_buf_len = -1;
85 static int hf_send_buf_len = -1;
86 static int hf_continuation_from = -1;
87 static int hf_status = -1;
88 static int hf_convert = -1;
89 static int hf_ecount = -1;
90 static int hf_acount = -1;
91 static int hf_share_name = -1;
92 static int hf_share_type = -1;
93 static int hf_share_comment = -1;
94 static int hf_share_permissions = -1;
95 static int hf_share_max_uses = -1;
96 static int hf_share_current_uses = -1;
97 static int hf_share_path = -1;
98 static int hf_share_password = -1;
99 static int hf_server_name = -1;
100 static int hf_server_major = -1;
101 static int hf_server_minor = -1;
102 static int hf_server_comment = -1;
103 static int hf_abytes = -1;
104 static int hf_current_time = -1;
105 static int hf_msecs = -1;
106 static int hf_hour = -1;
107 static int hf_minute = -1;
108 static int hf_second = -1;
109 static int hf_hundredths = -1;
110 static int hf_tzoffset = -1;
111 static int hf_timeinterval = -1;
112 static int hf_day = -1;
113 static int hf_month = -1;
114 static int hf_year = -1;
115 static int hf_weekday = -1;
116 static int hf_enumeration_domain = -1;
117 static int hf_computer_name = -1;
118 static int hf_user_name = -1;
119 static int hf_workstation_domain = -1;
120 static int hf_workstation_major = -1;
121 static int hf_workstation_minor = -1;
122 static int hf_logon_domain = -1;
123 static int hf_other_domains = -1;
124 static int hf_password = -1;
125 static int hf_workstation_name = -1;
126 static int hf_ustruct_size = -1;
127 static int hf_logon_code = -1;
128 static int hf_privilege_level = -1;
129 static int hf_operator_privileges = -1;
130 static int hf_num_logons = -1;
131 static int hf_bad_pw_count = -1;
132 static int hf_last_logon = -1;
133 static int hf_last_logoff = -1;
134 static int hf_logoff_time = -1;
135 static int hf_kickoff_time = -1;
136 static int hf_password_age = -1;
137 static int hf_password_can_change = -1;
138 static int hf_password_must_change = -1;
139 static int hf_script_path = -1;
140 static int hf_logoff_code = -1;
141 static int hf_duration = -1;
142 static int hf_user_comment = -1;
143 static int hf_full_name = -1;
144 static int hf_homedir = -1;
145 static int hf_parameters = -1;
146 static int hf_logon_server = -1;
147 static int hf_country_code = -1;
148 static int hf_workstations = -1;
149 static int hf_max_storage = -1;
150 static int hf_units_per_week = -1;
151 static int hf_logon_hours = -1;
152 static int hf_code_page = -1;
153 static int hf_new_password = -1;
154 static int hf_old_password = -1;
155 static int hf_reserved = -1;
156
157 static gint ett_lanman = -1;
158 static gint ett_lanman_shares = -1;
159 static gint ett_lanman_share = -1;
160 static gint ett_lanman_servers = -1;
161 static gint ett_lanman_server = -1;
162
163 static dissector_handle_t data_handle;
164
165 /*
166  * See
167  *
168  *      ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt
169  *
170  * among other documents.
171  */
172
173 static const value_string status_vals[] = {
174         {0,     "Success"},
175         {5,     "User has insufficient privilege"},
176         {65,    "Network access is denied"},
177         {86,    "The specified password is invalid"},
178         {SMBE_moredata, "Additional data is available"},
179         {2114,  "Service is not running on the remote computer"},
180         {2123,  "Supplied buffer is too small"},
181         {2141,  "Server is not configured for transactions (IPC$ not shared)"},
182         {2212,  "An error occurred while loading or running the logon script"},
183         {2214,  "The logon was not validated by any server"},
184         {2217,  "The logon server is running an older software version"},
185         {2221,  "The user name was not found"},
186         {2240,  "The user is not allowed to logon from this computer"},
187         {2241,  "The user is not allowed to logon at this time"},
188         {2242,  "The user password has expired"},
189         {2243,  "The password cannot be changed"},
190         {2246,  "The password is too short"},
191         {0,     NULL}
192 };
193
194 static const value_string share_type_vals[] = {
195         {0, "Directory tree"},
196         {1, "Printer queue"},
197         {2, "Communications device"},
198         {3, "IPC"},
199         {0, NULL}
200 };
201
202 static const value_string privilege_vals[] = {
203         {0, "Guest"},
204         {1, "User"},
205         {2, "Administrator"},
206         {0, NULL}
207 };
208
209 static const value_string op_privilege_vals[] = {
210         {0, "Print operator"},
211         {1, "Communications operator"},
212         {2, "Server operator"},
213         {3, "Accounts operator"},
214         {0, NULL}
215 };
216
217 static const value_string weekday_vals[] = {
218         {0, "Sunday"},
219         {1, "Monday"},
220         {2, "Tuesday"},
221         {3, "Wednesday"},
222         {4, "Thursday"},
223         {5, "Friday"},
224         {6, "Saturday"},
225         {0, NULL}
226 };
227
228 static int
229 add_word_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
230     proto_tree *tree, int convert, int hf_index)
231 {
232         guint16 WParam;
233
234         if (hf_index != -1)
235                 proto_tree_add_item(tree, hf_index, tvb, offset, 2, TRUE);
236         else {
237                 WParam = tvb_get_letohs(tvb, offset);
238                 proto_tree_add_text(tree, tvb, offset, 2,
239                     "Word Param: %u (0x%04X)", WParam, WParam);
240         }
241         offset += 2;
242         return offset;
243 }
244
245 static int
246 add_dword_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
247     proto_tree *tree, int convert, int hf_index)
248 {
249         guint32 LParam;
250
251         if (hf_index != -1)
252                 proto_tree_add_item(tree, hf_index, tvb, offset, 4, TRUE);
253         else {
254                 LParam = tvb_get_letohl(tvb, offset);
255                 proto_tree_add_text(tree, tvb, offset, 4,
256                     "Doubleword Param: %u (0x%08X)", LParam, LParam);
257         }
258         offset += 4;
259         return offset;
260 }
261
262 static int
263 add_byte_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
264     proto_tree *tree, int convert, int hf_index)
265 {
266         guint8 BParam;
267
268         if (hf_index != -1)
269                 proto_tree_add_item(tree, hf_index, tvb, offset, count, TRUE);
270         else {
271                 if (count == 1) {
272                         BParam = tvb_get_guint8(tvb, offset);
273                         proto_tree_add_text(tree, tvb, offset, count,
274                             "Byte Param: %u (0x%02X)",
275                             BParam, BParam);
276                 } else {
277                         proto_tree_add_text(tree, tvb, offset, count,
278                             "Bytes Param: %s, type is wrong",
279                             tvb_bytes_to_str(tvb, offset, count));
280                 }
281         }
282         offset += count;
283         return offset;
284 }
285
286 static int
287 add_pad_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
288     proto_tree *tree, int convert, int hf_index)
289 {
290         /*
291          * This is for parameters that have descriptor entries but that
292          * are, in practice, just padding.
293          */
294         offset += count;
295         return offset;
296 }
297
298 static void
299 add_null_pointer_param(tvbuff_t *tvb, int offset, int count,
300     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
301 {
302         if (hf_index != -1) {
303                 proto_tree_add_text(tree, tvb, offset, 0,
304                   "%s (Null pointer)",
305                   proto_registrar_get_name(hf_index));
306         } else {
307                 proto_tree_add_text(tree, tvb, offset, 0,
308                     "String Param (Null pointer)");
309         }
310 }
311
312 static int
313 add_string_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
314     proto_tree *tree, int convert, int hf_index)
315 {
316         guint string_len;
317
318         string_len = tvb_strsize(tvb, offset);
319         if (hf_index != -1) {
320                 proto_tree_add_item(tree, hf_index, tvb, offset, string_len,
321                     TRUE);
322         } else {
323                 proto_tree_add_text(tree, tvb, offset, string_len,
324                     "String Param: %s",
325                     tvb_format_text(tvb, offset, string_len));
326         }
327         offset += string_len;
328         return offset;
329 }
330
331 static const char *
332 get_pointer_value(tvbuff_t *tvb, int offset, int convert, int *cptrp, int *lenp)
333 {
334         int cptr;
335         gint string_len;
336
337         /* pointer to string */
338         cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
339         *cptrp = cptr;
340
341         /* string */
342         if (tvb_offset_exists(tvb, cptr) &&
343             (string_len = tvb_strnlen(tvb, cptr, -1)) != -1) {
344                 string_len++;   /* include the terminating '\0' */
345                 *lenp = string_len;
346                 return tvb_format_text(tvb, cptr, string_len - 1);
347         } else
348                 return NULL;
349 }
350
351 static int
352 add_pointer_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
353     proto_tree *tree, int convert, int hf_index)
354 {
355         int cptr;
356         const char *string;
357         gint string_len;
358
359         string = get_pointer_value(tvb, offset, convert, &cptr, &string_len);
360         offset += 4;
361
362         /* string */
363         if (string != NULL) {
364                 if (hf_index != -1) {
365                         proto_tree_add_item(tree, hf_index, tvb, cptr,
366                             string_len, TRUE);
367                 } else {
368                         proto_tree_add_text(tree, tvb, cptr, string_len,
369                             "String Param: %s", string);
370                 }
371         } else {
372                 if (hf_index != -1) {
373                         proto_tree_add_text(tree, tvb, 0, 0,
374                             "%s: <String goes past end of frame>",
375                             proto_registrar_get_name(hf_index));
376                 } else {
377                         proto_tree_add_text(tree, tvb, 0, 0,
378                             "String Param: <String goes past end of frame>");
379                 }
380         }
381
382         return offset;
383 }
384
385 static int
386 add_detail_level(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
387     proto_tree *tree, int convert, int hf_index)
388 {
389         struct smb_info *smb_info = pinfo->private_data;
390         smb_transact_info_t *trp = smb_info->sip->extra_info;
391         guint16 level;
392
393         level = tvb_get_letohs(tvb, offset);
394         if (!pinfo->fd->flags.visited)
395                 trp->info_level = level;        /* remember this for the response */
396         proto_tree_add_uint(tree, hf_index, tvb, offset, 2, level);
397         offset += 2;
398         return offset;
399 }
400
401 static int
402 add_max_uses(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
403     proto_tree *tree, int convert, int hf_index)
404 {
405         guint16 WParam;
406
407         WParam = tvb_get_letohs(tvb, offset);
408         if (WParam == 0xffff) { /* -1 */
409                 proto_tree_add_uint_format(tree, hf_index, tvb,
410                     offset, 2, WParam,
411                     "%s: No limit",
412                     proto_registrar_get_name(hf_index));
413         } else {
414                 proto_tree_add_uint(tree, hf_index, tvb,
415                             offset, 2, WParam);
416         }
417         offset += 2;
418         return offset;
419 }
420
421 static int
422 add_server_type(tvbuff_t *tvb, int offset, int count,
423     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
424 {
425         dissect_smb_server_type_flags(tvb, pinfo, tree, offset, FALSE);
426         offset += 4;
427         return offset;
428 }
429
430 static int
431 add_server_type_info(tvbuff_t *tvb, int offset, int count,
432     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
433 {
434         dissect_smb_server_type_flags(tvb, pinfo, tree, offset, TRUE);
435         offset += 4;
436         return offset;
437 }
438
439 static int
440 add_reltime(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
441     proto_tree *tree, int convert, int hf_index)
442 {
443         nstime_t nstime;
444
445         nstime.secs = tvb_get_letohl(tvb, offset);
446         nstime.nsecs = 0;
447         proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
448             &nstime, "%s: %s", proto_registrar_get_name(hf_index),
449             time_secs_to_str(nstime.secs));
450         offset += 4;
451         return offset;
452 }
453
454 /*
455  * Sigh.  These are for handling Microsoft's annoying almost-UNIX-time-but-
456  * it's-local-time-not-UTC time.
457  */
458 static int
459 add_abstime_common(tvbuff_t *tvb, int offset, int count,
460     packet_info *pinfo, proto_tree *tree, int convert, int hf_index,
461     const char *absent_name)
462 {
463         nstime_t nstime;
464         struct tm *tmp;
465
466         nstime.secs = tvb_get_letohl(tvb, offset);
467         nstime.nsecs = 0;
468         if (nstime.secs == -1) {
469                 proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
470                     &nstime, "%s: %s", proto_registrar_get_name(hf_index),
471                     absent_name);
472         } else {
473                 /*
474                  * Run it through "gmtime()" to break it down, and then
475                  * run it through "mktime()" to put it back together
476                  * as UTC.
477                  */
478                 tmp = gmtime(&nstime.secs);
479                 tmp->tm_isdst = -1;     /* we don't know if it's DST or not */
480                 nstime.secs = mktime(tmp);
481                 proto_tree_add_time(tree, hf_index, tvb, offset, 4,
482                     &nstime);
483         }
484         offset += 4;
485         return offset;
486 }
487
488 static int
489 add_abstime_absent_never(tvbuff_t *tvb, int offset, int count,
490     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
491 {
492         return add_abstime_common(tvb, offset, count, pinfo, tree,
493             convert, hf_index, "Never");
494 }
495
496 static int
497 add_abstime_absent_unknown(tvbuff_t *tvb, int offset, int count,
498     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
499 {
500         return add_abstime_common(tvb, offset, count, pinfo, tree,
501             convert, hf_index, "Unknown");
502 }
503
504 static int
505 add_nlogons(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
506     proto_tree *tree, int convert, int hf_index)
507 {
508         guint16 nlogons;
509
510         nlogons = tvb_get_letohs(tvb, offset);
511         if (nlogons == 0xffff)  /* -1 */
512                 proto_tree_add_uint_format(tree, hf_index, tvb, offset, 2,
513                     nlogons, "%s: Unknown",
514                     proto_registrar_get_name(hf_index));
515         else
516                 proto_tree_add_uint(tree, hf_index, tvb, offset, 2,
517                     nlogons);
518         offset += 2;
519         return offset;
520 }
521
522 static int
523 add_max_storage(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
524     proto_tree *tree, int convert, int hf_index)
525 {
526         guint32 max_storage;
527
528         max_storage = tvb_get_letohl(tvb, offset);
529         if (max_storage == 0xffffffff)
530                 proto_tree_add_uint_format(tree, hf_index, tvb, offset, 4,
531                     max_storage, "%s: No limit",
532                     proto_registrar_get_name(hf_index));
533         else
534                 proto_tree_add_uint(tree, hf_index, tvb, offset, 4,
535                     max_storage);
536         offset += 4;
537         return offset;
538 }
539
540 static int
541 add_logon_hours(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
542     proto_tree *tree, int convert, int hf_index)
543 {
544         int cptr;
545
546         /* pointer to string */
547         cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
548         offset += 4;
549
550         /* string */
551         /* XXX - should actually carve up the bits */
552         proto_tree_add_item(tree, hf_index, tvb, cptr, 21, TRUE);
553
554         return offset;
555 }
556
557 static int
558 add_tzoffset(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
559     proto_tree *tree, int convert, int hf_index)
560 {
561         gint16 tzoffset;
562
563         tzoffset = tvb_get_letohs(tvb, offset);
564         if (tzoffset < 0) {
565                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
566                     tzoffset, "%s: %s east of UTC",
567                     proto_registrar_get_name(hf_index),
568                     time_secs_to_str(-tzoffset*60));
569         } else if (tzoffset > 0) {
570                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
571                     tzoffset, "%s: %s west of UTC",
572                     proto_registrar_get_name(hf_index),
573                     time_secs_to_str(tzoffset*60));
574         } else {
575                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
576                     tzoffset, "%s: at UTC",
577                     proto_registrar_get_name(hf_index));
578         }
579         offset += 2;
580         return offset;
581 }
582
583 static int
584 add_timeinterval(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
585     proto_tree *tree, int convert, int hf_index)
586 {
587         guint16 timeinterval;
588
589         timeinterval = tvb_get_letohs(tvb, offset);
590         proto_tree_add_uint_format(tree, hf_timeinterval, tvb, offset, 2,
591            timeinterval, "%s: %f seconds", proto_registrar_get_name(hf_index),
592            timeinterval*.0001);
593         offset += 2;
594         return offset;
595 }
596
597 static int
598 add_logon_args(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
599     proto_tree *tree, int convert, int hf_index)
600 {
601         if (count != 54) {
602                 proto_tree_add_text(tree, tvb, offset, count,
603                    "Bogus NetWkstaUserLogon parameters: length is %d, should be 54",
604                    count);
605                 offset += count;
606                 return offset;
607         }
608
609         /* user name */
610         proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
611         offset += 21;
612
613         /* pad1 */
614         offset += 1;
615
616         /* password */
617         proto_tree_add_item(tree, hf_password, tvb, offset, 15, TRUE);
618         offset += 15;
619
620         /* pad2 */
621         offset += 1;
622
623         /* workstation name */
624         proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE);
625         offset += 16;
626         return offset;
627 }
628
629 /* 
630  * The following data structure describes the Remote API requests we
631  * understand.
632  *
633  * Simply fill in the number and parameter information.
634  * Try to keep them in order.
635  *
636  * We will extend this data structure as we try to decode more.
637  */
638
639 /*
640  * This is a pointer to a function to process an item.
641  */
642 typedef int     (*item_func)(tvbuff_t *, int, int, packet_info *, proto_tree *,
643                              int, int);
644
645 /*
646  * Type of an item; determines what parameter strings are valid for
647  * the item.
648  */
649 typedef enum {
650         PARAM_NONE,     /* for the end-of-list stopper */
651         PARAM_WORD,     /* 'W' or 'h' - 16-bit word */
652         PARAM_DWORD,    /* 'D' or 'i' - 32-bit word */
653         PARAM_BYTES,    /* 'B' or 'b' or 'g' or 'O' - one or more bytes */
654         PARAM_STRINGZ,  /* 'z' or 'O' - null-terminated string */
655 } param_type_t;
656
657 /*
658  * This structure describes an item; "hf_index" points to the index
659  * for the field corresponding to that item, "func" points to the
660  * function to use to add that item to the tree, and "type" is the
661  * type that the item is supposed to have.
662  */
663 typedef struct {
664         int             *hf_index;
665         item_func       func;
666         param_type_t    type;
667 } item_t;
668
669 /*
670  * This structure describes a list of items; each list of items
671  * has a corresponding detail level.
672  */
673 typedef struct {
674         int             level;
675         const item_t    *item_list;
676 } item_list_t;
677
678 struct lanman_desc {
679         int             lanman_num;
680         const item_t    *req;
681         proto_item      *(*req_data_item)(tvbuff_t *, packet_info *,
682                                           proto_tree *, int);
683         gint            *ett_req_data;
684         const item_t    *req_data;
685         const item_t    *req_aux_data;
686         const item_t    *resp;
687         proto_item      *(*resp_data_item)(tvbuff_t *, packet_info *,
688                                            proto_tree *, int);
689         gint            *ett_resp_data;
690         proto_item      *(*resp_data_element_item)(tvbuff_t *, packet_info *,
691                                                    proto_tree *, int);
692         gint            *ett_resp_data_element_item;
693         const item_list_t *resp_data_list;
694         const item_t    *resp_aux_data;
695 };
696
697 static int no_hf = -1;  /* for padding crap */
698
699 static const item_t lm_params_req_netshareenum[] = {
700         { &hf_detail_level, add_detail_level, PARAM_WORD },
701         { &hf_recv_buf_len, add_word_param, PARAM_WORD },
702         { NULL, NULL, PARAM_NONE }
703 };
704
705 static const item_t lm_params_resp_netshareenum[] = {
706         { &hf_acount, add_word_param, PARAM_WORD },
707         { NULL, NULL, PARAM_NONE }
708 };
709
710 /*
711  * Create a subtree for all available shares.
712  */
713 static proto_item *
714 netshareenum_shares_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
715     int offset)
716 {
717         if (tree) {
718                 return proto_tree_add_text(tree, tvb, offset, -1,
719                     "Available Shares");
720         } else
721                 return NULL;
722 }
723
724 /*
725  * Create a subtree for a share.
726  */
727 static proto_item *
728 netshareenum_share_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
729     int offset)
730 {
731         if (tree) {
732                 return proto_tree_add_text(tree, tvb, offset, -1,
733                     "Share %.13s", tvb_get_ptr(tvb, offset, 13));
734         } else
735                 return NULL;
736 }
737
738 static const item_t lm_null[] = {
739         { NULL, NULL, PARAM_NONE }
740 };
741
742 static const item_list_t lm_null_list[] = {
743         { 0, lm_null }
744 };
745
746 static const item_t lm_data_resp_netshareenum_1[] = {
747         { &hf_share_name, add_byte_param, PARAM_BYTES },
748         { &no_hf, add_pad_param, PARAM_BYTES },
749         { &hf_share_type, add_word_param, PARAM_WORD },
750         { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
751         { NULL, NULL, PARAM_NONE }
752 };
753
754 static const item_list_t lm_data_resp_netshareenum[] = {
755         { 1, lm_data_resp_netshareenum_1 },
756         { -1, lm_null }
757 };
758
759 static const item_t lm_params_req_netsharegetinfo[] = {
760         { &hf_share_name, add_string_param, PARAM_STRINGZ },
761         { &hf_detail_level, add_detail_level, PARAM_WORD },
762         { NULL, NULL, PARAM_NONE }
763 };
764
765 static const item_t lm_params_resp_netsharegetinfo[] = {
766         { &hf_abytes, add_word_param, PARAM_WORD },
767         { NULL, NULL, PARAM_NONE }
768 };
769
770 static const item_t lm_data_resp_netsharegetinfo_0[] = {
771         { &hf_share_name, add_byte_param, PARAM_BYTES },
772         { NULL, NULL, PARAM_NONE }
773 };
774
775 static const item_t lm_data_resp_netsharegetinfo_1[] = {
776         { &hf_share_name, add_byte_param, PARAM_BYTES },
777         { &no_hf, add_pad_param, PARAM_BYTES },
778         { &hf_share_type, add_word_param, PARAM_WORD },
779         { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
780         { NULL, NULL, PARAM_NONE }
781 };
782
783 static const item_t lm_data_resp_netsharegetinfo_2[] = {
784         { &hf_share_name, add_byte_param, PARAM_BYTES },
785         { &no_hf, add_pad_param, PARAM_BYTES },
786         { &hf_share_type, add_word_param, PARAM_WORD },
787         { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
788         { &hf_share_permissions, add_word_param, PARAM_WORD }, /* XXX - do as bit fields */
789         { &hf_share_max_uses, add_max_uses, PARAM_WORD },
790         { &hf_share_current_uses, add_word_param, PARAM_WORD },
791         { &hf_share_path, add_pointer_param, PARAM_STRINGZ },
792         { &hf_share_password, add_byte_param, PARAM_BYTES },
793         { NULL, NULL, PARAM_NONE }
794 };
795
796 static const item_list_t lm_data_resp_netsharegetinfo[] = {
797         { 0, lm_data_resp_netsharegetinfo_0 },
798         { 1, lm_data_resp_netsharegetinfo_1 },
799         { 2, lm_data_resp_netsharegetinfo_2 },
800         { -1, lm_null }
801 };
802
803 static const item_t lm_params_req_netservergetinfo[] = {
804         { &hf_detail_level, add_detail_level, PARAM_WORD },
805         { NULL, NULL, PARAM_NONE }
806 };
807
808 static const item_t lm_params_resp_netservergetinfo[] = {
809         { &hf_abytes, add_word_param, PARAM_WORD },
810         { NULL, NULL, PARAM_NONE }
811 };
812
813 static const item_t lm_data_serverinfo_0[] = {
814         { &hf_server_name, add_byte_param, PARAM_BYTES },
815         { NULL, NULL, PARAM_NONE }
816 };
817
818 static const item_t lm_data_serverinfo_1[] = {
819         { &hf_server_name, add_byte_param, PARAM_BYTES },
820         { &hf_server_major, add_byte_param, PARAM_BYTES },
821         { &hf_server_minor, add_byte_param, PARAM_BYTES },
822         { &no_hf, add_server_type, PARAM_DWORD },
823         { &hf_server_comment, add_pointer_param, PARAM_STRINGZ },
824         { NULL, NULL, PARAM_NONE }
825 };
826
827 static const item_list_t lm_data_serverinfo[] = {
828         { 0, lm_data_serverinfo_0 },
829         { 1, lm_data_serverinfo_1 },
830         { -1, lm_null }
831 };
832
833 static const item_t lm_params_req_netusergetinfo[] = {
834         { &hf_detail_level, add_detail_level, PARAM_WORD },
835         { NULL, NULL, PARAM_NONE }
836 };
837
838 static const item_t lm_params_resp_netusergetinfo[] = {
839         { &hf_abytes, add_word_param, PARAM_WORD },
840         { NULL, NULL, PARAM_NONE }
841 };
842
843 static const item_t lm_data_resp_netusergetinfo_11[] = {
844         { &hf_user_name, add_byte_param, PARAM_BYTES },
845         { &no_hf, add_pad_param, PARAM_BYTES },
846         { &hf_user_comment, add_pointer_param, PARAM_STRINGZ },
847         { &hf_full_name, add_pointer_param, PARAM_STRINGZ },
848         { &hf_privilege_level, add_word_param, PARAM_WORD },
849         { &hf_operator_privileges, add_dword_param, PARAM_DWORD },
850         { &hf_password_age, add_reltime, PARAM_DWORD },
851         { &hf_homedir, add_pointer_param, PARAM_STRINGZ },
852         { &hf_parameters, add_pointer_param, PARAM_STRINGZ },
853         { &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
854         { &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
855         { &hf_bad_pw_count, add_word_param, PARAM_WORD },
856         { &hf_num_logons, add_nlogons, PARAM_WORD },
857         { &hf_logon_server, add_pointer_param, PARAM_STRINGZ },
858         { &hf_country_code, add_word_param, PARAM_WORD },
859         { &hf_workstations, add_pointer_param, PARAM_STRINGZ },
860         { &hf_max_storage, add_max_storage, PARAM_DWORD },
861         { &hf_logon_hours, add_logon_hours, PARAM_DWORD },
862         { &hf_code_page, add_word_param, PARAM_WORD },
863         { NULL, NULL, PARAM_NONE }
864 };
865
866 static const item_list_t lm_data_resp_netusergetinfo[] = {
867         { 11, lm_data_resp_netusergetinfo_11 },
868         { -1, lm_null }
869 };
870
871 /*
872  * Has no detail level; make it the default.
873  */
874 static const item_t lm_data_resp_netremotetod_nolevel[] = {
875         { &hf_current_time, add_abstime_absent_unknown, PARAM_DWORD },
876         { &hf_msecs, add_dword_param, PARAM_DWORD },
877         { &hf_hour, add_byte_param, PARAM_BYTES },
878         { &hf_minute, add_byte_param, PARAM_BYTES },
879         { &hf_second, add_byte_param, PARAM_BYTES },
880         { &hf_hundredths, add_byte_param, PARAM_BYTES },
881         { &hf_tzoffset, add_tzoffset, PARAM_WORD },
882         { &hf_timeinterval, add_timeinterval, PARAM_WORD },
883         { &hf_day, add_byte_param, PARAM_BYTES },
884         { &hf_month, add_byte_param, PARAM_BYTES },
885         { &hf_year, add_word_param, PARAM_WORD },
886         { &hf_weekday, add_byte_param, PARAM_BYTES },
887         { NULL, NULL, PARAM_NONE }
888 };
889
890 static const item_list_t lm_data_resp_netremotetod[] = {
891         { -1, lm_data_resp_netremotetod_nolevel },
892 };
893
894 static const item_t lm_params_req_netserverenum2[] = {
895         { &hf_detail_level, add_detail_level, PARAM_WORD },
896         { &no_hf, add_server_type_info, PARAM_DWORD },
897         { &hf_enumeration_domain, add_string_param, PARAM_STRINGZ },
898         { NULL, NULL, PARAM_NONE }
899 };
900
901 /*
902  * Create a subtree for all servers.
903  */
904 static proto_item *
905 netserverenum2_servers_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
906     int offset)
907 {
908         if (tree) {
909                 return proto_tree_add_text(tree, tvb, offset, -1,
910                     "Servers");
911         } else
912                 return NULL;
913 }
914
915 /*
916  * Create a subtree for a share.
917  */
918 static proto_item *
919 netserverenum2_server_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
920     int offset)
921 {
922         if (tree) {
923                 return proto_tree_add_text(tree, tvb, offset, -1,
924                             "Server %.16s", tvb_get_ptr(tvb, offset, 16));
925         } else
926                 return NULL;
927 }
928 static const item_t lm_params_resp_netserverenum2[] = {
929         { &hf_acount, add_word_param, PARAM_WORD },
930         { NULL, NULL, PARAM_NONE }
931 };
932
933 static const item_t lm_params_req_netwkstagetinfo[] = {
934         { &hf_detail_level, add_detail_level, PARAM_WORD },
935         { NULL, NULL, PARAM_NONE }
936 };
937
938 static const item_t lm_params_resp_netwkstagetinfo[] = {
939         { &hf_abytes, add_word_param, PARAM_WORD },
940         { NULL, NULL, PARAM_NONE }
941 };
942
943 static const item_t lm_data_resp_netwkstagetinfo_10[] = {
944         { &hf_computer_name, add_pointer_param, PARAM_STRINGZ },
945         { &hf_user_name, add_pointer_param, PARAM_STRINGZ },
946         { &hf_workstation_domain, add_pointer_param, PARAM_STRINGZ },
947         { &hf_workstation_major, add_byte_param, PARAM_BYTES },
948         { &hf_workstation_minor, add_byte_param, PARAM_BYTES },
949         { &hf_logon_domain, add_pointer_param, PARAM_STRINGZ },
950         { &hf_other_domains, add_pointer_param, PARAM_STRINGZ },
951         { NULL, NULL, PARAM_NONE }
952 };
953
954 static const item_list_t lm_data_resp_netwkstagetinfo[] = {
955         { 10, lm_data_resp_netwkstagetinfo_10 },
956         { -1, lm_null }
957 };
958
959 static const item_t lm_params_req_netwkstauserlogon[] = {
960         { &no_hf, add_pointer_param, PARAM_STRINGZ },
961         { &no_hf, add_pointer_param, PARAM_STRINGZ },
962         { &hf_detail_level, add_detail_level, PARAM_WORD },
963         { &no_hf, add_logon_args, PARAM_BYTES },
964         { &hf_ustruct_size, add_word_param, PARAM_WORD },
965         { NULL, NULL, PARAM_NONE }
966 };
967
968 static const item_t lm_params_resp_netwkstauserlogon[] = {
969         { &hf_abytes, add_word_param, PARAM_WORD },
970         { NULL, NULL, PARAM_NONE }
971 };
972
973 static const item_t lm_data_resp_netwkstauserlogon_1[] = {
974         { &hf_logon_code, add_word_param, PARAM_WORD },
975         { &hf_user_name, add_byte_param, PARAM_BYTES },
976         { &no_hf, add_pad_param, PARAM_BYTES },
977         { &hf_privilege_level, add_word_param, PARAM_WORD },
978         { &hf_operator_privileges, add_dword_param, PARAM_DWORD },
979         { &hf_num_logons, add_nlogons, PARAM_WORD },
980         { &hf_bad_pw_count, add_word_param, PARAM_WORD },
981         { &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
982         { &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
983         { &hf_logoff_time, add_abstime_absent_never, PARAM_DWORD },
984         { &hf_kickoff_time, add_abstime_absent_never, PARAM_DWORD },
985         { &hf_password_age, add_reltime, PARAM_DWORD },
986         { &hf_password_can_change, add_abstime_absent_never, PARAM_DWORD },
987         { &hf_password_must_change, add_abstime_absent_never, PARAM_DWORD },
988         { &hf_server_name, add_pointer_param, PARAM_STRINGZ },
989         { &hf_logon_domain, add_pointer_param, PARAM_STRINGZ },
990         { &hf_script_path, add_pointer_param, PARAM_STRINGZ },
991         { &hf_reserved, add_dword_param, PARAM_DWORD },
992         { NULL, NULL, PARAM_NONE }
993 };
994
995 static const item_list_t lm_data_resp_netwkstauserlogon[] = {
996         { 1, lm_data_resp_netwkstauserlogon_1 },
997         { -1, lm_null }
998 };
999
1000 static const item_t lm_params_req_netwkstauserlogoff[] = {
1001         { &hf_user_name, add_byte_param, PARAM_BYTES },
1002         { &no_hf, add_pad_param, PARAM_BYTES },
1003         { &hf_workstation_name, add_byte_param, PARAM_BYTES },
1004         { NULL, NULL, PARAM_NONE }
1005 };
1006
1007 static const item_t lm_params_resp_netwkstauserlogoff[] = {
1008         { &hf_abytes, add_word_param, PARAM_WORD },
1009         { NULL, NULL, PARAM_NONE }
1010 };
1011
1012 static const item_t lm_data_resp_netwkstauserlogoff_1[] = {
1013         { &hf_logoff_code, add_word_param, PARAM_WORD },
1014         { &hf_duration, add_reltime, PARAM_DWORD },
1015         { &hf_num_logons, add_nlogons, PARAM_WORD },
1016         { NULL, NULL, PARAM_NONE }
1017 };
1018
1019 static const item_list_t lm_data_resp_netwkstauserlogoff[] = {
1020         { 1, lm_data_resp_netwkstauserlogoff_1 },
1021         { -1, lm_null }
1022 };
1023
1024 static const item_t lm_params_req_samoemchangepassword[] = {
1025         { &hf_user_name, add_string_param, PARAM_STRINGZ },
1026         { NULL, NULL, PARAM_NONE }
1027 };
1028
1029 static const item_t lm_data_req_samoemchangepassword[] = {
1030         { &hf_new_password, add_byte_param, PARAM_BYTES },
1031         { &hf_old_password, add_byte_param, PARAM_BYTES },
1032         { NULL, NULL, PARAM_NONE }
1033 };
1034
1035 #define LANMAN_NETSHAREENUM             0
1036 #define LANMAN_NETSHAREGETINFO          1
1037 #define LANMAN_NETSERVERGETINFO         13
1038 #define LANMAN_NETGROUPGETUSERS         52
1039 #define LANMAN_NETUSERGETINFO           56
1040 #define LANMAN_NETUSERGETGROUPS         59
1041 #define LANMAN_NETWKSTAGETINFO          63
1042 #define LANMAN_DOSPRINTQENUM            69
1043 #define LANMAN_DOSPRINTQGETINFO         70
1044 #define LANMAN_WPRINTQUEUEPAUSE         74
1045 #define LANMAN_WPRINTQUEUERESUME        75
1046 #define LANMAN_WPRINTJOBENUMERATE       76
1047 #define LANMAN_WPRINTJOBGETINFO         77
1048 #define LANMAN_RDOSPRINTJOBDEL          81
1049 #define LANMAN_RDOSPRINTJOBPAUSE        82
1050 #define LANMAN_RDOSPRINTJOBRESUME       83
1051 #define LANMAN_WPRINTDESTENUM           84
1052 #define LANMAN_WPRINTDESTGETINFO        85
1053 #define LANMAN_NETREMOTETOD             91
1054 #define LANMAN_WPRINTQUEUEPURGE         103
1055 #define LANMAN_NETSERVERENUM2           104
1056 #define LANMAN_WACCESSGETUSERPERMS      105
1057 #define LANMAN_SETUSERPASSWORD          115
1058 #define LANMAN_NETWKSTAUSERLOGON        132
1059 #define LANMAN_NETWKSTAUSERLOGOFF       133
1060 #define LANMAN_PRINTJOBINFO             147
1061 #define LANMAN_WPRINTDRIVERENUM         205
1062 #define LANMAN_WPRINTQPROCENUM          206
1063 #define LANMAN_WPRINTPORTENUM           207
1064 #define LANMAN_SAMOEMCHANGEPASSWORD     214
1065
1066 static const struct lanman_desc lmd[] = {
1067         { LANMAN_NETSHAREENUM,
1068           lm_params_req_netshareenum,
1069           NULL,
1070           NULL,
1071           lm_null,
1072           lm_null,
1073           lm_params_resp_netshareenum,
1074           netshareenum_shares_list,
1075           &ett_lanman_shares,
1076           netshareenum_share_entry,
1077           &ett_lanman_share,
1078           lm_data_resp_netshareenum,
1079           lm_null },
1080
1081         { LANMAN_NETSHAREGETINFO,
1082           lm_params_req_netsharegetinfo,
1083           NULL,
1084           NULL,
1085           lm_null,
1086           lm_null,
1087           lm_params_resp_netsharegetinfo,
1088           NULL,
1089           NULL,
1090           NULL,
1091           NULL,
1092           lm_data_resp_netsharegetinfo,
1093           lm_null },
1094
1095         { LANMAN_NETSERVERGETINFO, 
1096           lm_params_req_netservergetinfo,
1097           NULL,
1098           NULL,
1099           lm_null,
1100           lm_null,
1101           lm_params_resp_netservergetinfo,
1102           NULL,
1103           NULL,
1104           NULL,
1105           NULL,
1106           lm_data_serverinfo,
1107           lm_null },
1108
1109         { LANMAN_NETUSERGETINFO,
1110           lm_params_req_netusergetinfo,
1111           NULL,
1112           NULL,
1113           lm_null,
1114           lm_null,
1115           lm_params_resp_netusergetinfo,
1116           NULL,
1117           NULL,
1118           NULL,
1119           NULL,
1120           lm_data_resp_netusergetinfo,
1121           lm_null },
1122
1123         { LANMAN_NETREMOTETOD,
1124           lm_null,
1125           NULL,
1126           NULL,
1127           lm_null,
1128           lm_null,
1129           lm_null,
1130           NULL,
1131           NULL,
1132           NULL,
1133           NULL,
1134           lm_data_resp_netremotetod,
1135           lm_null },
1136
1137         { LANMAN_NETSERVERENUM2,
1138           lm_params_req_netserverenum2,
1139           NULL,
1140           NULL,
1141           lm_null,
1142           lm_null,
1143           lm_params_resp_netserverenum2,
1144           netserverenum2_servers_list,
1145           &ett_lanman_servers,
1146           netserverenum2_server_entry,
1147           &ett_lanman_server,
1148           lm_data_serverinfo,
1149           lm_null },
1150
1151         { LANMAN_NETWKSTAGETINFO,
1152           lm_params_req_netwkstagetinfo,
1153           NULL,
1154           NULL,
1155           lm_null,
1156           lm_null,
1157           lm_params_resp_netwkstagetinfo,
1158           NULL,
1159           NULL,
1160           NULL,
1161           NULL,
1162           lm_data_resp_netwkstagetinfo,
1163           lm_null },
1164
1165         { LANMAN_NETWKSTAUSERLOGON,
1166           lm_params_req_netwkstauserlogon,
1167           NULL,
1168           NULL,
1169           lm_null,
1170           lm_null,
1171           lm_params_resp_netwkstauserlogon,
1172           NULL,
1173           NULL,
1174           NULL,
1175           NULL,
1176           lm_data_resp_netwkstauserlogon,
1177           lm_null },
1178
1179         { LANMAN_NETWKSTAUSERLOGOFF,
1180           lm_params_req_netwkstauserlogoff,
1181           NULL,
1182           NULL,
1183           lm_null,
1184           lm_null,
1185           lm_params_resp_netwkstauserlogoff,
1186           NULL,
1187           NULL,
1188           NULL,
1189           NULL,
1190           lm_data_resp_netwkstauserlogoff,
1191           lm_null },
1192
1193         { LANMAN_SAMOEMCHANGEPASSWORD,
1194           lm_params_req_samoemchangepassword,
1195           NULL,
1196           NULL,
1197           lm_data_req_samoemchangepassword,
1198           lm_null,
1199           lm_null,
1200           NULL,
1201           NULL,
1202           NULL,
1203           NULL,
1204           lm_null_list,
1205           lm_null },
1206
1207         { -1,
1208           lm_null,
1209           NULL,
1210           NULL,
1211           lm_null,
1212           lm_null,
1213           lm_null,
1214           NULL,
1215           NULL,
1216           NULL,
1217           NULL,
1218           lm_null_list,
1219           lm_null }
1220 };
1221
1222 static const struct lanman_desc *
1223 find_lanman(int lanman_num)
1224 {
1225         int i;
1226
1227         for (i = 0; lmd[i].lanman_num != -1; i++) {
1228                 if (lmd[i].lanman_num == lanman_num)
1229                         break;
1230         }
1231         return &lmd[i];
1232 }
1233
1234 static const guchar *
1235 get_count(const guchar *desc, int *countp)
1236 {
1237         int count = 0;
1238         guchar c;
1239
1240         if (!isdigit(*desc)) {
1241                 *countp = 1;    /* no count was supplied */
1242                 return desc;
1243         }
1244
1245         while ((c = *desc) != '\0' && isdigit(c)) {
1246                 count = (count * 10) + c - '0';
1247                 desc++;
1248         }
1249
1250         *countp = count;        /* XXX - what if it's 0? */
1251         return desc;
1252 }
1253
1254 static int
1255 dissect_request_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
1256     proto_tree *tree, const guchar *desc, const item_t *items,
1257     gboolean *has_data_p)
1258 {
1259         guint c;
1260         guint16 WParam;
1261         guint32 LParam;
1262         guint string_len;
1263         int count;
1264
1265         *has_data_p = FALSE;
1266         while ((c = *desc++) != '\0') {
1267                 switch (c) {
1268
1269                 case 'W':
1270                         /*
1271                          * A 16-bit word value in the request.
1272                          */
1273                         if (items->func == NULL) {
1274                                 /*
1275                                  * We've run out of items in the table;
1276                                  * fall back on the default.
1277                                  */
1278                                 offset = add_word_param(tvb, offset, 0, pinfo,
1279                                     tree, 0, -1);
1280                         } else if (items->type != PARAM_WORD) {
1281                                 /*
1282                                  * Descriptor character is 'W', but this
1283                                  * isn't a word parameter.
1284                                  */
1285                                 WParam = tvb_get_letohs(tvb, offset);
1286                                 proto_tree_add_text(tree, tvb, offset, 2,
1287                                     "%s: Value is %u (0x%04X), type is wrong (W)",
1288                                     (*items->hf_index == -1) ?
1289                                       "Word Param" :
1290                                       proto_registrar_get_name(*items->hf_index),
1291                                     WParam, WParam);
1292                                 offset += 2;
1293                                 items++;
1294                         } else {
1295                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1296                                     tree, 0, *items->hf_index);
1297                                 items++;
1298                         }
1299                         break;
1300
1301                 case 'D':
1302                         /*
1303                          * A 32-bit doubleword value in the request.
1304                          */
1305                         if (items->func == NULL) {
1306                                 /*
1307                                  * We've run out of items in the table;
1308                                  * fall back on the default.
1309                                  */
1310                                 offset = add_dword_param(tvb, offset, 0, pinfo,
1311                                     tree, 0, -1);
1312                         } else if (items->type != PARAM_DWORD) {
1313                                 /*
1314                                  * Descriptor character is 'D', but this
1315                                  * isn't a doubleword parameter.
1316                                  */
1317                                 LParam = tvb_get_letohl(tvb, offset);
1318                                 proto_tree_add_text(tree, tvb, offset, 2,
1319                                     "%s: Value is %u (0x%08X), type is wrong (D)",
1320                                     (*items->hf_index == -1) ?
1321                                       "Doubleword Param" :
1322                                       proto_registrar_get_name(*items->hf_index),
1323                                     LParam, LParam);
1324                                 offset += 4;
1325                                 items++;
1326                         } else {
1327                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1328                                     tree, 0, *items->hf_index);
1329                                 items++;
1330                         }
1331                         break;
1332
1333                 case 'b':
1334                         /*
1335                          * A byte or multi-byte value in the request.
1336                          */
1337                         desc = get_count(desc, &count);
1338                         if (items->func == NULL) {
1339                                 /*
1340                                  * We've run out of items in the table;
1341                                  * fall back on the default.
1342                                  */
1343                                 offset = add_byte_param(tvb, offset, count,
1344                                     pinfo, tree, 0, -1);
1345                         } else if (items->type != PARAM_BYTES) {
1346                                 /*
1347                                  * Descriptor character is 'b', but this
1348                                  * isn't a byte/bytes parameter.
1349                                  */
1350                                 proto_tree_add_text(tree, tvb, offset, count,
1351                                     "%s: Value is %s, type is wrong (b)",
1352                                     (*items->hf_index == -1) ?
1353                                       "Byte Param" :
1354                                       proto_registrar_get_name(*items->hf_index),
1355                                     tvb_bytes_to_str(tvb, offset, count));
1356                                 offset += count;
1357                                 items++;
1358                         } else {
1359                                 offset = (*items->func)(tvb, offset, count,
1360                                     pinfo, tree, 0, *items->hf_index);
1361                                 items++;
1362                         }
1363                         break;
1364
1365                 case 'O':
1366                         /*
1367                          * A null pointer.
1368                          */
1369                         if (items->func == NULL) {
1370                                 /*
1371                                  * We've run out of items in the table;
1372                                  * fall back on the default.
1373                                  */
1374                                 add_null_pointer_param(tvb, offset, 0,
1375                                     pinfo, tree, 0, -1);
1376                         } else {
1377                                 /*
1378                                  * If "*items->hf_index" is -1, this is
1379                                  * a reserved must-be-null field; don't
1380                                  * clutter the protocol tree by putting
1381                                  * it in.
1382                                  */
1383                                 if (*items->hf_index != -1) {
1384                                         add_null_pointer_param(tvb,
1385                                             offset, 0, pinfo, tree, 0,
1386                                             *items->hf_index);
1387                                 }
1388                                 items++;
1389                         }
1390                         break;
1391
1392                 case 'z':
1393                         /*
1394                          * A null-terminated ASCII string.
1395                          */
1396                         if (items->func == NULL) {
1397                                 /*
1398                                  * We've run out of items in the table;
1399                                  * fall back on the default.
1400                                  */
1401                                 offset = add_string_param(tvb, offset, 0,
1402                                     pinfo, tree, 0, -1);
1403                         } else if (items->type != PARAM_STRINGZ) {
1404                                 /*
1405                                  * Descriptor character is 'z', but this
1406                                  * isn't a string parameter.
1407                                  */
1408                                 string_len = tvb_strsize(tvb, offset);
1409                                 proto_tree_add_text(tree, tvb, offset, string_len,
1410                                     "%s: Value is %s, type is wrong (z)",
1411                                     (*items->hf_index == -1) ?
1412                                       "String Param" :
1413                                       proto_registrar_get_name(*items->hf_index),
1414                                     tvb_format_text(tvb, offset, string_len));
1415                                 offset += string_len;
1416                                 items++;
1417                         } else {
1418                                 offset = (*items->func)(tvb, offset, 0,
1419                                     pinfo, tree, 0, *items->hf_index);
1420                                 items++;
1421                         }
1422                         break;
1423
1424                 case 'F':
1425                         /*
1426                          * One or more pad bytes.
1427                          */
1428                         desc = get_count(desc, &count);
1429                         proto_tree_add_text(tree, tvb, offset, count,
1430                             "%s", "Padding");
1431                         offset += count;
1432                         break;
1433
1434                 case 'L':
1435                         /*
1436                          * 16-bit receive buffer length.
1437                          */
1438                         proto_tree_add_item(tree, hf_recv_buf_len, tvb,
1439                             offset, 2, TRUE);
1440                         offset += 2;
1441                         break;
1442
1443                 case 's':
1444                         /*
1445                          * 32-bit send buffer offset.
1446                          * This appears not to be sent over the wire.
1447                          */
1448                         *has_data_p = TRUE;
1449                         break;
1450
1451                 case 'T':
1452                         /*
1453                          * 16-bit send buffer length.
1454                          * This also appears not to be sent over the wire.
1455                          */
1456                         break;
1457
1458                 default:
1459                         break;
1460                 }
1461         }
1462         return offset;
1463 }
1464
1465 static int
1466 dissect_response_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
1467     proto_tree *tree, const guchar *desc, const item_t *items,
1468     gboolean *has_data_p, gboolean *has_ent_count_p, guint16 *ent_count_p)
1469 {
1470         guint c;
1471         guint16 WParam;
1472         guint32 LParam;
1473         int count;
1474
1475         *has_data_p = FALSE;
1476         *has_ent_count_p = FALSE;
1477         while ((c = *desc++) != '\0') {
1478                 switch (c) {
1479
1480                 case 'r':
1481                         /*
1482                          * 32-bit receive buffer offset.
1483                          */
1484                         *has_data_p = TRUE;
1485                         break;
1486
1487                 case 'g':
1488                         /*
1489                          * A byte or series of bytes is returned.
1490                          */
1491                         desc = get_count(desc, &count);
1492                         if (items->func == NULL) {
1493                                 /*
1494                                  * We've run out of items in the table;
1495                                  * fall back on the default.
1496                                  */
1497                                 offset = add_byte_param(tvb, offset, count,
1498                                     pinfo, tree, 0, -1);
1499                         } else if (items->type != PARAM_BYTES) {
1500                                 /*
1501                                  * Descriptor character is 'b', but this
1502                                  * isn't a byte/bytes parameter.
1503                                  */
1504                                 proto_tree_add_text(tree, tvb, offset, count,
1505                                     "%s: Value is %s, type is wrong (g)",
1506                                     (*items->hf_index == -1) ?
1507                                       "Byte Param" :
1508                                       proto_registrar_get_name(*items->hf_index),
1509                                     tvb_bytes_to_str(tvb, offset, count));
1510                                 offset += count;
1511                                 items++;
1512                         } else {
1513                                 offset = (*items->func)(tvb, offset, count,
1514                                     pinfo, tree, 0, *items->hf_index);
1515                                 items++;
1516                         }
1517                         break;
1518
1519                 case 'h':
1520                         /*
1521                          * A 16-bit word is received.
1522                          */
1523                         if (items->func == NULL) {
1524                                 /*
1525                                  * We've run out of items in the table;
1526                                  * fall back on the default.
1527                                  */
1528                                 offset = add_word_param(tvb, offset, 0, pinfo,
1529                                     tree, 0, -1);
1530                         } else if (items->type != PARAM_WORD) {
1531                                 /*
1532                                  * Descriptor character is 'h', but this
1533                                  * isn't a word parameter.
1534                                  */
1535                                 WParam = tvb_get_letohs(tvb, offset);
1536                                 proto_tree_add_text(tree, tvb, offset, 2,
1537                                     "%s: Value is %u (0x%04X), type is wrong (W)",
1538                                     (*items->hf_index == -1) ?
1539                                       "Word Param" :
1540                                       proto_registrar_get_name(*items->hf_index),
1541                                     WParam, WParam);
1542                                 offset += 2;
1543                                 items++;
1544                         } else {
1545                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1546                                     tree, 0, *items->hf_index);
1547                                 items++;
1548                         }
1549                         break;
1550
1551                 case 'i':
1552                         /*
1553                          * A 32-bit doubleword is received.
1554                          */
1555                         if (items->func == NULL) {
1556                                 /*
1557                                  * We've run out of items in the table;
1558                                  * fall back on the default.
1559                                  */
1560                                 offset = add_dword_param(tvb, offset, 0, pinfo,
1561                                     tree, 0, -1);
1562                         } else if (items->type != PARAM_DWORD) {
1563                                 /*
1564                                  * Descriptor character is 'i', but this
1565                                  * isn't a doubleword parameter.
1566                                  */
1567                                 LParam = tvb_get_letohl(tvb, offset);
1568                                 proto_tree_add_text(tree, tvb, offset, 2,
1569                                     "%s: Value is %u (0x%08X), type is wrong (i)",
1570                                     (*items->hf_index == -1) ?
1571                                       "Doubleword Param" :
1572                                       proto_registrar_get_name(*items->hf_index),
1573                                     LParam, LParam);
1574                                 offset += 4;
1575                                 items++;
1576                         } else {
1577                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1578                                     tree, 0, *items->hf_index);
1579                                 items++;
1580                         }
1581                         break;
1582
1583                 case 'e':
1584                         /*
1585                          * A 16-bit entry count is returned.
1586                          */
1587                         WParam = tvb_get_letohs(tvb, offset);
1588                         proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2,
1589                             WParam);
1590                         offset += 2;
1591                         *has_ent_count_p = TRUE;
1592                         *ent_count_p = WParam;  /* Save this for later retrieval */
1593                         break;
1594
1595                 default:
1596                         break;
1597                 }
1598         }
1599         return offset;
1600 }
1601
1602 static int
1603 dissect_transact_data(tvbuff_t *tvb, int offset, int convert,
1604     packet_info *pinfo, proto_tree *tree, const guchar *desc,
1605     const item_t *items, guint16 *aux_count_p)
1606 {
1607         guint c;
1608         guint16 WParam;
1609         guint32 LParam;
1610         int count;
1611         int cptr;
1612         const char *string;
1613         gint string_len;
1614
1615         if (aux_count_p != NULL)
1616                 *aux_count_p = 0;
1617
1618         while ((c = *desc++) != '\0') {
1619                 switch (c) {
1620
1621                 case 'W':
1622                         /*
1623                          * A 16-bit word value.
1624                          * XXX - handle the count?
1625                          */
1626                         desc = get_count(desc, &count);
1627                         if (items->func == NULL) {
1628                                 /*
1629                                  * We've run out of items in the table;
1630                                  * fall back on the default.
1631                                  */
1632                                 offset = add_word_param(tvb, offset, 0, pinfo,
1633                                     tree, convert, -1);
1634                         } else if (items->type != PARAM_WORD) {
1635                                 /*
1636                                  * Descriptor character is 'W', but this
1637                                  * isn't a word parameter.
1638                                  */
1639                                 WParam = tvb_get_letohs(tvb, offset);
1640                                 proto_tree_add_text(tree, tvb, offset, 2,
1641                                     "%s: Value is %u (0x%04X), type is wrong (W)",
1642                                     (*items->hf_index == -1) ?
1643                                       "Word Param" :
1644                                       proto_registrar_get_name(*items->hf_index),
1645                                     WParam, WParam);
1646                                 offset += 2;
1647                                 items++;
1648                         } else {
1649                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1650                                     tree, convert, *items->hf_index);
1651                                 items++;
1652                         }
1653                         break;
1654
1655                 case 'D':
1656                         /*
1657                          * A 32-bit doubleword value.
1658                          * XXX - handle the count?
1659                          */
1660                         desc = get_count(desc, &count);
1661                         if (items->func == NULL) {
1662                                 /*
1663                                  * We've run out of items in the table;
1664                                  * fall back on the default.
1665                                  */
1666                                 offset = add_dword_param(tvb, offset, 0, pinfo,
1667                                     tree, convert, -1);
1668                         } else if (items->type != PARAM_DWORD) {
1669                                 /*
1670                                  * Descriptor character is 'D', but this
1671                                  * isn't a doubleword parameter.
1672                                  */
1673                                 LParam = tvb_get_letohl(tvb, offset);
1674                                 proto_tree_add_text(tree, tvb, offset, 2,
1675                                     "%s: Value is %u (0x%08X), type is wrong (D)",
1676                                     (*items->hf_index == -1) ?
1677                                       "Doubleword Param" :
1678                                       proto_registrar_get_name(*items->hf_index),
1679                                     LParam, LParam);
1680                                 offset += 4;
1681                                 items++;
1682                         } else {
1683                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1684                                     tree, convert, *items->hf_index);
1685                                 items++;
1686                         }
1687                         break;
1688
1689                 case 'B':
1690                         /*
1691                          * A byte or multi-byte value.
1692                          */
1693                         desc = get_count(desc, &count);
1694                         if (items->func == NULL) {
1695                                 /*
1696                                  * We've run out of items in the table;
1697                                  * fall back on the default.
1698                                  */
1699                                 offset = add_byte_param(tvb, offset, count,
1700                                     pinfo, tree, convert, -1);
1701                         } else if (items->type != PARAM_BYTES) {
1702                                 /*
1703                                  * Descriptor character is 'B', but this
1704                                  * isn't a byte/bytes parameter.
1705                                  */
1706                                 proto_tree_add_text(tree, tvb, offset, count,
1707                                     "%s: Value is %s, type is wrong (B)",
1708                                     (*items->hf_index == -1) ?
1709                                       "Byte Param" :
1710                                       proto_registrar_get_name(*items->hf_index),
1711                                     tvb_bytes_to_str(tvb, offset, count));
1712                                 offset += count;
1713                                 items++;
1714                         } else {
1715                                 offset = (*items->func)(tvb, offset, count,
1716                                     pinfo, tree, convert, *items->hf_index);
1717                                 items++;
1718                         }
1719                         break;
1720
1721                 case 'O':
1722                         /*
1723                          * A null pointer.
1724                          */
1725                         if (items->func == NULL) {
1726                                 /*
1727                                  * We've run out of items in the table;
1728                                  * fall back on the default.
1729                                  */
1730                                 add_null_pointer_param(tvb, offset, 0,
1731                                     pinfo, tree, convert, -1);
1732                         } else {
1733                                 /*
1734                                  * If "*items->hf_index" is -1, this is
1735                                  * a reserved must-be-null field; don't
1736                                  * clutter the protocol tree by putting
1737                                  * it in.
1738                                  */
1739                                 if (*items->hf_index != -1) {
1740                                         add_null_pointer_param(tvb,
1741                                             offset, 0, pinfo, tree, convert,
1742                                             *items->hf_index);
1743                                 }
1744                                 items++;
1745                         }
1746                         break;
1747
1748                 case 'z':
1749                         /*
1750                          * A pointer to a null-terminated ASCII string.
1751                          */
1752                         if (items->func == NULL) {
1753                                 /*
1754                                  * We've run out of items in the table;
1755                                  * fall back on the default.
1756                                  */
1757                                 offset = add_pointer_param(tvb, offset, 0,
1758                                     pinfo, tree, convert, -1);
1759                         } else if (items->type != PARAM_STRINGZ) {
1760                                 /*
1761                                  * Descriptor character is 'z', but this
1762                                  * isn't a string parameter.
1763                                  */
1764                                 string = get_pointer_value(tvb, offset,
1765                                     convert, &cptr, &string_len);
1766                                 offset += 4;
1767                                 proto_tree_add_text(tree, tvb, cptr, string_len,
1768                                     "%s: Value is %s, type is wrong (z)",
1769                                     (*items->hf_index == -1) ?
1770                                       "String Param" :
1771                                       proto_registrar_get_name(*items->hf_index),
1772                                     string);
1773                                 items++;
1774                         } else {
1775                                 offset = (*items->func)(tvb, offset, 0,
1776                                     pinfo, tree, convert, *items->hf_index);
1777                                 items++;
1778                         }
1779                         break;
1780
1781                 case 'N':
1782                         /*
1783                          * 16-bit auxiliary data structure count.
1784                          * XXX - hf_acount?
1785                          */
1786                         WParam = tvb_get_letohs(tvb, offset);
1787                         proto_tree_add_text(tree, tvb, offset, 2,
1788                             "%s: %u (0x%04X)",
1789                             "Auxiliary data structure count",
1790                             WParam, WParam);
1791                         offset += 2;
1792                         if (aux_count_p != NULL)
1793                                 *aux_count_p = WParam;  /* Save this for later retrieval */
1794                         break;
1795
1796                 default:
1797                         break;
1798                 }
1799         }
1800         return offset;
1801 }
1802
1803 static const value_string commands[] = {
1804         {LANMAN_NETSHAREENUM,           "NetShareEnum"},
1805         {LANMAN_NETSHAREGETINFO,        "NetShareGetInfo"},
1806         {LANMAN_NETSERVERGETINFO,       "NetServerGetInfo"},
1807         {LANMAN_NETGROUPGETUSERS,       "NetGroupGetUsers"},
1808         {LANMAN_NETUSERGETINFO,         "NetUserGetInfo"},
1809         {LANMAN_NETUSERGETGROUPS,       "NetUserGetGroups"},
1810         {LANMAN_NETWKSTAGETINFO,        "NetWkstaGetInfo"},
1811         {LANMAN_DOSPRINTQENUM,          "DOSPrintQEnum"},
1812         {LANMAN_DOSPRINTQGETINFO,       "DOSPrintQGetInfo"},
1813         {LANMAN_WPRINTQUEUEPAUSE,       "WPrintQueuePause"},
1814         {LANMAN_WPRINTQUEUERESUME,      "WPrintQueueResume"},
1815         {LANMAN_WPRINTJOBENUMERATE,     "WPrintJobEnumerate"},
1816         {LANMAN_WPRINTJOBGETINFO,       "WPrintJobGetInfo"},
1817         {LANMAN_RDOSPRINTJOBDEL,        "RDOSPrintJobDel"},
1818         {LANMAN_RDOSPRINTJOBPAUSE,      "RDOSPrintJobPause"},
1819         {LANMAN_RDOSPRINTJOBRESUME,     "RDOSPrintJobResume"},
1820         {LANMAN_WPRINTDESTENUM,         "WPrintDestEnum"},
1821         {LANMAN_WPRINTDESTGETINFO,      "WPrintDestGetInfo"},
1822         {LANMAN_NETREMOTETOD,           "NetRemoteTOD"},
1823         {LANMAN_WPRINTQUEUEPURGE,       "WPrintQueuePurge"},
1824         {LANMAN_NETSERVERENUM2,         "NetServerEnum2"},
1825         {LANMAN_WACCESSGETUSERPERMS,    "WAccessGetUserPerms"},
1826         {LANMAN_SETUSERPASSWORD,        "SetUserPassword"},
1827         {LANMAN_NETWKSTAUSERLOGON,      "NetWkstaUserLogon"},
1828         {LANMAN_NETWKSTAUSERLOGOFF,     "NetWkstaUserLogoff"},
1829         {LANMAN_PRINTJOBINFO,           "PrintJobInfo"},
1830         {LANMAN_WPRINTDRIVERENUM,       "WPrintDriverEnum"},
1831         {LANMAN_WPRINTQPROCENUM,        "WPrintQProcEnum"},
1832         {LANMAN_WPRINTPORTENUM,         "WPrintPortEnum"},
1833         {LANMAN_SAMOEMCHANGEPASSWORD,   "SamOEMChangePassword"},
1834         {0,     NULL}
1835 };
1836
1837 static void
1838 dissect_response_data(tvbuff_t *tvb, packet_info *pinfo, int convert,
1839     proto_tree *tree, struct smb_info *smb_info,
1840     const struct lanman_desc *lanman, gboolean has_ent_count,
1841     guint16 ent_count)
1842 {
1843         smb_transact_info_t *trp = smb_info->sip->extra_info;
1844         const item_list_t *resp_data_list;
1845         int offset, start_offset;
1846         const item_t *resp_data;
1847         proto_item *data_item;
1848         proto_tree *data_tree;
1849         proto_item *entry_item;
1850         proto_tree *entry_tree;
1851         guint i, j;
1852         guint16 aux_count;
1853
1854         /*
1855          * Find the item table for the matching request's detail level.
1856          */
1857         for (resp_data_list = lanman->resp_data_list;
1858             resp_data_list->level != -1; resp_data_list++) {
1859                 if (resp_data_list->level == trp->info_level)
1860                         break;
1861         }
1862         resp_data = resp_data_list->item_list;
1863
1864         offset = 0;
1865         if (lanman->resp_data_item != NULL) {
1866                 /*
1867                  * Create a protocol tree item for the data.
1868                  */
1869                 data_item = (*lanman->resp_data_item)(tvb,
1870                     pinfo, tree, offset);
1871                 data_tree = proto_item_add_subtree(data_item,
1872                     *lanman->ett_resp_data);
1873         } else {
1874                 /*
1875                  * Just leave it at the top level.
1876                  */
1877                 data_item = NULL;
1878                 data_tree = tree;
1879         }
1880
1881         if (trp->data_descrip == NULL) {
1882                 /*
1883                  * This could happen if we only dissected
1884                  * part of the request to which this is a
1885                  * reply, e.g. if the request was split
1886                  * across TCP segments and we weren't doing
1887                  * TCP desegmentation, or if we had a snapshot
1888                  * length that was too short.
1889                  *
1890                  * We can't dissect the data; just show it
1891                  * as raw data.
1892                  */
1893                 proto_tree_add_text(tree, tvb, offset, -1,
1894                     "Data (no descriptor available)");
1895                 offset += tvb_length_remaining(tvb, offset);
1896         } else {
1897                 /*
1898                  * If we have an entry count, show all the entries,
1899                  * with each one having a protocol tree item.
1900                  *
1901                  * Otherwise, we just show one returned item, with
1902                  * no protocol tree item.
1903                  */
1904                 if (!has_ent_count)
1905                         ent_count = 1;
1906                 for (i = 0; i < ent_count; i++) {
1907                         start_offset = offset;
1908                         if (has_ent_count) {
1909                                 /*
1910                                  * Create a protocol tree item for the
1911                                  * entry.
1912                                  */
1913                                 entry_item =
1914                                     (*lanman->resp_data_element_item)
1915                                       (tvb, pinfo, data_tree, offset);
1916                                 entry_tree = proto_item_add_subtree(
1917                                     entry_item,
1918                                     *lanman->ett_resp_data_element_item);
1919                         } else {
1920                                 /*
1921                                  * Just leave it at the current
1922                                  * level.
1923                                  */
1924                                 entry_item = NULL;
1925                                 entry_tree = data_tree;
1926                         }
1927
1928                         offset = dissect_transact_data(tvb, offset,
1929                             convert, pinfo, entry_tree,
1930                             trp->data_descrip, resp_data, &aux_count);
1931
1932                         /* auxiliary data */
1933                         if (trp->aux_data_descrip != NULL) {
1934                                 for (j = 0; j < aux_count; j++) {
1935                                         offset = dissect_transact_data(
1936                                             tvb, offset, convert,
1937                                             pinfo, entry_tree,
1938                                             trp->data_descrip,
1939                                             lanman->resp_aux_data, NULL);
1940                                 }
1941                         }
1942
1943                         if (entry_item != NULL) {
1944                                 /*
1945                                  * Set the length of the protocol tree
1946                                  * item for the entry.
1947                                  */
1948                                 proto_item_set_len(entry_item,
1949                                     offset - start_offset);
1950                         }
1951                 }
1952         }
1953
1954         if (data_item != NULL) {
1955                 /*
1956                  * Set the length of the protocol tree item
1957                  * for the data.
1958                  */
1959                 proto_item_set_len(data_item, offset);
1960         }
1961 }
1962
1963 static gboolean
1964 dissect_pipe_lanman(tvbuff_t *pd_tvb, tvbuff_t *p_tvb, tvbuff_t *d_tvb,
1965                     packet_info *pinfo, proto_tree *parent_tree)
1966 {
1967         smb_info_t *smb_info = pinfo->private_data;
1968         smb_transact_info_t *trp = smb_info->sip->extra_info;
1969         int offset = 0, start_offset;
1970         guint16 cmd;
1971         guint16 status;
1972         int convert;
1973         const struct lanman_desc *lanman;
1974         proto_item *item = NULL;
1975         proto_tree *tree = NULL;
1976         guint descriptor_len;
1977         const gchar *param_descrip, *data_descrip, *aux_data_descrip = NULL;
1978         gboolean has_data;
1979         gboolean has_ent_count;
1980         guint16 ent_count, aux_count;
1981         guint i;
1982         proto_item *data_item;
1983         proto_tree *data_tree;
1984
1985         if (!proto_is_protocol_enabled(proto_smb_lanman))
1986                 return FALSE;
1987         if (smb_info->request && p_tvb == NULL) {
1988                 /*
1989                  * Requests must have parameters.
1990                  */
1991                 return FALSE;
1992         }
1993         pinfo->current_proto = "LANMAN";
1994
1995         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
1996                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LANMAN");
1997         }
1998
1999         if (parent_tree) {
2000                 item = proto_tree_add_item(parent_tree, proto_smb_lanman,
2001                         pd_tvb, 0, -1, FALSE);
2002                 tree = proto_item_add_subtree(item, ett_lanman);
2003         }
2004
2005         if (smb_info->request) { /* this is a request */
2006                 /* function code */
2007                 cmd = tvb_get_letohs(p_tvb, offset);
2008                 if (check_col(pinfo->cinfo, COL_INFO)) {
2009                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s Request", val_to_str(cmd, commands, "Unknown Command:0x%02x"));
2010                 }
2011                 proto_tree_add_uint(tree, hf_function_code, p_tvb, offset, 2,
2012                     cmd);
2013                 offset += 2;
2014
2015                 /*
2016                  * If we haven't already done so, save the function code in
2017                  * the structure we were handed, so that it's available to
2018                  * the code parsing the reply, and initialize the detail
2019                  * level to -1, meaning "unknown".
2020                  */
2021                 if (!pinfo->fd->flags.visited) {
2022                         trp->lanman_cmd = cmd;
2023                         trp->info_level = -1;
2024                         trp->param_descrip=NULL;
2025                         trp->data_descrip=NULL;
2026                         trp->aux_data_descrip=NULL;
2027                 }
2028
2029                 /* parameter descriptor */
2030                 descriptor_len = tvb_strsize(p_tvb, offset);
2031                 proto_tree_add_item(tree, hf_param_desc, p_tvb, offset,
2032                     descriptor_len, TRUE);
2033                 param_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2034                 if (!pinfo->fd->flags.visited) {
2035                         /*
2036                          * Save the parameter descriptor for future use.
2037                          */
2038                         g_assert(trp->param_descrip == NULL);
2039                         trp->param_descrip = g_strdup(param_descrip);
2040                 }
2041                 offset += descriptor_len;
2042
2043                 /* return descriptor */
2044                 descriptor_len = tvb_strsize(p_tvb, offset);
2045                 proto_tree_add_item(tree, hf_return_desc, p_tvb, offset,
2046                     descriptor_len, TRUE);
2047                 data_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2048                 if (!pinfo->fd->flags.visited) {
2049                         /*
2050                          * Save the return descriptor for future use.
2051                          */
2052                         g_assert(trp->data_descrip == NULL);
2053                         trp->data_descrip = g_strdup(data_descrip);
2054                 }
2055                 offset += descriptor_len;
2056
2057                 lanman = find_lanman(cmd);
2058
2059                 /* request parameters */
2060                 start_offset = offset;
2061                 offset = dissect_request_parameters(p_tvb, offset, pinfo, tree,
2062                     param_descrip, lanman->req, &has_data);
2063
2064                 /* auxiliary data descriptor */
2065                 if (tvb_reported_length_remaining(p_tvb, offset) > 0){
2066                         /*
2067                          * There are more parameters left, so the next
2068                          * item is the auxiliary data descriptor.
2069                          */
2070                         descriptor_len = tvb_strsize(p_tvb, offset);
2071                         proto_tree_add_item(tree, hf_return_desc, p_tvb, offset,
2072                             descriptor_len, TRUE);
2073                         aux_data_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2074                         if (!pinfo->fd->flags.visited) {
2075                                 /*
2076                                  * Save the auxiliary data descriptor for
2077                                  * future use.
2078                                  */
2079                                 g_assert(trp->aux_data_descrip == NULL);
2080                                 trp->aux_data_descrip =
2081                                     g_strdup(aux_data_descrip);
2082                         }
2083                         offset += descriptor_len;
2084                 }
2085
2086                 /* reset offset, we now start dissecting the data area */
2087                 offset = 0;
2088                 if (has_data && d_tvb && tvb_reported_length(d_tvb) != 0) {
2089                         /*
2090                          * There's a send buffer item in the descriptor
2091                          * string, and the data count in the transaction
2092                          * is non-zero, so there's data to dissect.
2093                          */
2094
2095                         if (lanman->req_data_item != NULL) {
2096                                 /*
2097                                  * Create a protocol tree item for the data.
2098                                  */
2099                                 data_item = (*lanman->req_data_item)(d_tvb,
2100                                     pinfo, tree, offset);
2101                                 data_tree = proto_item_add_subtree(data_item,
2102                                     *lanman->ett_req_data);
2103                         } else {
2104                                 /*
2105                                  * Just leave it at the top level.
2106                                  */
2107                                 data_item = NULL;
2108                                 data_tree = tree;
2109                         }
2110
2111                         /* data */
2112                         offset = dissect_transact_data(d_tvb, offset, -1,
2113                             pinfo, data_tree, data_descrip, lanman->req_data,
2114                             &aux_count);        /* XXX - what about strings? */
2115
2116                         /* auxiliary data */
2117                         if (aux_data_descrip != NULL) {
2118                                 for (i = 0; i < aux_count; i++) {
2119                                         offset = dissect_transact_data(d_tvb,
2120                                             offset, -1, pinfo, data_tree,
2121                                             aux_data_descrip,
2122                                             lanman->req_aux_data, NULL);
2123                                 }
2124                         }
2125
2126                         if (data_item != NULL) {
2127                                 /*
2128                                  * Set the length of the protocol tree item
2129                                  * for the data.
2130                                  */
2131                                 proto_item_set_len(data_item, offset);
2132                         }
2133                 }
2134         } else {
2135                 /*
2136                  * This is a response.
2137                  * Have we seen the request to which it's a response?
2138                  */
2139                 if (trp == NULL)
2140                         return FALSE;   /* no - can't dissect it */
2141
2142                 /* ok we have seen this one before */
2143
2144                 /* if it looks like an interim response, update COL_INFO and return */
2145                 if( ( (p_tvb==NULL) || (tvb_reported_length(p_tvb)==0) )
2146                 &&  ( (d_tvb==NULL) || (tvb_reported_length(d_tvb)==0) ) ){
2147                         /* command */
2148                         if (check_col(pinfo->cinfo, COL_INFO)) {
2149                                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Interim Response",
2150                                              val_to_str(trp->lanman_cmd, commands, "Unknown Command (0x%02x)"));
2151                         }
2152                         proto_tree_add_uint(tree, hf_function_code, p_tvb, 0, 0, trp->lanman_cmd);
2153                         return TRUE;
2154                 }
2155
2156                 /* command */
2157                 if (check_col(pinfo->cinfo, COL_INFO)) {
2158                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s Response",
2159                                      val_to_str(trp->lanman_cmd, commands, "Unknown Command (0x%02x)"));
2160                 }
2161                 proto_tree_add_uint(tree, hf_function_code, p_tvb, 0, 0,
2162                     trp->lanman_cmd);
2163
2164                 lanman = find_lanman(trp->lanman_cmd);
2165
2166                 /* response parameters */
2167
2168                 /* status */
2169                 status = tvb_get_letohs(p_tvb, offset);
2170                 proto_tree_add_uint(tree, hf_status, p_tvb, offset, 2, status);
2171                 offset += 2;
2172
2173                 /* convert */
2174                 convert = tvb_get_letohs(p_tvb, offset);
2175                 proto_tree_add_uint(tree, hf_convert, p_tvb, offset, 2, convert);
2176                 offset += 2;
2177
2178                 /* rest of the parameters */
2179                 offset = dissect_response_parameters(p_tvb, offset, pinfo, tree,
2180                     trp->param_descrip, lanman->resp, &has_data,
2181                     &has_ent_count, &ent_count);
2182
2183
2184                 /* reset offset, we now start dissecting the data area */
2185                 offset = 0;
2186                 /* data */
2187                 if (has_data && d_tvb && tvb_reported_length(d_tvb) > 0) {
2188                         /*
2189                          * There's a receive buffer item in the descriptor
2190                          * string, and the data count in the transaction
2191                          * is non-zero, so there's data to dissect.
2192                          */
2193                         dissect_response_data(d_tvb, pinfo, convert, tree,
2194                             smb_info, lanman, has_ent_count, ent_count);
2195                 }
2196         }
2197
2198         return TRUE;
2199 }
2200
2201 void
2202 proto_register_pipe_lanman(void)
2203 {
2204         static hf_register_info hf[] = {
2205                 { &hf_function_code,
2206                         { "Function Code", "lanman.function_code", FT_UINT16, BASE_DEC,
2207                         VALS(commands), 0, "LANMAN Function Code/Command", HFILL }},
2208
2209                 { &hf_param_desc,
2210                         { "Parameter Descriptor", "lanman.param_desc", FT_STRING, BASE_NONE,
2211                         NULL, 0, "LANMAN Parameter Descriptor", HFILL }},
2212
2213                 { &hf_return_desc,
2214                         { "Return Descriptor", "lanman.ret_desc", FT_STRING, BASE_NONE,
2215                         NULL, 0, "LANMAN Return Descriptor", HFILL }},
2216
2217                 { &hf_aux_data_desc,
2218                         { "Auxiliary Data Descriptor", "lanman.aux_data_desc", FT_STRING, BASE_NONE,
2219                         NULL, 0, "LANMAN Auxiliary Data Descriptor", HFILL }},
2220
2221                 { &hf_detail_level,
2222                         { "Detail Level", "lanman.level", FT_UINT16, BASE_DEC,
2223                         NULL, 0, "LANMAN Detail Level", HFILL }},
2224
2225                 { &hf_recv_buf_len,
2226                         { "Receive Buffer Length", "lanman.recv_buf_len", FT_UINT16, BASE_DEC,
2227                         NULL, 0, "LANMAN Receive Buffer Length", HFILL }},
2228
2229                 { &hf_send_buf_len,
2230                         { "Send Buffer Length", "lanman.send_buf_len", FT_UINT16, BASE_DEC,
2231                         NULL, 0, "LANMAN Send Buffer Length", HFILL }},
2232
2233                 { &hf_continuation_from,
2234                         { "Continuation from message in frame", "lanman.continuation_from", FT_UINT32, BASE_DEC,
2235                         NULL, 0, "This is a LANMAN continuation from the message in the frame in question", HFILL }},
2236
2237                 { &hf_status,
2238                         { "Status", "lanman.status", FT_UINT16, BASE_DEC,
2239                         VALS(status_vals), 0, "LANMAN Return status", HFILL }},
2240
2241                 { &hf_convert,
2242                         { "Convert", "lanman.convert", FT_UINT16, BASE_DEC,
2243                         NULL, 0, "LANMAN Convert", HFILL }},
2244
2245                 { &hf_ecount,
2246                         { "Entry Count", "lanman.entry_count", FT_UINT16, BASE_DEC,
2247                         NULL, 0, "LANMAN Number of Entries", HFILL }},
2248
2249                 { &hf_acount,
2250                         { "Available Entries", "lanman.available_count", FT_UINT16, BASE_DEC,
2251                         NULL, 0, "LANMAN Number of Available Entries", HFILL }},
2252
2253                 { &hf_share_name,
2254                         { "Share Name", "lanman.share.name", FT_STRING, BASE_NONE,
2255                         NULL, 0, "LANMAN Name of Share", HFILL }},
2256
2257                 { &hf_share_type,
2258                         { "Share Type", "lanman.share.type", FT_UINT16, BASE_DEC,
2259                         VALS(share_type_vals), 0, "LANMAN Type of Share", HFILL }},
2260
2261                 { &hf_share_comment,
2262                         { "Share Comment", "lanman.share.comment", FT_STRING, BASE_NONE,
2263                         NULL, 0, "LANMAN Share Comment", HFILL }},
2264
2265                 { &hf_share_permissions,
2266                         { "Share Permissions", "lanman.share.permissions", FT_UINT16, BASE_DEC,
2267                         NULL, 0, "LANMAN Permissions on share", HFILL }},
2268
2269                 { &hf_share_max_uses,
2270                         { "Share Max Uses", "lanman.share.max_uses", FT_UINT16, BASE_DEC,
2271                         NULL, 0, "LANMAN Max connections allowed to share", HFILL }},
2272
2273                 { &hf_share_current_uses,
2274                         { "Share Current Uses", "lanman.share.current_uses", FT_UINT16, BASE_DEC,
2275                         NULL, 0, "LANMAN Current connections to share", HFILL }},
2276
2277                 { &hf_share_path,
2278                         { "Share Path", "lanman.share.path", FT_STRING, BASE_NONE,
2279                         NULL, 0, "LANMAN Share Path", HFILL }},
2280
2281                 { &hf_share_password,
2282                         { "Share Password", "lanman.share.password", FT_STRING, BASE_NONE,
2283                         NULL, 0, "LANMAN Share Password", HFILL }},
2284
2285                 { &hf_server_name,
2286                         { "Server Name", "lanman.server.name", FT_STRING, BASE_NONE,
2287                         NULL, 0, "LANMAN Name of Server", HFILL }},
2288
2289                 { &hf_server_major,
2290                         { "Major Version", "lanman.server.major", FT_UINT8, BASE_DEC,
2291                         NULL, 0, "LANMAN Server Major Version", HFILL }},
2292
2293                 { &hf_server_minor,
2294                         { "Minor Version", "lanman.server.minor", FT_UINT8, BASE_DEC,
2295                         NULL, 0, "LANMAN Server Minor Version", HFILL }},
2296
2297                 { &hf_server_comment,
2298                         { "Server Comment", "lanman.server.comment", FT_STRING, BASE_NONE,
2299                         NULL, 0, "LANMAN Server Comment", HFILL }},
2300
2301                 { &hf_abytes,
2302                         { "Available Bytes", "lanman.available_bytes", FT_UINT16, BASE_DEC,
2303                         NULL, 0, "LANMAN Number of Available Bytes", HFILL }},
2304
2305                 { &hf_current_time,
2306                         { "Current Date/Time", "lanman.current_time", FT_ABSOLUTE_TIME, BASE_NONE,
2307                         NULL, 0, "LANMAN Current date and time, in seconds since 00:00:00, January 1, 1970", HFILL }},
2308
2309                 { &hf_msecs,
2310                         { "Milliseconds", "lanman.msecs", FT_UINT32, BASE_DEC,
2311                         NULL, 0, "LANMAN Milliseconds since arbitrary time in the past (typically boot time)", HFILL }},
2312
2313                 { &hf_hour,
2314                         { "Hour", "lanman.hour", FT_UINT8, BASE_DEC,
2315                         NULL, 0, "LANMAN Current hour", HFILL }},
2316
2317                 { &hf_minute,
2318                         { "Minute", "lanman.minute", FT_UINT8, BASE_DEC,
2319                         NULL, 0, "LANMAN Current minute", HFILL }},
2320
2321                 { &hf_second,
2322                         { "Second", "lanman.second", FT_UINT8, BASE_DEC,
2323                         NULL, 0, "LANMAN Current second", HFILL }},
2324
2325                 { &hf_hundredths,
2326                         { "Hundredths of a second", "lanman.hundredths", FT_UINT8, BASE_DEC,
2327                         NULL, 0, "LANMAN Current hundredths of a second", HFILL }},
2328
2329                 { &hf_tzoffset,
2330                         { "Time Zone Offset", "lanman.tzoffset", FT_INT16, BASE_DEC,
2331                         NULL, 0, "LANMAN Offset of time zone from GMT, in minutes", HFILL }},
2332
2333                 { &hf_timeinterval,
2334                         { "Time Interval", "lanman.timeinterval", FT_UINT16, BASE_DEC,
2335                         NULL, 0, "LANMAN .0001 second units per clock tick", HFILL }},
2336
2337                 { &hf_day,
2338                         { "Day", "lanman.day", FT_UINT8, BASE_DEC,
2339                         NULL, 0, "LANMAN Current day", HFILL }},
2340
2341                 { &hf_month,
2342                         { "Month", "lanman.month", FT_UINT8, BASE_DEC,
2343                         NULL, 0, "LANMAN Current month", HFILL }},
2344
2345                 { &hf_year,
2346                         { "Year", "lanman.year", FT_UINT16, BASE_DEC,
2347                         NULL, 0, "LANMAN Current year", HFILL }},
2348
2349                 { &hf_weekday,
2350                         { "Weekday", "lanman.weekday", FT_UINT8, BASE_DEC,
2351                         VALS(weekday_vals), 0, "LANMAN Current day of the week", HFILL }},
2352
2353                 { &hf_enumeration_domain,
2354                         { "Enumeration Domain", "lanman.enumeration_domain", FT_STRING, BASE_NONE,
2355                         NULL, 0, "LANMAN Domain in which to enumerate servers", HFILL }},
2356
2357                 { &hf_computer_name,
2358                         { "Computer Name", "lanman.computer_name", FT_STRING, BASE_NONE,
2359                         NULL, 0, "LANMAN Computer Name", HFILL }},
2360
2361                 { &hf_user_name,
2362                         { "User Name", "lanman.user_name", FT_STRING, BASE_NONE,
2363                         NULL, 0, "LANMAN User Name", HFILL }},
2364
2365                 { &hf_workstation_domain,
2366                         { "Workstation Domain", "lanman.workstation_domain", FT_STRING, BASE_NONE,
2367                         NULL, 0, "LANMAN Workstation Domain", HFILL }},
2368
2369                 { &hf_workstation_major,
2370                         { "Workstation Major Version", "lanman.workstation_major", FT_UINT8, BASE_DEC,
2371                         NULL, 0, "LANMAN Workstation Major Version", HFILL }},
2372
2373                 { &hf_workstation_minor,
2374                         { "Workstation Minor Version", "lanman.workstation_minor", FT_UINT8, BASE_DEC,
2375                         NULL, 0, "LANMAN Workstation Minor Version", HFILL }},
2376
2377                 { &hf_logon_domain,
2378                         { "Logon Domain", "lanman.logon_domain", FT_STRING, BASE_NONE,
2379                         NULL, 0, "LANMAN Logon Domain", HFILL }},
2380
2381                 { &hf_other_domains,
2382                         { "Other Domains", "lanman.other_domains", FT_STRING, BASE_NONE,
2383                         NULL, 0, "LANMAN Other Domains", HFILL }},
2384
2385                 { &hf_password,
2386                         { "Password", "lanman.password", FT_STRING, BASE_NONE,
2387                         NULL, 0, "LANMAN Password", HFILL }},
2388
2389                 { &hf_workstation_name,
2390                         { "Workstation Name", "lanman.workstation_name", FT_STRING, BASE_NONE,
2391                         NULL, 0, "LANMAN Workstation Name", HFILL }},
2392
2393                 { &hf_ustruct_size,
2394                         { "Length of UStruct", "lanman.ustruct_size", FT_UINT16, BASE_DEC,
2395                         NULL, 0, "LANMAN UStruct Length", HFILL }},
2396
2397                 { &hf_logon_code,
2398                         { "Logon Code", "lanman.logon_code", FT_UINT16, BASE_DEC,
2399                         VALS(status_vals), 0, "LANMAN Logon Code", HFILL }},
2400
2401                 { &hf_privilege_level,
2402                         { "Privilege Level", "lanman.privilege_level", FT_UINT16, BASE_DEC,
2403                         VALS(privilege_vals), 0, "LANMAN Privilege Level", HFILL }},
2404
2405                 { &hf_operator_privileges,
2406                         { "Operator Privileges", "lanman.operator_privileges", FT_UINT32, BASE_DEC,
2407                         VALS(op_privilege_vals), 0, "LANMAN Operator Privileges", HFILL }},
2408
2409                 { &hf_num_logons,
2410                         { "Number of Logons", "lanman.num_logons", FT_UINT16, BASE_DEC,
2411                         NULL, 0, "LANMAN Number of Logons", HFILL }},
2412
2413                 { &hf_bad_pw_count,
2414                         { "Bad Password Count", "lanman.bad_pw_count", FT_UINT16, BASE_DEC,
2415                         NULL, 0, "LANMAN Number of incorrect passwords entered since last successful login", HFILL }},
2416
2417                 { &hf_last_logon,
2418                         { "Last Logon Date/Time", "lanman.last_logon", FT_ABSOLUTE_TIME, BASE_NONE,
2419                         NULL, 0, "LANMAN Date and time of last logon", HFILL }},
2420
2421                 { &hf_last_logoff,
2422                         { "Last Logoff Date/Time", "lanman.last_logoff", FT_ABSOLUTE_TIME, BASE_NONE,
2423                         NULL, 0, "LANMAN Date and time of last logoff", HFILL }},
2424
2425                 { &hf_logoff_time,
2426                         { "Logoff Date/Time", "lanman.logoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
2427                         NULL, 0, "LANMAN Date and time when user should log off", HFILL }},
2428
2429                 { &hf_kickoff_time,
2430                         { "Kickoff Date/Time", "lanman.kickoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
2431                         NULL, 0, "LANMAN Date and time when user will be logged off", HFILL }},
2432
2433                 { &hf_password_age,
2434                         { "Password Age", "lanman.password_age", FT_RELATIVE_TIME, BASE_NONE,
2435                         NULL, 0, "LANMAN Time since user last changed his/her password", HFILL }},
2436
2437                 { &hf_password_can_change,
2438                         { "Password Can Change", "lanman.password_can_change", FT_ABSOLUTE_TIME, BASE_NONE,
2439                         NULL, 0, "LANMAN Date and time when user can change their password", HFILL }},
2440
2441                 { &hf_password_must_change,
2442                         { "Password Must Change", "lanman.password_must_change", FT_ABSOLUTE_TIME, BASE_NONE,
2443                         NULL, 0, "LANMAN Date and time when user must change their password", HFILL }},
2444
2445                 { &hf_script_path,
2446                         { "Script Path", "lanman.script_path", FT_STRING, BASE_NONE,
2447                         NULL, 0, "LANMAN Pathname of user's logon script", HFILL }},
2448
2449                 { &hf_logoff_code,
2450                         { "Logoff Code", "lanman.logoff_code", FT_UINT16, BASE_DEC,
2451                         VALS(status_vals), 0, "LANMAN Logoff Code", HFILL }},
2452
2453                 { &hf_duration,
2454                         { "Duration of Session", "lanman.duration", FT_RELATIVE_TIME, BASE_NONE,
2455                         NULL, 0, "LANMAN Number of seconds the user was logged on", HFILL }},
2456
2457                 { &hf_user_comment,
2458                         { "User Comment", "lanman.user_comment", FT_STRING, BASE_NONE,
2459                         NULL, 0, "LANMAN User Comment", HFILL }},
2460
2461                 { &hf_full_name,
2462                         { "Full Name", "lanman.full_name", FT_STRING, BASE_NONE,
2463                         NULL, 0, "LANMAN Full Name", HFILL }},
2464
2465                 { &hf_homedir,
2466                         { "Home Directory", "lanman.homedir", FT_STRING, BASE_NONE,
2467                         NULL, 0, "LANMAN Home Directory", HFILL }},
2468
2469                 { &hf_parameters,
2470                         { "Parameters", "lanman.parameters", FT_STRING, BASE_NONE,
2471                         NULL, 0, "LANMAN Parameters", HFILL }},
2472
2473                 { &hf_logon_server,
2474                         { "Logon Server", "lanman.logon_server", FT_STRING, BASE_NONE,
2475                         NULL, 0, "LANMAN Logon Server", HFILL }},
2476
2477                 /* XXX - we should have a value_string table for this */
2478                 { &hf_country_code,
2479                         { "Country Code", "lanman.country_code", FT_UINT16, BASE_DEC,
2480                         NULL, 0, "LANMAN Country Code", HFILL }},
2481
2482                 { &hf_workstations,
2483                         { "Workstations", "lanman.workstations", FT_STRING, BASE_NONE,
2484                         NULL, 0, "LANMAN Workstations", HFILL }},
2485
2486                 { &hf_max_storage,
2487                         { "Max Storage", "lanman.max_storage", FT_UINT32, BASE_DEC,
2488                         NULL, 0, "LANMAN Max Storage", HFILL }},
2489
2490                 { &hf_units_per_week,
2491                         { "Units Per Week", "lanman.units_per_week", FT_UINT16, BASE_DEC,
2492                         NULL, 0, "LANMAN Units Per Week", HFILL }},
2493
2494                 { &hf_logon_hours,
2495                         { "Logon Hours", "lanman.logon_hours", FT_BYTES, BASE_NONE,
2496                         NULL, 0, "LANMAN Logon Hours", HFILL }},
2497
2498                 /* XXX - we should have a value_string table for this */
2499                 { &hf_code_page,
2500                         { "Code Page", "lanman.code_page", FT_UINT16, BASE_DEC,
2501                         NULL, 0, "LANMAN Code Page", HFILL }},
2502
2503                 { &hf_new_password,
2504                         { "New Password", "lanman.new_password", FT_BYTES, BASE_HEX,
2505                         NULL, 0, "LANMAN New Password (encrypted)", HFILL }},
2506
2507                 { &hf_old_password,
2508                         { "Old Password", "lanman.old_password", FT_BYTES, BASE_HEX,
2509                         NULL, 0, "LANMAN Old Password (encrypted)", HFILL }},
2510
2511                 { &hf_reserved,
2512                         { "Reserved", "lanman.reserved", FT_UINT32, BASE_HEX,
2513                         NULL, 0, "LANMAN Reserved", HFILL }},
2514
2515         };
2516         static gint *ett[] = {
2517                 &ett_lanman,
2518                 &ett_lanman_servers,
2519                 &ett_lanman_server,
2520                 &ett_lanman_shares,
2521                 &ett_lanman_share,
2522         };
2523
2524         proto_smb_lanman = proto_register_protocol(
2525                 "Microsoft Windows Lanman Remote API Protocol", "LANMAN", "lanman");
2526         proto_register_field_array(proto_smb_lanman, hf, array_length(hf));
2527         proto_register_subtree_array(ett, array_length(ett));
2528 }
2529
2530 static heur_dissector_list_t smb_transact_heur_subdissector_list;
2531
2532 static gboolean
2533 dissect_pipe_dcerpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree,
2534     proto_tree *tree, guint32 fid)
2535 {
2536         dcerpc_private_info dcerpc_priv;
2537         smb_info_t *smb_priv = (smb_info_t *)pinfo->private_data;
2538         gboolean result;
2539         gboolean save_fragmented;
2540
2541         dcerpc_priv.transport_type = DCERPC_TRANSPORT_SMB;
2542         dcerpc_priv.data.smb.fid = fid;
2543
2544         pinfo->private_data = &dcerpc_priv;
2545
2546         /* offer desegmentation service to DCERPC */
2547         pinfo->can_desegment=0;
2548         pinfo->desegment_offset = 0;
2549         pinfo->desegment_len = 0;
2550         if(smb_dcerpc_reassembly){ 
2551                 pinfo->can_desegment=2;
2552         }
2553
2554         save_fragmented = pinfo->fragmented;
2555
2556         /* see if this packet is already desegmented */
2557         if(smb_dcerpc_reassembly && pinfo->fd->flags.visited){
2558                 fragment_data *fd_head;
2559                 tvbuff_t *new_tvb;
2560
2561                 fd_head=fragment_get(pinfo, pinfo->fd->num , 
2562                         dcerpc_fragment_table);
2563                 if(fd_head && fd_head->flags&FD_DEFRAGMENTED){
2564                         proto_tree *tr;
2565                         proto_item *it;
2566                         fragment_data *fd;
2567                 
2568                         new_tvb = tvb_new_real_data(fd_head->data,
2569                                   fd_head->datalen, fd_head->datalen,
2570                                   "DCERPC over SMB");
2571                         tvb_set_child_real_data_tvbuff(d_tvb, new_tvb);
2572                         pinfo->fd->data_src=g_slist_append(pinfo->fd->data_src,
2573                                    new_tvb);
2574                         pinfo->fragmented=FALSE;
2575
2576                         d_tvb=new_tvb;
2577
2578                         /* list what segments we have */
2579                         it = proto_tree_add_text(tree, d_tvb, 0, 0, "Fragments");
2580                         tr = proto_item_add_subtree(it, ett_smb_pipe_fragments);
2581                         for(fd=fd_head->next;fd;fd=fd->next){
2582                                 proto_tree_add_text(tr, d_tvb, 0, 0, "Frame:%u Data:%u-%u",
2583                                             fd->frame, fd->offset, fd->offset+fd->len-1);
2584                         }
2585                 }
2586         }
2587
2588         result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb,
2589                                          pinfo, parent_tree);
2590         pinfo->private_data = smb_priv;
2591
2592         /* check if dissector wanted us to desegment the data */
2593         if(smb_dcerpc_reassembly && !pinfo->fd->flags.visited && pinfo->desegment_len){
2594                 fragment_add(d_tvb, 0, pinfo, pinfo->fd->num,
2595                         dcerpc_fragment_table,
2596                         0, tvb_length(d_tvb), TRUE);
2597                 fragment_set_tot_len(pinfo, pinfo->fd->num, 
2598                         dcerpc_fragment_table, 
2599                         pinfo->desegment_len+tvb_length(d_tvb));
2600                 /* since the other fragments are in normal ReadAndX and WriteAndX calls
2601                    we must make sure we can map FID values to this defragmentation
2602                    session */
2603                 /* first remove any old mappings */
2604                 if(g_hash_table_lookup(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid)){
2605                         g_hash_table_remove(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid);
2606                 }
2607                 g_hash_table_insert(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid, 
2608                         (void *)pinfo->fd->num);
2609         }
2610         /* clear out the variables */
2611         pinfo->can_desegment=0;
2612         pinfo->desegment_offset = 0;
2613         pinfo->desegment_len = 0;
2614
2615         if (!result)
2616                 call_dissector(data_handle, d_tvb, pinfo, parent_tree);
2617
2618         pinfo->fragmented = save_fragmented;
2619         return TRUE;
2620 }
2621
2622 void
2623 proto_register_pipe_dcerpc(void)
2624 {
2625         register_heur_dissector_list("smb_transact", &smb_transact_heur_subdissector_list);
2626 }
2627
2628 #define CALL_NAMED_PIPE         0x54
2629 #define WAIT_NAMED_PIPE         0x53
2630 #define PEEK_NAMED_PIPE         0x23
2631 #define Q_NM_P_HAND_STATE       0x21
2632 #define SET_NM_P_HAND_STATE     0x01
2633 #define Q_NM_PIPE_INFO          0x22
2634 #define TRANSACT_NM_PIPE        0x26
2635 #define RAW_READ_NM_PIPE        0x11
2636 #define RAW_WRITE_NM_PIPE       0x31
2637
2638 static const value_string functions[] = {
2639         {CALL_NAMED_PIPE,       "CallNamedPipe"},
2640         {WAIT_NAMED_PIPE,       "WaitNamedPipe"},
2641         {PEEK_NAMED_PIPE,       "PeekNamedPipe"},
2642         {Q_NM_P_HAND_STATE,     "QNmPHandState"},
2643         {SET_NM_P_HAND_STATE,   "SetNmPHandState"},
2644         {Q_NM_PIPE_INFO,        "QNmPipeInfo"},
2645         {TRANSACT_NM_PIPE,      "TransactNmPipe"},
2646         {RAW_READ_NM_PIPE,      "RawReadNmPipe"},
2647         {RAW_WRITE_NM_PIPE,     "RawWriteNmPipe"},
2648         {0,                     NULL}
2649 };
2650
2651 static const value_string pipe_status[] = {
2652         {1,     "Disconnected by server"},
2653         {2,     "Listening"},
2654         {3,     "Connection to server is OK"},
2655         {4,     "Server end of pipe is closed"},
2656         {0,     NULL}
2657 };
2658
2659 #define PIPE_LANMAN     1
2660 #define PIPE_DCERPC     2
2661
2662 /* decode the SMB pipe protocol
2663    for requests
2664     pipe is the name of the pipe, e.g. LANMAN
2665     smb_info->trans_subcmd is set to the symbolic constant matching the mailslot name
2666   for responses
2667     pipe is NULL
2668     smb_info->trans_subcmd gives us which pipe this response is for
2669 */
2670 gboolean
2671 dissect_pipe_smb(tvbuff_t *sp_tvb, tvbuff_t *s_tvb, tvbuff_t *pd_tvb,
2672                  tvbuff_t *p_tvb, tvbuff_t *d_tvb, const char *pipe,
2673                  packet_info *pinfo, proto_tree *tree)
2674 {
2675         smb_info_t *smb_info;
2676         smb_transact_info_t *tri;
2677         guint sp_len;
2678         proto_item *pipe_item = NULL;
2679         proto_tree *pipe_tree = NULL;
2680         int offset;
2681         int trans_subcmd;
2682         int function;
2683         int fid = -1;
2684         guint16 info_level;
2685
2686         if (!proto_is_protocol_enabled(proto_smb_pipe))
2687                 return FALSE;
2688         pinfo->current_proto = "SMB Pipe";
2689
2690         smb_info = pinfo->private_data;
2691
2692         /*
2693          * Set the columns.
2694          */
2695         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2696                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMB Pipe");
2697         }
2698         if (check_col(pinfo->cinfo, COL_INFO)) {
2699                 col_set_str(pinfo->cinfo, COL_INFO,
2700                     smb_info->request ? "Request" : "Response");
2701         }
2702
2703         if (smb_info->sip != NULL)
2704                 tri = smb_info->sip->extra_info;
2705         else
2706                 tri = NULL;
2707
2708         /*
2709          * Set up a subtree for the pipe protocol.  (It might not contain
2710          * anything.)
2711          */
2712         if (sp_tvb != NULL)
2713                 sp_len = tvb_length(sp_tvb);
2714         else
2715                 sp_len = 0;
2716         if (tree) {
2717                 pipe_item = proto_tree_add_item(tree, proto_smb_pipe,
2718                     sp_tvb, 0, sp_len, FALSE);
2719                 pipe_tree = proto_item_add_subtree(pipe_item, ett_smb_pipe);
2720         }
2721         offset = 0;
2722
2723         /*
2724          * Do we have any setup words at all?
2725          */
2726         if (s_tvb != NULL && tvb_length(s_tvb) != 0) {
2727                 /*
2728                  * Yes.  The first of them is the function.
2729                  */
2730                 function = tvb_get_letohs(s_tvb, offset);
2731                 proto_tree_add_uint(pipe_tree, hf_pipe_function, s_tvb,
2732                     offset, 2, function);
2733                 offset += 2;
2734                 if (check_col(pinfo->cinfo, COL_INFO)) {
2735                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2736                             val_to_str(function, functions, "Unknown function (0x%04x)"),
2737                             smb_info->request ? "Request" : "Response");
2738                 }
2739                 if (tri != NULL)
2740                         tri->function = function;
2741
2742                 /*
2743                  * The second of them depends on the function.
2744                  */
2745                 switch (function) {
2746
2747                 case CALL_NAMED_PIPE:
2748                 case WAIT_NAMED_PIPE:
2749                         /*
2750                          * It's a priority.
2751                          */
2752                         proto_tree_add_item(pipe_tree, hf_pipe_priority, s_tvb,
2753                             offset, 2, TRUE);
2754                         break;
2755
2756                 case PEEK_NAMED_PIPE:
2757                 case Q_NM_P_HAND_STATE:
2758                 case SET_NM_P_HAND_STATE:
2759                 case Q_NM_PIPE_INFO:
2760                 case TRANSACT_NM_PIPE:
2761                 case RAW_READ_NM_PIPE:
2762                 case RAW_WRITE_NM_PIPE:
2763                         /*
2764                          * It's a FID.
2765                          */
2766                         fid = tvb_get_letohs(s_tvb, 2);
2767                         add_fid(s_tvb, pinfo, pipe_tree, offset, 2, fid);
2768                         if (tri != NULL)
2769                                 tri->fid = fid;
2770                         break;
2771
2772                 default:
2773                         /*
2774                          * It's something unknown.
2775                          * XXX - put it into the tree?
2776                          */
2777                         break;
2778                 }
2779                 offset += 2;
2780         } else {
2781                 /*
2782                  * This is either a response or a pipe transaction with
2783                  * no setup information.
2784                  *
2785                  * In the former case, we can get that information from
2786                  * the matching request, if we saw it.
2787                  *
2788                  * In the latter case, there is no function or FID.
2789                  */
2790                 if (tri != NULL && tri->function != -1) {
2791                         function = tri->function;
2792                         proto_tree_add_uint(pipe_tree, hf_pipe_function, NULL,
2793                             0, 0, function);
2794                         if (check_col(pinfo->cinfo, COL_INFO)) {
2795                                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2796                                     val_to_str(function, functions, "Unknown function (0x%04x)"),
2797                                     smb_info->request ? "Request" : "Response");
2798                         }
2799                         fid = tri->fid;
2800                         if (fid != -1)
2801                                 add_fid(NULL, pinfo, pipe_tree, 0, 0, fid);
2802                 } else {
2803                         function = -1;
2804                         fid = -1;
2805                 }
2806         }
2807
2808         /*
2809          * XXX - put the byte count and the pipe name into the tree as well;
2810          * that requires us to fetch a possibly-Unicode string.
2811          */
2812
2813         if(smb_info->request){
2814                 if(strncmp(pipe,"LANMAN",6) == 0){
2815                         trans_subcmd=PIPE_LANMAN;
2816                 } else {
2817                         /* assume it is DCERPC */
2818                         trans_subcmd=PIPE_DCERPC;
2819                 }
2820                 
2821                 if (!pinfo->fd->flags.visited)
2822                         tri->trans_subcmd = trans_subcmd;
2823         } else
2824                 trans_subcmd = tri->trans_subcmd;
2825
2826         if (tri == NULL) {
2827                 /*
2828                  * We don't know what type of pipe transaction this
2829                  * was, so indicate that we didn't dissect it.
2830                  */
2831                 return FALSE;
2832         }
2833
2834         switch (function) {
2835
2836         case CALL_NAMED_PIPE:
2837         case TRANSACT_NM_PIPE:
2838                 switch(trans_subcmd){
2839
2840                 case PIPE_LANMAN:
2841                         return dissect_pipe_lanman(pd_tvb, p_tvb, d_tvb, pinfo,
2842                             tree);
2843                         break;
2844
2845                 case PIPE_DCERPC:
2846                         /*
2847                          * Only dissect this if we know the FID.
2848                          */
2849                         if (fid != -1) {
2850                                 if (d_tvb == NULL)
2851                                         return FALSE;
2852                                 return dissect_pipe_dcerpc(d_tvb, pinfo, tree,
2853                                     pipe_tree, fid);
2854                         }
2855                         break;
2856                 }
2857                 break;
2858
2859         case -1:
2860                 /*
2861                  * We don't know the function; we dissect only LANMAN
2862                  * pipe messages, not RPC pipe messages, in that case.
2863                  */
2864                 switch(trans_subcmd){
2865                 case PIPE_LANMAN:
2866                         return dissect_pipe_lanman(pd_tvb, p_tvb, d_tvb, pinfo,
2867                             tree);
2868                         break;
2869                 }
2870                 break;
2871
2872         case WAIT_NAMED_PIPE:
2873                 break;
2874
2875         case PEEK_NAMED_PIPE:
2876                 /*
2877                  * Request contains no parameters or data.
2878                  */
2879                 if (!smb_info->request) {
2880                         if (p_tvb == NULL)
2881                                 return FALSE;
2882                         offset = 0;
2883                         proto_tree_add_item(pipe_tree, hf_pipe_peek_available,
2884                             p_tvb, offset, 2, TRUE);
2885                         offset += 2;
2886                         proto_tree_add_item(pipe_tree, hf_pipe_peek_remaining,
2887                             p_tvb, offset, 2, TRUE);
2888                         offset += 2;
2889                         proto_tree_add_item(pipe_tree, hf_pipe_peek_status,
2890                             p_tvb, offset, 2, TRUE);
2891                         offset += 2;
2892                 }
2893                 break;
2894
2895         case Q_NM_P_HAND_STATE:
2896                 /*
2897                  * Request contains no parameters or data.
2898                  */
2899                 if (!smb_info->request) {
2900                         if (p_tvb == NULL)
2901                                 return FALSE;
2902                         offset = dissect_ipc_state(p_tvb, pinfo, pipe_tree, 0,
2903                             FALSE);
2904                 }
2905                 break;
2906
2907         case SET_NM_P_HAND_STATE:
2908                 /*
2909                  * Response contains no parameters or data.
2910                  */
2911                 if (smb_info->request) {
2912                         if (p_tvb == NULL)
2913                                 return FALSE;
2914                         offset = dissect_ipc_state(p_tvb, pinfo, pipe_tree, 0,
2915                             TRUE);
2916                 }
2917                 break;
2918
2919         case Q_NM_PIPE_INFO:
2920                 offset = 0;
2921                 if (smb_info->request) {
2922                         if (p_tvb == NULL)
2923                                 return FALSE;
2924
2925                         /*
2926                          * Request contains an information level.
2927                          */
2928                         info_level = tvb_get_letohs(p_tvb, offset);
2929                         proto_tree_add_uint(pipe_tree, hf_pipe_getinfo_info_level,
2930                             p_tvb, offset, 2, info_level);
2931                         offset += 2;
2932                         if (!pinfo->fd->flags.visited)
2933                                 tri->info_level = info_level;
2934                 } else {
2935                         guint8 pipe_namelen;
2936
2937                         if (d_tvb == NULL)
2938                                 return FALSE;
2939
2940                         switch (tri->info_level) {
2941
2942                         case 1:
2943                                 proto_tree_add_item(pipe_tree,
2944                                     hf_pipe_getinfo_output_buffer_size,
2945                                     d_tvb, offset, 2, TRUE);
2946                                 offset += 2;
2947                                 proto_tree_add_item(pipe_tree,
2948                                     hf_pipe_getinfo_input_buffer_size,
2949                                     d_tvb, offset, 2, TRUE);
2950                                 offset += 2;
2951                                 proto_tree_add_item(pipe_tree,
2952                                     hf_pipe_getinfo_maximum_instances,
2953                                     d_tvb, offset, 1, TRUE);
2954                                 offset += 1;
2955                                 proto_tree_add_item(pipe_tree,
2956                                     hf_pipe_getinfo_current_instances,
2957                                     d_tvb, offset, 1, TRUE);
2958                                 offset += 1;
2959                                 pipe_namelen = tvb_get_guint8(d_tvb, offset);
2960                                 proto_tree_add_uint(pipe_tree,
2961                                     hf_pipe_getinfo_pipe_name_length,
2962                                     d_tvb, offset, 1, pipe_namelen);
2963                                 offset += 1;
2964                                 /* XXX - can this be Unicode? */
2965                                 proto_tree_add_item(pipe_tree,
2966                                     hf_pipe_getinfo_pipe_name,
2967                                     d_tvb, offset, pipe_namelen, TRUE);
2968                                 break;
2969                         }
2970                 }
2971                 break;
2972
2973         case RAW_READ_NM_PIPE:
2974                 /*
2975                  * Request contains no parameters or data.
2976                  */
2977                 if (!smb_info->request) {
2978                         if (d_tvb == NULL)
2979                                 return FALSE;
2980
2981                         offset = dissect_file_data(d_tvb, pinfo, pipe_tree, 0,
2982                             tvb_reported_length(d_tvb),
2983                             tvb_reported_length(d_tvb));
2984                 }
2985                 break;
2986
2987         case RAW_WRITE_NM_PIPE:
2988                 offset = 0;
2989                 if (smb_info->request) {
2990                         if (d_tvb == NULL)
2991                                 return FALSE;
2992
2993                         offset = dissect_file_data(d_tvb, pinfo, pipe_tree,
2994                             offset, tvb_reported_length(d_tvb),
2995                             tvb_reported_length(d_tvb));
2996                 } else {
2997                         if (p_tvb == NULL)
2998                                 return FALSE;
2999                         proto_tree_add_item(pipe_tree,
3000                             hf_pipe_write_raw_bytes_written,
3001                             p_tvb, offset, 2, TRUE);
3002                         offset += 2;
3003                 }
3004                 break;
3005         }
3006         return TRUE;
3007 }
3008
3009 void
3010 proto_register_smb_pipe(void)
3011 {
3012         static hf_register_info hf[] = {
3013                 { &hf_pipe_function,
3014                         { "Function", "pipe.function", FT_UINT16, BASE_HEX,
3015                         VALS(functions), 0, "SMB Pipe Function Code", HFILL }},
3016                 { &hf_pipe_priority,
3017                         { "Priority", "pipe.priority", FT_UINT16, BASE_DEC,
3018                         NULL, 0, "SMB Pipe Priority", HFILL }},
3019                 { &hf_pipe_peek_available,
3020                         { "Available Bytes", "pipe.peek.available_bytes", FT_UINT16, BASE_DEC,
3021                         NULL, 0, "Total number of bytes available to be read from the pipe", HFILL }},
3022                 { &hf_pipe_peek_remaining,
3023                         { "Bytes Remaining", "pipe.peek.remaining_bytes", FT_UINT16, BASE_DEC,
3024                         NULL, 0, "Total number of bytes remaining in the message at the head of the pipe", HFILL }},
3025                 { &hf_pipe_peek_status,
3026                         { "Pipe Status", "pipe.peek.status", FT_UINT16, BASE_DEC,
3027                         VALS(pipe_status), 0, "Pipe status", HFILL }},
3028                 { &hf_pipe_getinfo_info_level,
3029                         { "Information Level", "pipe.getinfo.info_level", FT_UINT16, BASE_DEC,
3030                         NULL, 0, "Information level of information to return", HFILL }},
3031                 { &hf_pipe_getinfo_output_buffer_size,
3032                         { "Output Buffer Size", "pipe.getinfo.output_buffer_size", FT_UINT16, BASE_DEC,
3033                         NULL, 0, "Actual size of buffer for outgoing (server) I/O", HFILL }},
3034                 { &hf_pipe_getinfo_input_buffer_size,
3035                         { "Input Buffer Size", "pipe.getinfo.input_buffer_size", FT_UINT16, BASE_DEC,
3036                         NULL, 0, "Actual size of buffer for incoming (client) I/O", HFILL }},
3037                 { &hf_pipe_getinfo_maximum_instances,
3038                         { "Maximum Instances", "pipe.getinfo.maximum_instances", FT_UINT8, BASE_DEC,
3039                         NULL, 0, "Maximum allowed number of instances", HFILL }},
3040                 { &hf_pipe_getinfo_current_instances,
3041                         { "Current Instances", "pipe.getinfo.current_instances", FT_UINT8, BASE_DEC,
3042                         NULL, 0, "Current number of instances", HFILL }},
3043                 { &hf_pipe_getinfo_pipe_name_length,
3044                         { "Pipe Name Length", "pipe.getinfo.pipe_name_length", FT_UINT8, BASE_DEC,
3045                         NULL, 0, "Length of pipe name", HFILL }},
3046                 { &hf_pipe_getinfo_pipe_name,
3047                         { "Pipe Name", "pipe.getinfo.pipe_name", FT_STRING, BASE_NONE,
3048                         NULL, 0, "Name of pipe", HFILL }},
3049                 { &hf_pipe_write_raw_bytes_written,
3050                         { "Bytes Written", "pipe.write_raw.bytes_written", FT_UINT16, BASE_DEC,
3051                         NULL, 0, "Number of bytes written to the pipe", HFILL }},
3052         };
3053         static gint *ett[] = {
3054                 &ett_smb_pipe,
3055                 &ett_smb_pipe_fragments,
3056         };
3057
3058         proto_smb_pipe = proto_register_protocol(
3059                 "SMB Pipe Protocol", "SMB Pipe", "pipe");
3060
3061         proto_register_field_array(proto_smb_pipe, hf, array_length(hf));
3062         proto_register_subtree_array(ett, array_length(ett));
3063 }
3064
3065 void
3066 proto_reg_handoff_smb_pipe(void)
3067 {
3068   data_handle = find_dissector("data");
3069 }