Have "dissect_netbios_payload()" take as an argument a tvbuff containing
[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.35 2001/09/14 07:10:05 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 "packet.h"
53 #include "conversation.h"
54 #include "smb.h"
55 #include "packet-smb-pipe.h"
56 #include "packet-smb-browse.h"
57
58 static int proto_smb_lanman = -1;
59 static int hf_function_code = -1;
60 static int hf_param_desc = -1;
61 static int hf_return_desc = -1;
62 static int hf_aux_data_desc = -1;
63 static int hf_detail_level = -1;
64 static int hf_recv_buf_len = -1;
65 static int hf_send_buf_len = -1;
66 static int hf_response_to = -1;
67 static int hf_continuation_from = -1;
68 static int hf_status = -1;
69 static int hf_convert = -1;
70 static int hf_ecount = -1;
71 static int hf_acount = -1;
72 static int hf_share_name = -1;
73 static int hf_share_type = -1;
74 static int hf_share_comment = -1;
75 static int hf_share_permissions = -1;
76 static int hf_share_max_uses = -1;
77 static int hf_share_current_uses = -1;
78 static int hf_share_path = -1;
79 static int hf_share_password = -1;
80 static int hf_server_name = -1;
81 static int hf_server_major = -1;
82 static int hf_server_minor = -1;
83 static int hf_server_comment = -1;
84 static int hf_abytes = -1;
85 static int hf_current_time = -1;
86 static int hf_msecs = -1;
87 static int hf_hour = -1;
88 static int hf_minute = -1;
89 static int hf_second = -1;
90 static int hf_hundredths = -1;
91 static int hf_tzoffset = -1;
92 static int hf_timeinterval = -1;
93 static int hf_day = -1;
94 static int hf_month = -1;
95 static int hf_year = -1;
96 static int hf_weekday = -1;
97 static int hf_enumeration_domain = -1;
98 static int hf_computer_name = -1;
99 static int hf_user_name = -1;
100 static int hf_workstation_domain = -1;
101 static int hf_workstation_major = -1;
102 static int hf_workstation_minor = -1;
103 static int hf_logon_domain = -1;
104 static int hf_other_domains = -1;
105 static int hf_password = -1;
106 static int hf_workstation_name = -1;
107 static int hf_ustruct_size = -1;
108 static int hf_logon_code = -1;
109 static int hf_privilege_level = -1;
110 static int hf_operator_privileges = -1;
111 static int hf_num_logons = -1;
112 static int hf_bad_pw_count = -1;
113 static int hf_last_logon = -1;
114 static int hf_last_logoff = -1;
115 static int hf_logoff_time = -1;
116 static int hf_kickoff_time = -1;
117 static int hf_password_age = -1;
118 static int hf_password_can_change = -1;
119 static int hf_password_must_change = -1;
120 static int hf_script_path = -1;
121 static int hf_logoff_code = -1;
122 static int hf_duration = -1;
123 static int hf_user_comment = -1;
124 static int hf_full_name = -1;
125 static int hf_homedir = -1;
126 static int hf_parameters = -1;
127 static int hf_logon_server = -1;
128 static int hf_country_code = -1;
129 static int hf_workstations = -1;
130 static int hf_max_storage = -1;
131 static int hf_units_per_week = -1;
132 static int hf_logon_hours = -1;
133 static int hf_code_page = -1;
134 static int hf_new_password = -1;
135 static int hf_old_password = -1;
136 static int hf_reserved = -1;
137
138 static gint ett_lanman = -1;
139 static gint ett_lanman_shares = -1;
140 static gint ett_lanman_share = -1;
141 static gint ett_lanman_servers = -1;
142 static gint ett_lanman_server = -1;
143
144 /*
145  * See
146  *
147  *      ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt
148  *
149  * among other documents.
150  */
151
152 static const value_string status_vals[] = {
153         {0,     "Success"},
154         {5,     "User has insufficient privilege"},
155         {65,    "Network access is denied"},
156         {86,    "The specified password is invalid"},
157         {SMBE_moredata, "Additional data is available"},
158         {2114,  "Service is not running on the remote computer"},
159         {2123,  "Supplied buffer is too small"},
160         {2141,  "Server is not configured for transactions (IPC$ not shared)"},
161         {2212,  "An error occurred while loading or running the logon script"},
162         {2214,  "The logon was not validated by any server"},
163         {2217,  "The logon server is running an older software version"},
164         {2221,  "The user name was not found"},
165         {2240,  "The user is not allowed to logon from this computer"},
166         {2241,  "The user is not allowed to logon at this time"},
167         {2242,  "The user password has expired"},
168         {2243,  "The password cannot be changed"},
169         {2246,  "The password is too short"},
170         {0,     NULL}
171 };
172
173 static const value_string share_type_vals[] = {
174         {0, "Directory tree"},
175         {1, "Printer queue"},
176         {2, "Communications device"},
177         {3, "IPC"},
178         {0, NULL}
179 };
180
181 static const value_string privilege_vals[] = {
182         {0, "Guest"},
183         {1, "User"},
184         {2, "Administrator"},
185         {0, NULL}
186 };
187
188 static const value_string op_privilege_vals[] = {
189         {0, "Print operator"},
190         {1, "Communications operator"},
191         {2, "Server operator"},
192         {3, "Accounts operator"},
193         {0, NULL}
194 };
195
196 static const value_string weekday_vals[] = {
197         {0, "Sunday"},
198         {1, "Monday"},
199         {2, "Tuesday"},
200         {3, "Wednesday"},
201         {4, "Thursday"},
202         {5, "Friday"},
203         {6, "Saturday"},
204         {0, NULL}
205 };
206
207 static int
208 add_word_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
209     proto_tree *tree, int convert, int hf_index)
210 {
211         guint16 WParam;
212
213         if (hf_index != -1)
214                 proto_tree_add_item(tree, hf_index, tvb, offset, 2, TRUE);
215         else {
216                 WParam = tvb_get_letohs(tvb, offset);
217                 proto_tree_add_text(tree, tvb, offset, 2,
218                     "Word Param: %u (0x%04X)", WParam, WParam);
219         }
220         offset += 2;
221         return offset;
222 }
223
224 static int
225 add_dword_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
226     proto_tree *tree, int convert, int hf_index)
227 {
228         guint32 LParam;
229
230         if (hf_index != -1)
231                 proto_tree_add_item(tree, hf_index, tvb, offset, 4, TRUE);
232         else {
233                 LParam = tvb_get_letohl(tvb, offset);
234                 proto_tree_add_text(tree, tvb, offset, 4,
235                     "Doubleword Param: %u (0x%08X)", LParam, LParam);
236         }
237         offset += 4;
238         return offset;
239 }
240
241 static int
242 add_byte_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
243     proto_tree *tree, int convert, int hf_index)
244 {
245         guint8 BParam;
246
247         if (hf_index != -1)
248                 proto_tree_add_item(tree, hf_index, tvb, offset, count, TRUE);
249         else {
250                 if (count == 1) {
251                         BParam = tvb_get_guint8(tvb, offset);
252                         proto_tree_add_text(tree, tvb, offset, count,
253                             "Byte Param: %u (0x%02X)",
254                             BParam, BParam);
255                 } else {
256                         proto_tree_add_text(tree, tvb, offset, count,
257                             "Bytes Param: %s, type is wrong",
258                             tvb_bytes_to_str(tvb, offset, count));
259                 }
260         }
261         offset += count;
262         return offset;
263 }
264
265 static int
266 add_pad_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
267     proto_tree *tree, int convert, int hf_index)
268 {
269         /*
270          * This is for parameters that have descriptor entries but that
271          * are, in practice, just padding.
272          */
273         offset += count;
274         return offset;
275 }
276
277 static void
278 add_null_pointer_param(tvbuff_t *tvb, int offset, int count,
279     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
280 {
281         if (hf_index != -1) {
282                 proto_tree_add_text(tree, tvb, offset, 0,
283                   "%s (Null pointer)",
284                   proto_registrar_get_name(hf_index));
285         } else {
286                 proto_tree_add_text(tree, tvb, offset, 0,
287                     "String Param (Null pointer)");
288         }
289 }
290
291 static int
292 add_string_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
293     proto_tree *tree, int convert, int hf_index)
294 {
295         guint string_len;
296
297         string_len = tvb_strsize(tvb, offset);
298         if (hf_index != -1) {
299                 proto_tree_add_item(tree, hf_index, tvb, offset, string_len,
300                     TRUE);
301         } else {
302                 proto_tree_add_text(tree, tvb, offset, string_len,
303                     "String Param: %s",
304                     tvb_format_text(tvb, offset, string_len));
305         }
306         offset += string_len;
307         return offset;
308 }
309
310 static const char *
311 get_pointer_value(tvbuff_t *tvb, int offset, int convert, int *cptrp, int *lenp)
312 {
313         int cptr;
314         gint string_len;
315
316         /* pointer to string */
317         cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
318         *cptrp = cptr;
319
320         /* string */
321         if (tvb_offset_exists(tvb, cptr) &&
322             (string_len = tvb_strnlen(tvb, cptr, -1)) != -1) {
323                 string_len++;   /* include the terminating '\0' */
324                 *lenp = string_len;
325                 return tvb_format_text(tvb, offset, string_len);
326         } else
327                 return NULL;
328 }
329
330 static int
331 add_pointer_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
332     proto_tree *tree, int convert, int hf_index)
333 {
334         int cptr;
335         const char *string;
336         gint string_len;
337
338         string = get_pointer_value(tvb, offset, convert, &cptr, &string_len);
339         offset += 4;
340
341         /* string */
342         if (string != NULL) {
343                 if (hf_index != -1) {
344                         proto_tree_add_item(tree, hf_index, tvb, cptr,
345                             string_len, TRUE);
346                 } else {
347                         proto_tree_add_text(tree, tvb, offset, string_len,
348                             "String Param: %s", string);
349                 }
350         } else {
351                 if (hf_index != -1) {
352                         proto_tree_add_text(tree, tvb, 0, 0,
353                             "%s: <String goes past end of frame>",
354                             proto_registrar_get_name(hf_index));
355                 } else {
356                         proto_tree_add_text(tree, tvb, 0, 0,
357                             "String Param: <String goes past end of frame>");
358                 }
359         }
360
361         return offset;
362 }
363
364 static int
365 add_detail_level(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
366     proto_tree *tree, int convert, int hf_index)
367 {
368         struct smb_info *smb_info = pinfo->private;
369         struct smb_request_val *request_val = smb_info->request_val;
370         guint16 level;
371
372         level = tvb_get_letohs(tvb, offset);
373         if (!pinfo->fd->flags.visited)
374                 request_val->last_level = level;        /* remember this for the response */
375         proto_tree_add_uint(tree, hf_index, tvb, offset, 2, level);
376         offset += 2;
377         return offset;
378 }
379
380 static int
381 add_max_uses(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
382     proto_tree *tree, int convert, int hf_index)
383 {
384         guint16 WParam;
385
386         WParam = tvb_get_letohs(tvb, offset);
387         if (WParam == 0xffff) { /* -1 */
388                 proto_tree_add_uint_format(tree, hf_index, tvb,
389                     offset, 2, WParam,
390                     "%s: No limit",
391                     proto_registrar_get_name(hf_index));
392         } else {
393                 proto_tree_add_uint(tree, hf_index, tvb,
394                             offset, 2, WParam);
395         }
396         offset += 2;
397         return offset;
398 }
399
400 static int
401 add_server_type(tvbuff_t *tvb, int offset, int count,
402     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
403 {
404         dissect_smb_server_type_flags(tvb, pinfo, tree, offset, FALSE);
405         offset += 4;
406         return offset;
407 }
408
409 static int
410 add_server_type_info(tvbuff_t *tvb, int offset, int count,
411     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
412 {
413         dissect_smb_server_type_flags(tvb, pinfo, tree, offset, TRUE);
414         offset += 4;
415         return offset;
416 }
417
418 static int
419 add_reltime(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
420     proto_tree *tree, int convert, int hf_index)
421 {
422         nstime_t nstime;
423
424         nstime.secs = tvb_get_letohl(tvb, offset);
425         nstime.nsecs = 0;
426         proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
427             &nstime, "%s: %s", proto_registrar_get_name(hf_index),
428             time_secs_to_str(nstime.secs));
429         offset += 4;
430         return offset;
431 }
432
433 /*
434  * Sigh.  These are for handling Microsoft's annoying almost-UNIX-time-but-
435  * it's-local-time-not-UTC time.
436  */
437 static int
438 add_abstime_common(tvbuff_t *tvb, int offset, int count,
439     packet_info *pinfo, proto_tree *tree, int convert, int hf_index,
440     const char *absent_name)
441 {
442         nstime_t nstime;
443         struct tm *tmp;
444
445         nstime.secs = tvb_get_letohl(tvb, offset);
446         nstime.nsecs = 0;
447         if (nstime.secs == -1) {
448                 proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
449                     &nstime, "%s: %s", proto_registrar_get_name(hf_index),
450                     absent_name);
451         } else {
452                 /*
453                  * Run it through "gmtime()" to break it down, and then
454                  * run it through "mktime()" to put it back together
455                  * as UTC.
456                  */
457                 tmp = gmtime(&nstime.secs);
458                 tmp->tm_isdst = -1;     /* we don't know if it's DST or not */
459                 nstime.secs = mktime(tmp);
460                 proto_tree_add_time(tree, hf_index, tvb, offset, 4,
461                     &nstime);
462         }
463         offset += 4;
464         return offset;
465 }
466
467 static int
468 add_abstime_absent_never(tvbuff_t *tvb, int offset, int count,
469     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
470 {
471         return add_abstime_common(tvb, offset, count, pinfo, tree,
472             convert, hf_index, "Never");
473 }
474
475 static int
476 add_abstime_absent_unknown(tvbuff_t *tvb, int offset, int count,
477     packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
478 {
479         return add_abstime_common(tvb, offset, count, pinfo, tree,
480             convert, hf_index, "Unknown");
481 }
482
483 static int
484 add_nlogons(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
485     proto_tree *tree, int convert, int hf_index)
486 {
487         guint16 nlogons;
488
489         nlogons = tvb_get_letohs(tvb, offset);
490         if (nlogons == 0xffff)  /* -1 */
491                 proto_tree_add_uint_format(tree, hf_index, tvb, offset, 2,
492                     nlogons, "%s: Unknown",
493                     proto_registrar_get_name(hf_index));
494         else
495                 proto_tree_add_uint(tree, hf_index, tvb, offset, 2,
496                     nlogons);
497         offset += 2;
498         return offset;
499 }
500
501 static int
502 add_max_storage(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
503     proto_tree *tree, int convert, int hf_index)
504 {
505         guint32 max_storage;
506
507         max_storage = tvb_get_letohl(tvb, offset);
508         if (max_storage == 0xffffffff)
509                 proto_tree_add_uint_format(tree, hf_index, tvb, offset, 4,
510                     max_storage, "%s: No limit",
511                     proto_registrar_get_name(hf_index));
512         else
513                 proto_tree_add_uint(tree, hf_index, tvb, offset, 4,
514                     max_storage);
515         offset += 4;
516         return offset;
517 }
518
519 static int
520 add_logon_hours(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
521     proto_tree *tree, int convert, int hf_index)
522 {
523         int cptr;
524
525         /* pointer to string */
526         cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
527         offset += 4;
528
529         /* string */
530         /* XXX - should actually carve up the bits */
531         proto_tree_add_item(tree, hf_index, tvb, cptr, 21, TRUE);
532
533         return offset;
534 }
535
536 static int
537 add_tzoffset(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
538     proto_tree *tree, int convert, int hf_index)
539 {
540         gint16 tzoffset;
541
542         tzoffset = tvb_get_letohs(tvb, offset);
543         if (tzoffset < 0) {
544                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
545                     tzoffset, "%s: %s east of UTC",
546                     proto_registrar_get_name(hf_index),
547                     time_secs_to_str(-tzoffset*60));
548         } else if (tzoffset > 0) {
549                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
550                     tzoffset, "%s: %s west of UTC",
551                     proto_registrar_get_name(hf_index),
552                     time_secs_to_str(tzoffset*60));
553         } else {
554                 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
555                     tzoffset, "%s: at UTC",
556                     proto_registrar_get_name(hf_index));
557         }
558         offset += 2;
559         return offset;
560 }
561
562 static int
563 add_timeinterval(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
564     proto_tree *tree, int convert, int hf_index)
565 {
566         guint16 timeinterval;
567
568         timeinterval = tvb_get_letohs(tvb, offset);
569         proto_tree_add_uint_format(tree, hf_timeinterval, tvb, offset, 2,
570            timeinterval, "%s: %f seconds", proto_registrar_get_name(hf_index),
571            timeinterval*.0001);
572         offset += 2;
573         return offset;
574 }
575
576 static int
577 add_logon_args(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
578     proto_tree *tree, int convert, int hf_index)
579 {
580         if (count != 54) {
581                 proto_tree_add_text(tree, tvb, offset, count,
582                    "Bogus NetWkstaUserLogon parameters: length is %d, should be 54",
583                    count);
584                 offset += count;
585                 return offset;
586         }
587
588         /* user name */
589         proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
590         offset += 21;
591
592         /* pad1 */
593         offset += 1;
594
595         /* password */
596         proto_tree_add_item(tree, hf_password, tvb, offset, 15, TRUE);
597         offset += 15;
598
599         /* pad2 */
600         offset += 1;
601
602         /* workstation name */
603         proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE);
604         offset += 16;
605         return offset;
606 }
607
608 /* 
609  * The following data structure describes the Remote API requests we
610  * understand.
611  *
612  * Simply fill in the number and parameter information.
613  * Try to keep them in order.
614  *
615  * We will extend this data structure as we try to decode more.
616  */
617
618 /*
619  * This is a pointer to a function to process an item.
620  */
621 typedef int     (*item_func)(tvbuff_t *, int, int, packet_info *, proto_tree *,
622                              int, int);
623
624 /*
625  * Type of an item; determines what parameter strings are valid for
626  * the item.
627  */
628 typedef enum {
629         PARAM_NONE,     /* for the end-of-list stopper */
630         PARAM_WORD,     /* 'W' or 'h' - 16-bit word */
631         PARAM_DWORD,    /* 'D' or 'i' - 32-bit word */
632         PARAM_BYTES,    /* 'B' or 'b' or 'g' or 'O' - one or more bytes */
633         PARAM_STRINGZ,  /* 'z' or 'O' - null-terminated string */
634 } param_type_t;
635
636 /*
637  * This structure describes an item; "hf_index" points to the index
638  * for the field corresponding to that item, "func" points to the
639  * function to use to add that item to the tree, and "type" is the
640  * type that the item is supposed to have.
641  */
642 typedef struct {
643         int             *hf_index;
644         item_func       func;
645         param_type_t    type;
646 } item_t;
647
648 /*
649  * This structure describes a list of items; each list of items
650  * has a corresponding detail level.
651  */
652 typedef struct {
653         int             level;
654         const item_t    *item_list;
655 } item_list_t;
656
657 struct lanman_desc {
658         int             lanman_num;
659         const item_t    *req;
660         proto_item      *(*req_data_item)(tvbuff_t *, packet_info *,
661                                           proto_tree *, int);
662         gint            *ett_req_data;
663         const item_t    *req_data;
664         const item_t    *req_aux_data;
665         const item_t    *resp;
666         proto_item      *(*resp_data_item)(tvbuff_t *, packet_info *,
667                                            proto_tree *, int);
668         gint            *ett_resp_data;
669         proto_item      *(*resp_data_element_item)(tvbuff_t *, packet_info *,
670                                                    proto_tree *, int);
671         gint            *ett_resp_data_element_item;
672         const item_list_t *resp_data_list;
673         const item_t    *resp_aux_data;
674 };
675
676 static int no_hf = -1;  /* for padding crap */
677
678 static const item_t lm_params_req_netshareenum[] = {
679         { &hf_detail_level, add_detail_level, PARAM_WORD },
680         { &hf_recv_buf_len, add_word_param, PARAM_WORD },
681         { NULL, NULL, PARAM_NONE }
682 };
683
684 static const item_t lm_params_resp_netshareenum[] = {
685         { &hf_acount, add_word_param, PARAM_WORD },
686         { NULL, NULL, PARAM_NONE }
687 };
688
689 /*
690  * Create a subtree for all available shares.
691  */
692 static proto_item *
693 netshareenum_shares_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
694     int offset)
695 {
696         if (tree) {
697                 return proto_tree_add_text(tree, tvb, offset,
698                     tvb_length_remaining(tvb, offset),
699                     "Available Shares");
700         } else
701                 return NULL;
702 }
703
704 /*
705  * Create a subtree for a share.
706  */
707 static proto_item *
708 netshareenum_share_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
709     int offset)
710 {
711         if (tree) {
712                 return proto_tree_add_text(tree, tvb, offset,
713                     tvb_length_remaining(tvb, offset),
714                     "Share %.13s", tvb_get_ptr(tvb, offset, 13));
715         } else
716                 return NULL;
717 }
718
719 static const item_t lm_null[] = {
720         { NULL, NULL, PARAM_NONE }
721 };
722
723 static const item_list_t lm_null_list[] = {
724         { 0, lm_null }
725 };
726
727 static const item_t lm_data_resp_netshareenum_1[] = {
728         { &hf_share_name, add_byte_param, PARAM_BYTES },
729         { &no_hf, add_pad_param, PARAM_BYTES },
730         { &hf_share_type, add_word_param, PARAM_WORD },
731         { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
732         { NULL, NULL, PARAM_NONE }
733 };
734
735 static const item_list_t lm_data_resp_netshareenum[] = {
736         { 1, lm_data_resp_netshareenum_1 },
737         { -1, lm_null }
738 };
739
740 static const item_t lm_params_req_netsharegetinfo[] = {
741         { &hf_share_name, add_string_param, PARAM_STRINGZ },
742         { &hf_detail_level, add_detail_level, PARAM_WORD },
743         { NULL, NULL, PARAM_NONE }
744 };
745
746 static const item_t lm_params_resp_netsharegetinfo[] = {
747         { &hf_abytes, add_word_param, PARAM_WORD },
748         { NULL, NULL, PARAM_NONE }
749 };
750
751 static const item_t lm_data_resp_netsharegetinfo_0[] = {
752         { &hf_share_name, add_byte_param, PARAM_BYTES },
753         { NULL, NULL, PARAM_NONE }
754 };
755
756 static const item_t lm_data_resp_netsharegetinfo_1[] = {
757         { &hf_share_name, add_byte_param, PARAM_BYTES },
758         { &no_hf, add_pad_param, PARAM_BYTES },
759         { &hf_share_type, add_word_param, PARAM_WORD },
760         { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
761         { NULL, NULL, PARAM_NONE }
762 };
763
764 static const item_t lm_data_resp_netsharegetinfo_2[] = {
765         { &hf_share_name, add_byte_param, PARAM_BYTES },
766         { &no_hf, add_pad_param, PARAM_BYTES },
767         { &hf_share_type, add_word_param, PARAM_WORD },
768         { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
769         { &hf_share_permissions, add_word_param, PARAM_WORD }, /* XXX - do as bit fields */
770         { &hf_share_max_uses, add_max_uses, PARAM_WORD },
771         { &hf_share_current_uses, add_word_param, PARAM_WORD },
772         { &hf_share_path, add_pointer_param, PARAM_STRINGZ },
773         { &hf_share_password, add_byte_param, PARAM_BYTES },
774         { NULL, NULL, PARAM_NONE }
775 };
776
777 static const item_list_t lm_data_resp_netsharegetinfo[] = {
778         { 0, lm_data_resp_netsharegetinfo_0 },
779         { 1, lm_data_resp_netsharegetinfo_1 },
780         { 2, lm_data_resp_netsharegetinfo_2 },
781         { -1, lm_null }
782 };
783
784 static const item_t lm_params_req_netservergetinfo[] = {
785         { &hf_detail_level, add_detail_level, PARAM_WORD },
786         { NULL, NULL, PARAM_NONE }
787 };
788
789 static const item_t lm_params_resp_netservergetinfo[] = {
790         { &hf_abytes, add_word_param, PARAM_WORD },
791         { NULL, NULL, PARAM_NONE }
792 };
793
794 static const item_t lm_data_serverinfo_0[] = {
795         { &hf_server_name, add_byte_param, PARAM_BYTES },
796         { NULL, NULL, PARAM_NONE }
797 };
798
799 static const item_t lm_data_serverinfo_1[] = {
800         { &hf_server_name, add_byte_param, PARAM_BYTES },
801         { &hf_server_major, add_byte_param, PARAM_BYTES },
802         { &hf_server_minor, add_byte_param, PARAM_BYTES },
803         { &no_hf, add_server_type, PARAM_DWORD },
804         { &hf_server_comment, add_pointer_param, PARAM_STRINGZ },
805         { NULL, NULL, PARAM_NONE }
806 };
807
808 static const item_list_t lm_data_serverinfo[] = {
809         { 0, lm_data_serverinfo_0 },
810         { 1, lm_data_serverinfo_1 },
811         { -1, lm_null }
812 };
813
814 static const item_t lm_params_req_netusergetinfo[] = {
815         { &hf_detail_level, add_detail_level, PARAM_WORD },
816         { NULL, NULL, PARAM_NONE }
817 };
818
819 static const item_t lm_params_resp_netusergetinfo[] = {
820         { &hf_abytes, add_word_param, PARAM_WORD },
821         { NULL, NULL, PARAM_NONE }
822 };
823
824 static const item_t lm_data_resp_netusergetinfo_11[] = {
825         { &hf_user_name, add_byte_param, PARAM_BYTES },
826         { &no_hf, add_pad_param, PARAM_BYTES },
827         { &hf_user_comment, add_pointer_param, PARAM_STRINGZ },
828         { &hf_full_name, add_pointer_param, PARAM_STRINGZ },
829         { &hf_privilege_level, add_word_param, PARAM_WORD },
830         { &hf_operator_privileges, add_dword_param, PARAM_DWORD },
831         { &hf_password_age, add_reltime, PARAM_DWORD },
832         { &hf_homedir, add_pointer_param, PARAM_STRINGZ },
833         { &hf_parameters, add_pointer_param, PARAM_STRINGZ },
834         { &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
835         { &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
836         { &hf_bad_pw_count, add_word_param, PARAM_WORD },
837         { &hf_num_logons, add_nlogons, PARAM_WORD },
838         { &hf_logon_server, add_pointer_param, PARAM_STRINGZ },
839         { &hf_country_code, add_word_param, PARAM_WORD },
840         { &hf_workstations, add_pointer_param, PARAM_STRINGZ },
841         { &hf_max_storage, add_max_storage, PARAM_DWORD },
842         { &hf_logon_hours, add_logon_hours, PARAM_DWORD },
843         { &hf_code_page, add_word_param, PARAM_WORD },
844         { NULL, NULL, PARAM_NONE }
845 };
846
847 static const item_list_t lm_data_resp_netusergetinfo[] = {
848         { 11, lm_data_resp_netusergetinfo_11 },
849         { -1, lm_null }
850 };
851
852 /*
853  * Has no detail level; make it the default.
854  */
855 static const item_t lm_data_resp_netremotetod_nolevel[] = {
856         { &hf_current_time, add_abstime_absent_unknown, PARAM_DWORD },
857         { &hf_msecs, add_dword_param, PARAM_DWORD },
858         { &hf_hour, add_byte_param, PARAM_BYTES },
859         { &hf_minute, add_byte_param, PARAM_BYTES },
860         { &hf_second, add_byte_param, PARAM_BYTES },
861         { &hf_hundredths, add_byte_param, PARAM_BYTES },
862         { &hf_tzoffset, add_tzoffset, PARAM_WORD },
863         { &hf_timeinterval, add_timeinterval, PARAM_WORD },
864         { &hf_day, add_byte_param, PARAM_BYTES },
865         { &hf_month, add_byte_param, PARAM_BYTES },
866         { &hf_year, add_word_param, PARAM_WORD },
867         { &hf_weekday, add_byte_param, PARAM_BYTES },
868         { NULL, NULL, PARAM_NONE }
869 };
870
871 static const item_list_t lm_data_resp_netremotetod[] = {
872         { -1, lm_data_resp_netremotetod_nolevel },
873 };
874
875 static const item_t lm_params_req_netserverenum2[] = {
876         { &hf_detail_level, add_detail_level, PARAM_WORD },
877         { &no_hf, add_server_type_info, PARAM_DWORD },
878         { &hf_enumeration_domain, add_string_param, PARAM_STRINGZ },
879         { NULL, NULL, PARAM_NONE }
880 };
881
882 /*
883  * Create a subtree for all servers.
884  */
885 static proto_item *
886 netserverenum2_servers_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
887     int offset)
888 {
889         if (tree) {
890                 return proto_tree_add_text(tree, tvb, offset,
891                     tvb_length_remaining(tvb, offset), "Servers");
892         } else
893                 return NULL;
894 }
895
896 /*
897  * Create a subtree for a share.
898  */
899 static proto_item *
900 netserverenum2_server_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
901     int offset)
902 {
903         if (tree) {
904                 return proto_tree_add_text(tree, tvb, offset,
905                             tvb_length_remaining(tvb, offset),
906                             "Server %.16s", tvb_get_ptr(tvb, offset, 16));
907         } else
908                 return NULL;
909 }
910 static const item_t lm_params_resp_netserverenum2[] = {
911         { &hf_acount, add_word_param, PARAM_WORD },
912         { NULL, NULL, PARAM_NONE }
913 };
914
915 static const item_t lm_params_req_netwkstagetinfo[] = {
916         { &hf_detail_level, add_detail_level, PARAM_WORD },
917         { NULL, NULL, PARAM_NONE }
918 };
919
920 static const item_t lm_params_resp_netwkstagetinfo[] = {
921         { &hf_abytes, add_word_param, PARAM_WORD },
922         { NULL, NULL, PARAM_NONE }
923 };
924
925 static const item_t lm_data_resp_netwkstagetinfo_10[] = {
926         { &hf_computer_name, add_pointer_param, PARAM_STRINGZ },
927         { &hf_user_name, add_pointer_param, PARAM_STRINGZ },
928         { &hf_workstation_domain, add_pointer_param, PARAM_STRINGZ },
929         { &hf_workstation_major, add_byte_param, PARAM_BYTES },
930         { &hf_workstation_minor, add_byte_param, PARAM_BYTES },
931         { &hf_logon_domain, add_pointer_param, PARAM_STRINGZ },
932         { &hf_other_domains, add_pointer_param, PARAM_STRINGZ },
933         { NULL, NULL, PARAM_NONE }
934 };
935
936 static const item_list_t lm_data_resp_netwkstagetinfo[] = {
937         { 10, lm_data_resp_netwkstagetinfo_10 },
938         { -1, NULL }
939 };
940
941 static const item_t lm_params_req_netwkstauserlogon[] = {
942         { &no_hf, add_pointer_param, PARAM_STRINGZ },
943         { &no_hf, add_pointer_param, PARAM_STRINGZ },
944         { &hf_detail_level, add_detail_level, PARAM_WORD },
945         { &no_hf, add_logon_args, PARAM_BYTES },
946         { &hf_ustruct_size, add_word_param, PARAM_WORD },
947         { NULL, NULL, PARAM_NONE }
948 };
949
950 static const item_t lm_params_resp_netwkstauserlogon[] = {
951         { &hf_abytes, add_word_param, PARAM_WORD },
952         { NULL, NULL, PARAM_NONE }
953 };
954
955 static const item_t lm_data_resp_netwkstauserlogon_1[] = {
956         { &hf_logon_code, add_word_param, PARAM_WORD },
957         { &hf_user_name, add_byte_param, PARAM_BYTES },
958         { &no_hf, add_pad_param, PARAM_BYTES },
959         { &hf_privilege_level, add_word_param, PARAM_WORD },
960         { &hf_operator_privileges, add_dword_param, PARAM_DWORD },
961         { &hf_num_logons, add_nlogons, PARAM_WORD },
962         { &hf_bad_pw_count, add_word_param, PARAM_WORD },
963         { &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
964         { &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
965         { &hf_logoff_time, add_abstime_absent_never, PARAM_DWORD },
966         { &hf_kickoff_time, add_abstime_absent_never, PARAM_DWORD },
967         { &hf_password_age, add_reltime, PARAM_DWORD },
968         { &hf_password_can_change, add_abstime_absent_never, PARAM_DWORD },
969         { &hf_password_must_change, add_abstime_absent_never, PARAM_DWORD },
970         { &hf_server_name, add_pointer_param, PARAM_STRINGZ },
971         { &hf_logon_domain, add_pointer_param, PARAM_STRINGZ },
972         { &hf_script_path, add_pointer_param, PARAM_STRINGZ },
973         { &hf_reserved, add_dword_param, PARAM_DWORD },
974         { NULL, NULL, PARAM_NONE }
975 };
976
977 static const item_list_t lm_data_resp_netwkstauserlogon[] = {
978         { 1, lm_data_resp_netwkstauserlogon_1 },
979         { -1, NULL }
980 };
981
982 static const item_t lm_params_req_netwkstauserlogoff[] = {
983         { &hf_user_name, add_byte_param, PARAM_BYTES },
984         { &no_hf, add_pad_param, PARAM_BYTES },
985         { &hf_workstation_name, add_byte_param, PARAM_BYTES },
986         { NULL, NULL, PARAM_NONE }
987 };
988
989 static const item_t lm_params_resp_netwkstauserlogoff[] = {
990         { &hf_abytes, add_word_param, PARAM_WORD },
991         { NULL, NULL, PARAM_NONE }
992 };
993
994 static const item_t lm_data_resp_netwkstauserlogoff_1[] = {
995         { &hf_logoff_code, add_word_param, PARAM_WORD },
996         { &hf_duration, add_reltime, PARAM_DWORD },
997         { &hf_num_logons, add_nlogons, PARAM_WORD },
998         { NULL, NULL, PARAM_NONE }
999 };
1000
1001 static const item_list_t lm_data_resp_netwkstauserlogoff[] = {
1002         { 1, lm_data_resp_netwkstauserlogoff_1 },
1003         { -1, NULL }
1004 };
1005
1006 static const item_t lm_params_req_samoemchangepassword[] = {
1007         { &hf_user_name, add_string_param, PARAM_STRINGZ },
1008         { NULL, NULL, PARAM_NONE }
1009 };
1010
1011 static const item_t lm_data_req_samoemchangepassword[] = {
1012         { &hf_new_password, add_byte_param, PARAM_BYTES },
1013         { &hf_old_password, add_byte_param, PARAM_BYTES },
1014         { NULL, NULL, PARAM_NONE }
1015 };
1016
1017 #define LANMAN_NETSHAREENUM             0
1018 #define LANMAN_NETSHAREGETINFO          1
1019 #define LANMAN_NETSERVERGETINFO         13
1020 #define LANMAN_NETGROUPGETUSERS         52
1021 #define LANMAN_NETUSERGETINFO           56
1022 #define LANMAN_NETUSERGETGROUPS         59
1023 #define LANMAN_NETWKSTAGETINFO          63
1024 #define LANMAN_DOSPRINTQENUM            69
1025 #define LANMAN_DOSPRINTQGETINFO         70
1026 #define LANMAN_WPRINTQUEUEPAUSE         74
1027 #define LANMAN_WPRINTQUEUERESUME        75
1028 #define LANMAN_WPRINTJOBENUMERATE       76
1029 #define LANMAN_WPRINTJOBGETINFO         77
1030 #define LANMAN_RDOSPRINTJOBDEL          81
1031 #define LANMAN_RDOSPRINTJOBPAUSE        82
1032 #define LANMAN_RDOSPRINTJOBRESUME       83
1033 #define LANMAN_WPRINTDESTENUM           84
1034 #define LANMAN_WPRINTDESTGETINFO        85
1035 #define LANMAN_NETREMOTETOD             91
1036 #define LANMAN_WPRINTQUEUEPURGE         103
1037 #define LANMAN_NETSERVERENUM2           104
1038 #define LANMAN_WACCESSGETUSERPERMS      105
1039 #define LANMAN_SETUSERPASSWORD          115
1040 #define LANMAN_NETWKSTAUSERLOGON        132
1041 #define LANMAN_NETWKSTAUSERLOGOFF       133
1042 #define LANMAN_PRINTJOBINFO             147
1043 #define LANMAN_WPRINTDRIVERENUM         205
1044 #define LANMAN_WPRINTQPROCENUM          206
1045 #define LANMAN_WPRINTPORTENUM           207
1046 #define LANMAN_SAMOEMCHANGEPASSWORD     214
1047
1048 static const struct lanman_desc lmd[] = {
1049         { LANMAN_NETSHAREENUM,
1050           lm_params_req_netshareenum,
1051           NULL,
1052           NULL,
1053           lm_null,
1054           lm_null,
1055           lm_params_resp_netshareenum,
1056           netshareenum_shares_list,
1057           &ett_lanman_shares,
1058           netshareenum_share_entry,
1059           &ett_lanman_share,
1060           lm_data_resp_netshareenum,
1061           lm_null },
1062
1063         { LANMAN_NETSHAREGETINFO,
1064           lm_params_req_netsharegetinfo,
1065           NULL,
1066           NULL,
1067           lm_null,
1068           lm_null,
1069           lm_params_resp_netsharegetinfo,
1070           NULL,
1071           NULL,
1072           NULL,
1073           NULL,
1074           lm_data_resp_netsharegetinfo,
1075           lm_null },
1076
1077         { LANMAN_NETSERVERGETINFO, 
1078           lm_params_req_netservergetinfo,
1079           NULL,
1080           NULL,
1081           lm_null,
1082           lm_null,
1083           lm_params_resp_netservergetinfo,
1084           NULL,
1085           NULL,
1086           NULL,
1087           NULL,
1088           lm_data_serverinfo,
1089           lm_null },
1090
1091         { LANMAN_NETUSERGETINFO,
1092           lm_params_req_netusergetinfo,
1093           NULL,
1094           NULL,
1095           lm_null,
1096           lm_null,
1097           lm_params_resp_netusergetinfo,
1098           NULL,
1099           NULL,
1100           NULL,
1101           NULL,
1102           lm_data_resp_netusergetinfo,
1103           lm_null },
1104
1105         { LANMAN_NETREMOTETOD,
1106           lm_null,
1107           NULL,
1108           NULL,
1109           lm_null,
1110           lm_null,
1111           lm_null,
1112           NULL,
1113           NULL,
1114           NULL,
1115           NULL,
1116           lm_data_resp_netremotetod,
1117           lm_null },
1118
1119         { LANMAN_NETSERVERENUM2,
1120           lm_params_req_netserverenum2,
1121           NULL,
1122           NULL,
1123           lm_null,
1124           lm_null,
1125           lm_params_resp_netserverenum2,
1126           netserverenum2_servers_list,
1127           &ett_lanman_servers,
1128           netserverenum2_server_entry,
1129           &ett_lanman_server,
1130           lm_data_serverinfo,
1131           lm_null },
1132
1133         { LANMAN_NETWKSTAGETINFO,
1134           lm_params_req_netwkstagetinfo,
1135           NULL,
1136           NULL,
1137           lm_null,
1138           lm_null,
1139           lm_params_resp_netwkstagetinfo,
1140           NULL,
1141           NULL,
1142           NULL,
1143           NULL,
1144           lm_data_resp_netwkstagetinfo,
1145           lm_null },
1146
1147         { LANMAN_NETWKSTAUSERLOGON,
1148           lm_params_req_netwkstauserlogon,
1149           NULL,
1150           NULL,
1151           lm_null,
1152           lm_null,
1153           lm_params_resp_netwkstauserlogon,
1154           NULL,
1155           NULL,
1156           NULL,
1157           NULL,
1158           lm_data_resp_netwkstauserlogon,
1159           lm_null },
1160
1161         { LANMAN_NETWKSTAUSERLOGOFF,
1162           lm_params_req_netwkstauserlogoff,
1163           NULL,
1164           NULL,
1165           lm_null,
1166           lm_null,
1167           lm_params_resp_netwkstauserlogoff,
1168           NULL,
1169           NULL,
1170           NULL,
1171           NULL,
1172           lm_data_resp_netwkstauserlogoff,
1173           lm_null },
1174
1175         { LANMAN_SAMOEMCHANGEPASSWORD,
1176           lm_params_req_samoemchangepassword,
1177           NULL,
1178           NULL,
1179           lm_data_req_samoemchangepassword,
1180           lm_null,
1181           lm_null,
1182           NULL,
1183           NULL,
1184           NULL,
1185           NULL,
1186           lm_null_list,
1187           lm_null },
1188
1189         { -1,
1190           lm_null,
1191           NULL,
1192           NULL,
1193           lm_null,
1194           lm_null,
1195           lm_null,
1196           NULL,
1197           NULL,
1198           NULL,
1199           NULL,
1200           lm_null_list,
1201           lm_null }
1202 };
1203
1204 static const struct lanman_desc *
1205 find_lanman(int lanman_num)
1206 {
1207         int i;
1208
1209         for (i = 0; lmd[i].lanman_num != -1; i++) {
1210                 if (lmd[i].lanman_num == lanman_num)
1211                         break;
1212         }
1213         return &lmd[i];
1214 }
1215
1216 static const guchar *
1217 get_count(const guchar *desc, int *countp)
1218 {
1219         int count = 0, off = 0;
1220         guchar c;
1221
1222         if (!isdigit(*desc)) {
1223                 *countp = 1;    /* no count was supplied */
1224                 return desc;
1225         }
1226
1227         while ((c = *desc) != '\0' && isdigit(c)) {
1228                 count = (count * 10) + c - '0';
1229                 desc++;
1230         }
1231
1232         *countp = count;        /* XXX - what if it's 0? */
1233         return desc;
1234 }
1235
1236 static int
1237 dissect_request_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
1238     proto_tree *tree, const guchar *desc, const item_t *items,
1239     gboolean *has_data_p)
1240 {
1241         guint c;
1242         guint16 WParam;
1243         guint32 LParam;
1244         guint string_len;
1245         int count;
1246
1247         *has_data_p = FALSE;
1248         while ((c = *desc++) != '\0') {
1249                 switch (c) {
1250
1251                 case 'W':
1252                         /*
1253                          * A 16-bit word value in the request.
1254                          */
1255                         if (items->func == NULL) {
1256                                 /*
1257                                  * We've run out of items in the table;
1258                                  * fall back on the default.
1259                                  */
1260                                 offset = add_word_param(tvb, offset, 0, pinfo,
1261                                     tree, 0, -1);
1262                         } else if (items->type != PARAM_WORD) {
1263                                 /*
1264                                  * Descriptor character is 'W', but this
1265                                  * isn't a word parameter.
1266                                  */
1267                                 WParam = tvb_get_letohs(tvb, offset);
1268                                 proto_tree_add_text(tree, tvb, offset, 2,
1269                                     "%s: Value is %u (0x%04X), type is wrong (W)",
1270                                     (*items->hf_index == -1) ?
1271                                       "Word Param" :
1272                                       proto_registrar_get_name(*items->hf_index),
1273                                     WParam, WParam);
1274                                 offset += 2;
1275                                 items++;
1276                         } else {
1277                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1278                                     tree, 0, *items->hf_index);
1279                                 items++;
1280                         }
1281                         break;
1282
1283                 case 'D':
1284                         /*
1285                          * A 32-bit doubleword value in the request.
1286                          */
1287                         if (items->func == NULL) {
1288                                 /*
1289                                  * We've run out of items in the table;
1290                                  * fall back on the default.
1291                                  */
1292                                 offset = add_dword_param(tvb, offset, 0, pinfo,
1293                                     tree, 0, -1);
1294                         } else if (items->type != PARAM_DWORD) {
1295                                 /*
1296                                  * Descriptor character is 'D', but this
1297                                  * isn't a doubleword parameter.
1298                                  */
1299                                 LParam = tvb_get_letohl(tvb, offset);
1300                                 proto_tree_add_text(tree, tvb, offset, 2,
1301                                     "%s: Value is %u (0x%08X), type is wrong (D)",
1302                                     (*items->hf_index == -1) ?
1303                                       "Doubleword Param" :
1304                                       proto_registrar_get_name(*items->hf_index),
1305                                     LParam, LParam);
1306                                 offset += 4;
1307                                 items++;
1308                         } else {
1309                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1310                                     tree, 0, *items->hf_index);
1311                                 items++;
1312                         }
1313                         break;
1314
1315                 case 'b':
1316                         /*
1317                          * A byte or multi-byte value in the request.
1318                          */
1319                         desc = get_count(desc, &count);
1320                         if (items->func == NULL) {
1321                                 /*
1322                                  * We've run out of items in the table;
1323                                  * fall back on the default.
1324                                  */
1325                                 offset = add_byte_param(tvb, offset, count,
1326                                     pinfo, tree, 0, -1);
1327                         } else if (items->type != PARAM_BYTES) {
1328                                 /*
1329                                  * Descriptor character is 'b', but this
1330                                  * isn't a byte/bytes parameter.
1331                                  */
1332                                 proto_tree_add_text(tree, tvb, offset, count,
1333                                     "%s: Value is %s, type is wrong (b)",
1334                                     (*items->hf_index == -1) ?
1335                                       "Byte Param" :
1336                                       proto_registrar_get_name(*items->hf_index),
1337                                     tvb_bytes_to_str(tvb, offset, count));
1338                                 offset += count;
1339                                 items++;
1340                         } else {
1341                                 offset = (*items->func)(tvb, offset, count,
1342                                     pinfo, tree, 0, *items->hf_index);
1343                                 items++;
1344                         }
1345                         break;
1346
1347                 case 'O':
1348                         /*
1349                          * A null pointer.
1350                          */
1351                         if (items->func == NULL) {
1352                                 /*
1353                                  * We've run out of items in the table;
1354                                  * fall back on the default.
1355                                  */
1356                                 add_null_pointer_param(tvb, offset, 0,
1357                                     pinfo, tree, 0, -1);
1358                         } else {
1359                                 /*
1360                                  * If "*items->hf_index" is -1, this is
1361                                  * a reserved must-be-null field; don't
1362                                  * clutter the protocol tree by putting
1363                                  * it in.
1364                                  */
1365                                 if (*items->hf_index != -1) {
1366                                         add_null_pointer_param(tvb,
1367                                             offset, 0, pinfo, tree, 0,
1368                                             *items->hf_index);
1369                                 }
1370                                 items++;
1371                         }
1372                         break;
1373
1374                 case 'z':
1375                         /*
1376                          * A null-terminated ASCII string.
1377                          */
1378                         if (items->func == NULL) {
1379                                 /*
1380                                  * We've run out of items in the table;
1381                                  * fall back on the default.
1382                                  */
1383                                 offset = add_string_param(tvb, offset, 0,
1384                                     pinfo, tree, 0, -1);
1385                         } else if (items->type != PARAM_STRINGZ) {
1386                                 /*
1387                                  * Descriptor character is 'z', but this
1388                                  * isn't a string parameter.
1389                                  */
1390                                 string_len = tvb_strsize(tvb, offset);
1391                                 proto_tree_add_text(tree, tvb, offset, string_len,
1392                                     "%s: Value is %s, type is wrong (z)",
1393                                     (*items->hf_index == -1) ?
1394                                       "String Param" :
1395                                       proto_registrar_get_name(*items->hf_index),
1396                                     tvb_format_text(tvb, offset, string_len));
1397                                 offset += string_len;
1398                                 items++;
1399                         } else {
1400                                 offset = (*items->func)(tvb, offset, 0,
1401                                     pinfo, tree, 0, *items->hf_index);
1402                                 items++;
1403                         }
1404                         break;
1405
1406                 case 'F':
1407                         /*
1408                          * One or more pad bytes.
1409                          */
1410                         desc = get_count(desc, &count);
1411                         proto_tree_add_text(tree, tvb, offset, count,
1412                             "%s", "Padding");
1413                         offset += count;
1414                         break;
1415
1416                 case 'L':
1417                         /*
1418                          * 16-bit receive buffer length.
1419                          */
1420                         proto_tree_add_item(tree, hf_recv_buf_len, tvb,
1421                             offset, 2, TRUE);
1422                         offset += 2;
1423                         break;
1424
1425                 case 's':
1426                         /*
1427                          * 32-bit send buffer offset.
1428                          * XXX - is there actually a pointer here?
1429                          * I suspect not.  It looks like junk.
1430                          */
1431                         *has_data_p = TRUE;
1432                         LParam = tvb_get_letohl(tvb, offset);
1433                         proto_tree_add_text(tree, tvb, offset, 4,
1434                             "%s: %u", "Send Buffer Ptr", LParam);
1435                         offset += 4;
1436                         break;
1437
1438                 case 'T':
1439                         /*
1440                          * 16-bit send buffer length.
1441                          */
1442                         proto_tree_add_item(tree, hf_send_buf_len, tvb,
1443                             offset, 2, FALSE);
1444                         offset += 2;
1445                         break;
1446
1447                 default:
1448                         break;
1449                 }
1450         }
1451         return offset;
1452 }
1453
1454 static int
1455 dissect_response_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
1456     proto_tree *tree, const guchar *desc, const item_t *items,
1457     gboolean *has_data_p, gboolean *has_ent_count_p, guint16 *ent_count_p)
1458 {
1459         guint c;
1460         guint16 WParam;
1461         guint32 LParam;
1462         int count;
1463
1464         *has_data_p = FALSE;
1465         *has_ent_count_p = FALSE;
1466         while ((c = *desc++) != '\0') {
1467                 switch (c) {
1468
1469                 case 'r':
1470                         /*
1471                          * 32-bit receive buffer offset.
1472                          */
1473                         *has_data_p = TRUE;
1474                         break;
1475
1476                 case 'g':
1477                         /*
1478                          * A byte or series of bytes is returned.
1479                          */
1480                         desc = get_count(desc, &count);
1481                         if (items->func == NULL) {
1482                                 /*
1483                                  * We've run out of items in the table;
1484                                  * fall back on the default.
1485                                  */
1486                                 offset = add_byte_param(tvb, offset, count,
1487                                     pinfo, tree, 0, -1);
1488                         } else if (items->type != PARAM_BYTES) {
1489                                 /*
1490                                  * Descriptor character is 'b', but this
1491                                  * isn't a byte/bytes parameter.
1492                                  */
1493                                 proto_tree_add_text(tree, tvb, offset, count,
1494                                     "%s: Value is %s, type is wrong (g)",
1495                                     (*items->hf_index == -1) ?
1496                                       "Byte Param" :
1497                                       proto_registrar_get_name(*items->hf_index),
1498                                     tvb_bytes_to_str(tvb, offset, count));
1499                                 offset += count;
1500                                 items++;
1501                         } else {
1502                                 offset = (*items->func)(tvb, offset, count,
1503                                     pinfo, tree, 0, *items->hf_index);
1504                                 items++;
1505                         }
1506                         break;
1507
1508                 case 'h':
1509                         /*
1510                          * A 16-bit word is received.
1511                          */
1512                         if (items->func == NULL) {
1513                                 /*
1514                                  * We've run out of items in the table;
1515                                  * fall back on the default.
1516                                  */
1517                                 offset = add_word_param(tvb, offset, 0, pinfo,
1518                                     tree, 0, -1);
1519                         } else if (items->type != PARAM_WORD) {
1520                                 /*
1521                                  * Descriptor character is 'h', but this
1522                                  * isn't a word parameter.
1523                                  */
1524                                 WParam = tvb_get_letohs(tvb, offset);
1525                                 proto_tree_add_text(tree, tvb, offset, 2,
1526                                     "%s: Value is %u (0x%04X), type is wrong (W)",
1527                                     (*items->hf_index == -1) ?
1528                                       "Word Param" :
1529                                       proto_registrar_get_name(*items->hf_index),
1530                                     WParam, WParam);
1531                                 offset += 2;
1532                                 items++;
1533                         } else {
1534                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1535                                     tree, 0, *items->hf_index);
1536                                 items++;
1537                         }
1538                         break;
1539
1540                 case 'i':
1541                         /*
1542                          * A 32-bit doubleword is received.
1543                          */
1544                         if (items->func == NULL) {
1545                                 /*
1546                                  * We've run out of items in the table;
1547                                  * fall back on the default.
1548                                  */
1549                                 offset = add_dword_param(tvb, offset, 0, pinfo,
1550                                     tree, 0, -1);
1551                         } else if (items->type != PARAM_DWORD) {
1552                                 /*
1553                                  * Descriptor character is 'i', but this
1554                                  * isn't a doubleword parameter.
1555                                  */
1556                                 LParam = tvb_get_letohl(tvb, offset);
1557                                 proto_tree_add_text(tree, tvb, offset, 2,
1558                                     "%s: Value is %u (0x%08X), type is wrong (i)",
1559                                     (*items->hf_index == -1) ?
1560                                       "Doubleword Param" :
1561                                       proto_registrar_get_name(*items->hf_index),
1562                                     LParam, LParam);
1563                                 offset += 4;
1564                                 items++;
1565                         } else {
1566                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1567                                     tree, 0, *items->hf_index);
1568                                 items++;
1569                         }
1570                         break;
1571
1572                 case 'e':
1573                         /*
1574                          * A 16-bit entry count is returned.
1575                          */
1576                         WParam = tvb_get_letohs(tvb, offset);
1577                         proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2,
1578                             WParam);
1579                         offset += 2;
1580                         *has_ent_count_p = TRUE;
1581                         *ent_count_p = WParam;  /* Save this for later retrieval */
1582                         break;
1583
1584                 default:
1585                         break;
1586                 }
1587         }
1588         return offset;
1589 }
1590
1591 static int
1592 dissect_transact_data(tvbuff_t *tvb, int offset, int convert,
1593     packet_info *pinfo, proto_tree *tree, const guchar *desc,
1594     const item_t *items, guint16 *aux_count_p)
1595 {
1596         guint c;
1597         guint16 WParam;
1598         guint32 LParam;
1599         int count;
1600         int cptr;
1601         const char *string;
1602         gint string_len;
1603
1604         *aux_count_p = 0;
1605         while ((c = *desc++) != '\0') {
1606                 switch (c) {
1607
1608                 case 'W':
1609                         /*
1610                          * A 16-bit word value.
1611                          * XXX - handle the count?
1612                          */
1613                         desc = get_count(desc, &count);
1614                         if (items->func == NULL) {
1615                                 /*
1616                                  * We've run out of items in the table;
1617                                  * fall back on the default.
1618                                  */
1619                                 offset = add_word_param(tvb, offset, 0, pinfo,
1620                                     tree, convert, -1);
1621                         } else if (items->type != PARAM_WORD) {
1622                                 /*
1623                                  * Descriptor character is 'W', but this
1624                                  * isn't a word parameter.
1625                                  */
1626                                 WParam = tvb_get_letohs(tvb, offset);
1627                                 proto_tree_add_text(tree, tvb, offset, 2,
1628                                     "%s: Value is %u (0x%04X), type is wrong (W)",
1629                                     (*items->hf_index == -1) ?
1630                                       "Word Param" :
1631                                       proto_registrar_get_name(*items->hf_index),
1632                                     WParam, WParam);
1633                                 offset += 2;
1634                                 items++;
1635                         } else {
1636                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1637                                     tree, convert, *items->hf_index);
1638                                 items++;
1639                         }
1640                         break;
1641
1642                 case 'D':
1643                         /*
1644                          * A 32-bit doubleword value.
1645                          * XXX - handle the count?
1646                          */
1647                         desc = get_count(desc, &count);
1648                         if (items->func == NULL) {
1649                                 /*
1650                                  * We've run out of items in the table;
1651                                  * fall back on the default.
1652                                  */
1653                                 offset = add_dword_param(tvb, offset, 0, pinfo,
1654                                     tree, convert, -1);
1655                         } else if (items->type != PARAM_DWORD) {
1656                                 /*
1657                                  * Descriptor character is 'D', but this
1658                                  * isn't a doubleword parameter.
1659                                  */
1660                                 LParam = tvb_get_letohl(tvb, offset);
1661                                 proto_tree_add_text(tree, tvb, offset, 2,
1662                                     "%s: Value is %u (0x%08X), type is wrong (D)",
1663                                     (*items->hf_index == -1) ?
1664                                       "Doubleword Param" :
1665                                       proto_registrar_get_name(*items->hf_index),
1666                                     LParam, LParam);
1667                                 offset += 4;
1668                                 items++;
1669                         } else {
1670                                 offset = (*items->func)(tvb, offset, 0, pinfo,
1671                                     tree, convert, *items->hf_index);
1672                                 items++;
1673                         }
1674                         break;
1675
1676                 case 'B':
1677                         /*
1678                          * A byte or multi-byte value.
1679                          */
1680                         desc = get_count(desc, &count);
1681                         if (items->func == NULL) {
1682                                 /*
1683                                  * We've run out of items in the table;
1684                                  * fall back on the default.
1685                                  */
1686                                 offset = add_byte_param(tvb, offset, count,
1687                                     pinfo, tree, convert, -1);
1688                         } else if (items->type != PARAM_BYTES) {
1689                                 /*
1690                                  * Descriptor character is 'B', but this
1691                                  * isn't a byte/bytes parameter.
1692                                  */
1693                                 proto_tree_add_text(tree, tvb, offset, count,
1694                                     "%s: Value is %s, type is wrong (B)",
1695                                     (*items->hf_index == -1) ?
1696                                       "Byte Param" :
1697                                       proto_registrar_get_name(*items->hf_index),
1698                                     tvb_bytes_to_str(tvb, offset, count));
1699                                 offset += count;
1700                                 items++;
1701                         } else {
1702                                 offset = (*items->func)(tvb, offset, count,
1703                                     pinfo, tree, convert, *items->hf_index);
1704                                 items++;
1705                         }
1706                         break;
1707
1708                 case 'O':
1709                         /*
1710                          * A null pointer.
1711                          */
1712                         if (items->func == NULL) {
1713                                 /*
1714                                  * We've run out of items in the table;
1715                                  * fall back on the default.
1716                                  */
1717                                 add_null_pointer_param(tvb, offset, 0,
1718                                     pinfo, tree, convert, -1);
1719                         } else {
1720                                 /*
1721                                  * If "*items->hf_index" is -1, this is
1722                                  * a reserved must-be-null field; don't
1723                                  * clutter the protocol tree by putting
1724                                  * it in.
1725                                  */
1726                                 if (*items->hf_index != -1) {
1727                                         add_null_pointer_param(tvb,
1728                                             offset, 0, pinfo, tree, convert,
1729                                             *items->hf_index);
1730                                 }
1731                                 items++;
1732                         }
1733                         break;
1734
1735                 case 'z':
1736                         /*
1737                          * A pointer to a null-terminated ASCII string.
1738                          */
1739                         if (items->func == NULL) {
1740                                 /*
1741                                  * We've run out of items in the table;
1742                                  * fall back on the default.
1743                                  */
1744                                 offset = add_pointer_param(tvb, offset, 0,
1745                                     pinfo, tree, convert, -1);
1746                         } else if (items->type != PARAM_STRINGZ) {
1747                                 /*
1748                                  * Descriptor character is 'z', but this
1749                                  * isn't a string parameter.
1750                                  */
1751                                 string = get_pointer_value(tvb, offset,
1752                                     convert, &cptr, &string_len);
1753                                 offset += 4;
1754                                 proto_tree_add_text(tree, tvb, cptr, string_len,
1755                                     "%s: Value is %s, type is wrong (z)",
1756                                     (*items->hf_index == -1) ?
1757                                       "String Param" :
1758                                       proto_registrar_get_name(*items->hf_index),
1759                                     string);
1760                                 items++;
1761                         } else {
1762                                 offset = (*items->func)(tvb, offset, 0,
1763                                     pinfo, tree, convert, *items->hf_index);
1764                                 items++;
1765                         }
1766                         break;
1767
1768                 case 'N':
1769                         /*
1770                          * 16-bit auxiliary data structure count.
1771                          * XXX - hf_acount?
1772                          */
1773                         WParam = tvb_get_letohs(tvb, offset);
1774                         proto_tree_add_text(tree, tvb, offset, 2,
1775                             "%s: %u (0x%04X)",
1776                             "Auxiliary data structure count",
1777                             WParam, WParam);
1778                         offset += 2;
1779                         if (aux_count_p != NULL)
1780                                 *aux_count_p = WParam;  /* Save this for later retrieval */
1781                         break;
1782
1783                 default:
1784                         break;
1785                 }
1786         }
1787         return offset;
1788 }
1789
1790 static const value_string commands[] = {
1791         {LANMAN_NETSHAREENUM,           "NetShareEnum"},
1792         {LANMAN_NETSHAREGETINFO,        "NetShareGetInfo"},
1793         {LANMAN_NETSERVERGETINFO,       "NetServerGetInfo"},
1794         {LANMAN_NETGROUPGETUSERS,       "NetGroupGetUsers"},
1795         {LANMAN_NETUSERGETINFO,         "NetUserGetInfo"},
1796         {LANMAN_NETUSERGETGROUPS,       "NetUserGetGroups"},
1797         {LANMAN_NETWKSTAGETINFO,        "NetWkstaGetInfo"},
1798         {LANMAN_DOSPRINTQENUM,          "DOSPrintQEnum"},
1799         {LANMAN_DOSPRINTQGETINFO,       "DOSPrintQGetInfo"},
1800         {LANMAN_WPRINTQUEUEPAUSE,       "WPrintQueuePause"},
1801         {LANMAN_WPRINTQUEUERESUME,      "WPrintQueueResume"},
1802         {LANMAN_WPRINTJOBENUMERATE,     "WPrintJobEnumerate"},
1803         {LANMAN_WPRINTJOBGETINFO,       "WPrintJobGetInfo"},
1804         {LANMAN_RDOSPRINTJOBDEL,        "RDOSPrintJobDel"},
1805         {LANMAN_RDOSPRINTJOBPAUSE,      "RDOSPrintJobPause"},
1806         {LANMAN_RDOSPRINTJOBRESUME,     "RDOSPrintJobResume"},
1807         {LANMAN_WPRINTDESTENUM,         "WPrintDestEnum"},
1808         {LANMAN_WPRINTDESTGETINFO,      "WPrintDestGetInfo"},
1809         {LANMAN_NETREMOTETOD,           "NetRemoteTOD"},
1810         {LANMAN_WPRINTQUEUEPURGE,       "WPrintQueuePurge"},
1811         {LANMAN_NETSERVERENUM2,         "NetServerEnum2"},
1812         {LANMAN_WACCESSGETUSERPERMS,    "WAccessGetUserPerms"},
1813         {LANMAN_SETUSERPASSWORD,        "SetUserPassword"},
1814         {LANMAN_NETWKSTAUSERLOGON,      "NetWkstaUserLogon"},
1815         {LANMAN_NETWKSTAUSERLOGOFF,     "NetWkstaUserLogoff"},
1816         {LANMAN_PRINTJOBINFO,           "PrintJobInfo"},
1817         {LANMAN_WPRINTDRIVERENUM,       "WPrintDriverEnum"},
1818         {LANMAN_WPRINTQPROCENUM,        "WPrintQProcEnum"},
1819         {LANMAN_WPRINTPORTENUM,         "WPrintPortEnum"},
1820         {LANMAN_SAMOEMCHANGEPASSWORD,   "SamOEMChangePassword"},
1821         {0,     NULL}
1822 };
1823
1824 static gboolean
1825 dissect_pipe_lanman(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
1826 {
1827         struct smb_info *smb_info = pinfo->private;
1828         struct smb_request_val *request_val = smb_info->request_val;
1829         int parameter_count = smb_info->parameter_count;
1830         int offset = 0, start_offset;
1831         guint16 cmd;
1832         guint16 status;
1833         int convert;
1834         const struct lanman_desc *lanman;
1835         proto_item *item = NULL;
1836         proto_tree *tree = NULL;
1837         guint descriptor_len;
1838         const gchar *param_descrip, *data_descrip, *aux_data_descrip = NULL;
1839         gboolean has_data;
1840         gboolean has_ent_count;
1841         guint16 ent_count, aux_count;
1842         guint i, j;
1843         const item_list_t *resp_data_list;
1844         const item_t *resp_data;
1845         proto_item *data_item;
1846         proto_tree *data_tree;
1847         proto_item *entry_item;
1848         proto_tree *entry_tree;
1849
1850         if (check_col(pinfo->fd, COL_PROTOCOL)) {
1851                 col_set_str(pinfo->fd, COL_PROTOCOL, "LANMAN");
1852         }
1853
1854         if (parent_tree) {
1855                 item = proto_tree_add_item(parent_tree, proto_smb_lanman,
1856                         tvb, 0, tvb_length(tvb), FALSE);
1857                 tree = proto_item_add_subtree(item, ett_lanman);
1858         }
1859
1860         /*
1861          * Don't try to decode continuation messages.
1862          *
1863          * XXX - at some point, we will probably be handed tvbuffs
1864          * for the parameters of the first message and for the
1865          * reassembled contents of the data of the first message
1866          * and all the continuations, and should dissect it.
1867          *
1868          * Transaction reassembly may, however, be an option, so that if
1869          * we don't *have* all the reply messages, you at least can
1870          * see what you have, by turning the option off.  (We don't know
1871          * that we don't have them until we get to the end of the capture,
1872          * but, by that time, it may be too late to dissect what we have;
1873          * in Tethereal, for example, there's no going back....)
1874          */
1875         if (smb_info->ddisp) {
1876                 if (check_col(pinfo->fd, COL_INFO)) {
1877                         col_set_str(pinfo->fd, COL_INFO, "Transact Continuation");
1878                 }
1879                 if (smb_info->continuation_val != NULL) {
1880                         /* continuation from the message in frame xx */
1881                         proto_tree_add_uint(tree, hf_continuation_from, tvb,
1882                             0, 0, smb_info->continuation_val->frame);
1883                 }
1884                 proto_tree_add_text(tree, tvb, 0, tvb_length(tvb),
1885                     "Continuation data");
1886                 return TRUE;
1887         }
1888
1889         if (smb_info->request) { /* this is a request */
1890                 /* function code */
1891                 cmd = tvb_get_letohs(tvb, offset);
1892                 if (check_col(pinfo->fd, COL_INFO)) {
1893                         col_add_fstr(pinfo->fd, COL_INFO, "%s Request", val_to_str(cmd, commands, "Unknown Command:0x%02x"));
1894                 }
1895                 proto_tree_add_uint(tree, hf_function_code, tvb, offset, 2,
1896                     cmd);
1897                 offset += 2;
1898                 parameter_count -= 2;
1899
1900                 /*
1901                  * If we haven't already done so, save the function code in
1902                  * the structure we were handed, so that it's available to
1903                  * the code parsing the reply, and initialize the detail
1904                  * level to -1, meaning "unknown".
1905                  */
1906                 if (!pinfo->fd->flags.visited) {
1907                         request_val->last_lanman_cmd = cmd;
1908                         request_val->last_level = -1;
1909                 }
1910
1911                 /* parameter descriptor */
1912                 descriptor_len = tvb_strsize(tvb, offset);
1913                 proto_tree_add_item(tree, hf_param_desc, tvb, offset,
1914                     descriptor_len, TRUE);
1915                 param_descrip = tvb_get_ptr(tvb, offset, descriptor_len);
1916                 if (!pinfo->fd->flags.visited) {
1917                         /*
1918                          * Save the parameter descriptor for future use.
1919                          */
1920                         g_assert(request_val->last_param_descrip == NULL);
1921                         request_val->last_param_descrip = g_strdup(param_descrip);
1922                 }
1923                 offset += descriptor_len;
1924                 parameter_count -= descriptor_len;
1925
1926                 /* return descriptor */
1927                 descriptor_len = tvb_strsize(tvb, offset);
1928                 proto_tree_add_item(tree, hf_return_desc, tvb, offset,
1929                     descriptor_len, TRUE);
1930                 data_descrip = tvb_get_ptr(tvb, offset, descriptor_len);
1931                 if (!pinfo->fd->flags.visited) {
1932                         /*
1933                          * Save the return descriptor for future use.
1934                          */
1935                         g_assert(request_val->last_data_descrip == NULL);
1936                         request_val->last_data_descrip = g_strdup(data_descrip);
1937                 }
1938                 offset += descriptor_len;
1939                 parameter_count -= descriptor_len;
1940
1941                 lanman = find_lanman(cmd);
1942
1943                 /* request parameters */
1944                 start_offset = offset;
1945                 offset = dissect_request_parameters(tvb, offset, pinfo, tree,
1946                     param_descrip, lanman->req, &has_data);
1947                 parameter_count -= offset - start_offset;
1948
1949                 /* auxiliary data descriptor */
1950                 if (parameter_count > 0) {
1951                         /*
1952                          * There are more parameters left, so the next
1953                          * item is the auxiliary data descriptor.
1954                          */
1955                         descriptor_len = tvb_strsize(tvb, offset);
1956                         proto_tree_add_item(tree, hf_return_desc, tvb, offset,
1957                             descriptor_len, TRUE);
1958                         aux_data_descrip = tvb_get_ptr(tvb, offset, descriptor_len);
1959                         if (!pinfo->fd->flags.visited) {
1960                                 /*
1961                                  * Save the auxiliary data descriptor for
1962                                  * future use.
1963                                  */
1964                                 g_assert(request_val->last_aux_data_descrip == NULL);
1965                                 request_val->last_aux_data_descrip =
1966                                     g_strdup(aux_data_descrip);
1967                         }
1968                         offset += descriptor_len;
1969                 }
1970
1971                 if (has_data && smb_info->data_count != 0) {
1972                         /*
1973                          * There's a send buffer item in the descriptor
1974                          * string, and the data count in the transaction
1975                          * is non-zero, so there's data to dissect.
1976                          *
1977                          * XXX - should we just check "smb_info->data_count"?
1978                          */
1979
1980                         offset = smb_info->data_offset;
1981                         if (lanman->req_data_item != NULL) {
1982                                 /*
1983                                  * Create a protocol tree item for the data.
1984                                  */
1985                                 data_item = (*lanman->req_data_item)(tvb,
1986                                     pinfo, tree, offset);
1987                                 data_tree = proto_item_add_subtree(data_item,
1988                                     *lanman->ett_req_data);
1989                         } else {
1990                                 /*
1991                                  * Just leave it at the top level.
1992                                  */
1993                                 data_item = NULL;
1994                                 data_tree = tree;
1995                         }
1996
1997                         /* data */
1998                         offset = dissect_transact_data(tvb, offset, -1,
1999                             pinfo, data_tree, data_descrip, lanman->req_data,
2000                             &aux_count);        /* XXX - what about strings? */
2001
2002                         /* auxiliary data */
2003                         if (aux_data_descrip != NULL) {
2004                                 for (i = 0; i < aux_count; i++) {
2005                                         offset = dissect_transact_data(tvb,
2006                                             offset, -1, pinfo, data_tree,
2007                                             aux_data_descrip,
2008                                             lanman->req_aux_data, NULL);
2009                                 }
2010                         }
2011
2012                         if (data_item != NULL) {
2013                                 /*
2014                                  * Set the length of the protocol tree item
2015                                  * for the data.
2016                                  */
2017                                 proto_item_set_len(data_item,
2018                                     offset - smb_info->data_offset);
2019                         }
2020                 }
2021         } else {
2022                 /*
2023                  * This is a response.
2024                  * Have we seen the request to which it's a response?
2025                  */
2026                 if (request_val == NULL)
2027                         return FALSE;   /* no - can't dissect it */
2028
2029                 /* ok we have seen this one before */
2030
2031                 /* response to the request in frame xx */
2032                 proto_tree_add_uint(tree, hf_response_to, tvb, 0, 0,
2033                                     request_val->frame);
2034                 /* command */
2035                 if (check_col(pinfo->fd, COL_INFO)) {
2036                         col_add_fstr(pinfo->fd, COL_INFO, "%s %sResponse",
2037                             val_to_str(request_val->last_lanman_cmd, commands, "Unknown Command (0x%02x)"),
2038                             smb_info->is_interim_response ? "Interim " : "");
2039                 }
2040                 proto_tree_add_uint(tree, hf_function_code, tvb, 0, 0,
2041                     request_val->last_lanman_cmd);
2042
2043                 if (smb_info->is_interim_response)
2044                         return TRUE;    /* no data to dissect */
2045
2046                 lanman = find_lanman(request_val->last_lanman_cmd);
2047
2048                 /* response parameters */
2049
2050                 /* status */
2051                 status = tvb_get_letohs(tvb, offset);
2052                 proto_tree_add_uint(tree, hf_status, tvb, offset, 2, status);
2053                 offset += 2;
2054
2055                 /* convert */
2056                 convert = tvb_get_letohs(tvb, offset);
2057                 proto_tree_add_uint(tree, hf_convert, tvb, offset, 2, convert);
2058                 offset += 2;
2059
2060                 /*
2061                  * "convert" is relative to the beginning of the data
2062                  * area, but we're handed a tvbuff that starts at the
2063                  * beginning of the parameter area, so we need to
2064                  * add "smb_info->data_offset" to offsets after
2065                  * subtracting "convert"; subtract it from "convert"
2066                  * so that it gets added in for free.
2067                  */
2068                 convert -= smb_info->data_offset;
2069
2070                 /* rest of the parameters */
2071                 offset = dissect_response_parameters(tvb, offset, pinfo, tree,
2072                     request_val->last_param_descrip, lanman->resp, &has_data,
2073                     &has_ent_count, &ent_count);
2074
2075                 /* data */
2076                 if (has_data && smb_info->data_count != 0) {
2077                         /*
2078                          * There's a receive buffer item in the descriptor
2079                          * string, and the data count in the transaction
2080                          * is non-zero, so there's data to dissect.
2081                          *
2082                          * XXX - should we just check "smb_info->data_count"?
2083                          */
2084
2085                         /*
2086                          * Find the item table for the matching request's
2087                          * detail level.
2088                          */
2089                         for (resp_data_list = lanman->resp_data_list;
2090                             resp_data_list->level != -1; resp_data_list++) {
2091                                 if (resp_data_list->level == request_val->last_level)
2092                                         break;
2093                         }
2094                         resp_data = resp_data_list->item_list;
2095
2096                         offset = smb_info->data_offset;
2097                         if (lanman->resp_data_item != NULL) {
2098                                 /*
2099                                  * Create a protocol tree item for the data.
2100                                  */
2101                                 data_item = (*lanman->resp_data_item)(tvb,
2102                                     pinfo, tree, offset);
2103                                 data_tree = proto_item_add_subtree(data_item,
2104                                     *lanman->ett_resp_data);
2105                         } else {
2106                                 /*
2107                                  * Just leave it at the top level.
2108                                  */
2109                                 data_item = NULL;
2110                                 data_tree = tree;
2111                         }
2112
2113                         /*
2114                          * If we have an entry count, show all the entries,
2115                          * with each one having a protocol tree item.
2116                          *
2117                          * Otherwise, we just show one returned item, with
2118                          * no protocol tree item.
2119                          */
2120                         if (!has_ent_count)
2121                                 ent_count = 1;
2122                         for (i = 0; i < ent_count; i++) {
2123                                 start_offset = offset;
2124                                 if (has_ent_count) {
2125                                         /*
2126                                          * Create a protocol tree item for the
2127                                          * entry.
2128                                          */
2129                                         entry_item =
2130                                             (*lanman->resp_data_element_item)
2131                                               (tvb, pinfo, data_tree, offset);
2132                                         entry_tree = proto_item_add_subtree(
2133                                             entry_item,
2134                                             *lanman->ett_resp_data_element_item);
2135                                 } else {
2136                                         /*
2137                                          * Just leave it at the current
2138                                          * level.
2139                                          */
2140                                         entry_item = NULL;
2141                                         entry_tree = data_tree;
2142                                 }
2143
2144                                 offset = dissect_transact_data(tvb, offset,
2145                                     convert, pinfo, entry_tree,
2146                                     request_val->last_data_descrip,
2147                                     resp_data, &aux_count);
2148
2149                                 /* auxiliary data */
2150                                 if (request_val->last_aux_data_descrip != NULL) {
2151                                         for (j = 0; j < aux_count; j++) {
2152                                                 offset = dissect_transact_data(
2153                                                     tvb, offset, convert,
2154                                                     pinfo, entry_tree,
2155                                                     request_val->last_data_descrip,
2156                                                     lanman->resp_aux_data, NULL);
2157                                         }
2158                                 }
2159
2160                                 if (entry_item != NULL) {
2161                                         /*
2162                                          * Set the length of the protocol tree
2163                                          * item for the entry.
2164                                          */
2165                                         proto_item_set_len(entry_item,
2166                                             offset - start_offset);
2167                                 }
2168                         }
2169
2170                         if (data_item != NULL) {
2171                                 /*
2172                                  * Set the length of the protocol tree item
2173                                  * for the data.
2174                                  */
2175                                 proto_item_set_len(data_item,
2176                                     offset - smb_info->data_offset);
2177                         }
2178                 }
2179         }
2180
2181         return TRUE;
2182 }
2183
2184
2185
2186 gboolean
2187 dissect_pipe_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2188 {
2189         struct smb_info *smb_info = pinfo->private;
2190
2191         if (!proto_is_protocol_enabled(proto_smb_lanman))
2192                 return FALSE;
2193         pinfo->current_proto = "LANMAN";
2194
2195         if (smb_info->trans_cmd && strcmp(smb_info->trans_cmd, "LANMAN") == 0) {
2196                 /* Try to decode a LANMAN */
2197
2198                 return dissect_pipe_lanman(tvb, pinfo, tree);
2199         }
2200
2201         return FALSE;
2202 }
2203
2204 void
2205 register_proto_smb_pipe(void)
2206 {
2207         static hf_register_info hf[] = {
2208                 { &hf_function_code,
2209                         { "Function Code", "lanman.function_code", FT_UINT16, BASE_DEC,
2210                         VALS(commands), 0, "LANMAN Function Code/Command", HFILL }},
2211
2212                 { &hf_param_desc,
2213                         { "Parameter Descriptor", "lanman.param_desc", FT_STRING, BASE_NONE,
2214                         NULL, 0, "LANMAN Parameter Descriptor", HFILL }},
2215
2216                 { &hf_return_desc,
2217                         { "Return Descriptor", "lanman.ret_desc", FT_STRING, BASE_NONE,
2218                         NULL, 0, "LANMAN Return Descriptor", HFILL }},
2219
2220                 { &hf_aux_data_desc,
2221                         { "Auxiliary Data Descriptor", "lanman.aux_data_desc", FT_STRING, BASE_NONE,
2222                         NULL, 0, "LANMAN Auxiliary Data Descriptor", HFILL }},
2223
2224                 { &hf_detail_level,
2225                         { "Detail Level", "lanman.level", FT_UINT16, BASE_DEC,
2226                         NULL, 0, "LANMAN Detail Level", HFILL }},
2227
2228                 { &hf_recv_buf_len,
2229                         { "Receive Buffer Length", "lanman.recv_buf_len", FT_UINT16, BASE_DEC,
2230                         NULL, 0, "LANMAN Receive Buffer Length", HFILL }},
2231
2232                 { &hf_send_buf_len,
2233                         { "Send Buffer Length", "lanman.send_buf_len", FT_UINT16, BASE_DEC,
2234                         NULL, 0, "LANMAN Send Buffer Length", HFILL }},
2235
2236                 { &hf_response_to,
2237                         { "Response to request in frame", "lanman.response_to", FT_UINT32, BASE_DEC,
2238                         NULL, 0, "This is a LANMAN response to the request in the frame in question", HFILL }},
2239
2240                 { &hf_continuation_from,
2241                         { "Continuation from message in frame", "lanman.continuation_from", FT_UINT32, BASE_DEC,
2242                         NULL, 0, "This is a LANMAN continuation from the message in the frame in question", HFILL }},
2243
2244                 { &hf_status,
2245                         { "Status", "lanman.status", FT_UINT16, BASE_DEC,
2246                         VALS(status_vals), 0, "LANMAN Return status", HFILL }},
2247
2248                 { &hf_convert,
2249                         { "Convert", "lanman.convert", FT_UINT16, BASE_DEC,
2250                         NULL, 0, "LANMAN Convert", HFILL }},
2251
2252                 { &hf_ecount,
2253                         { "Entry Count", "lanman.entry_count", FT_UINT16, BASE_DEC,
2254                         NULL, 0, "LANMAN Number of Entries", HFILL }},
2255
2256                 { &hf_acount,
2257                         { "Available Entries", "lanman.available_count", FT_UINT16, BASE_DEC,
2258                         NULL, 0, "LANMAN Number of Available Entries", HFILL }},
2259
2260                 { &hf_share_name,
2261                         { "Share Name", "lanman.share.name", FT_STRING, BASE_NONE,
2262                         NULL, 0, "LANMAN Name of Share", HFILL }},
2263
2264                 { &hf_share_type,
2265                         { "Share Type", "lanman.share.type", FT_UINT16, BASE_DEC,
2266                         VALS(share_type_vals), 0, "LANMAN Type of Share", HFILL }},
2267
2268                 { &hf_share_comment,
2269                         { "Share Comment", "lanman.share.comment", FT_STRING, BASE_NONE,
2270                         NULL, 0, "LANMAN Share Comment", HFILL }},
2271
2272                 { &hf_share_permissions,
2273                         { "Share Permissions", "lanman.share.permissions", FT_UINT16, BASE_DEC,
2274                         NULL, 0, "LANMAN Permissions on share", HFILL }},
2275
2276                 { &hf_share_max_uses,
2277                         { "Share Max Uses", "lanman.share.max_uses", FT_UINT16, BASE_DEC,
2278                         NULL, 0, "LANMAN Max connections allowed to share", HFILL }},
2279
2280                 { &hf_share_current_uses,
2281                         { "Share Current Uses", "lanman.share.current_uses", FT_UINT16, BASE_DEC,
2282                         NULL, 0, "LANMAN Current connections to share", HFILL }},
2283
2284                 { &hf_share_path,
2285                         { "Share Path", "lanman.share.path", FT_STRING, BASE_NONE,
2286                         NULL, 0, "LANMAN Share Path", HFILL }},
2287
2288                 { &hf_share_password,
2289                         { "Share Password", "lanman.share.password", FT_STRING, BASE_NONE,
2290                         NULL, 0, "LANMAN Share Password", HFILL }},
2291
2292                 { &hf_server_name,
2293                         { "Server Name", "lanman.server.name", FT_STRING, BASE_NONE,
2294                         NULL, 0, "LANMAN Name of Server", HFILL }},
2295
2296                 { &hf_server_major,
2297                         { "Major Version", "lanman.server.major", FT_UINT8, BASE_DEC,
2298                         NULL, 0, "LANMAN Server Major Version", HFILL }},
2299
2300                 { &hf_server_minor,
2301                         { "Minor Version", "lanman.server.minor", FT_UINT8, BASE_DEC,
2302                         NULL, 0, "LANMAN Server Minor Version", HFILL }},
2303
2304                 { &hf_server_comment,
2305                         { "Server Comment", "lanman.server.comment", FT_STRING, BASE_NONE,
2306                         NULL, 0, "LANMAN Server Comment", HFILL }},
2307
2308                 { &hf_abytes,
2309                         { "Available Bytes", "lanman.available_bytes", FT_UINT16, BASE_DEC,
2310                         NULL, 0, "LANMAN Number of Available Bytes", HFILL }},
2311
2312                 { &hf_current_time,
2313                         { "Current Date/Time", "lanman.current_time", FT_ABSOLUTE_TIME, BASE_NONE,
2314                         NULL, 0, "LANMAN Current date and time, in seconds since 00:00:00, January 1, 1970", HFILL }},
2315
2316                 { &hf_msecs,
2317                         { "Milliseconds", "lanman.msecs", FT_UINT32, BASE_DEC,
2318                         NULL, 0, "LANMAN Milliseconds since arbitrary time in the past (typically boot time)", HFILL }},
2319
2320                 { &hf_hour,
2321                         { "Hour", "lanman.hour", FT_UINT8, BASE_DEC,
2322                         NULL, 0, "LANMAN Current hour", HFILL }},
2323
2324                 { &hf_minute,
2325                         { "Minute", "lanman.minute", FT_UINT8, BASE_DEC,
2326                         NULL, 0, "LANMAN Current minute", HFILL }},
2327
2328                 { &hf_second,
2329                         { "Second", "lanman.second", FT_UINT8, BASE_DEC,
2330                         NULL, 0, "LANMAN Current second", HFILL }},
2331
2332                 { &hf_hundredths,
2333                         { "Hundredths of a second", "lanman.hundredths", FT_UINT8, BASE_DEC,
2334                         NULL, 0, "LANMAN Current hundredths of a second", HFILL }},
2335
2336                 { &hf_tzoffset,
2337                         { "Time Zone Offset", "lanman.tzoffset", FT_INT16, BASE_DEC,
2338                         NULL, 0, "LANMAN Offset of time zone from GMT, in minutes", HFILL }},
2339
2340                 { &hf_timeinterval,
2341                         { "Time Interval", "lanman.timeinterval", FT_UINT16, BASE_DEC,
2342                         NULL, 0, "LANMAN .0001 second units per clock tick", HFILL }},
2343
2344                 { &hf_day,
2345                         { "Day", "lanman.day", FT_UINT8, BASE_DEC,
2346                         NULL, 0, "LANMAN Current day", HFILL }},
2347
2348                 { &hf_month,
2349                         { "Month", "lanman.month", FT_UINT8, BASE_DEC,
2350                         NULL, 0, "LANMAN Current month", HFILL }},
2351
2352                 { &hf_year,
2353                         { "Year", "lanman.year", FT_UINT16, BASE_DEC,
2354                         NULL, 0, "LANMAN Current year", HFILL }},
2355
2356                 { &hf_weekday,
2357                         { "Weekday", "lanman.weekday", FT_UINT8, BASE_DEC,
2358                         VALS(weekday_vals), 0, "LANMAN Current day of the week", HFILL }},
2359
2360                 { &hf_enumeration_domain,
2361                         { "Enumeration Domain", "lanman.enumeration_domain", FT_STRING, BASE_NONE,
2362                         NULL, 0, "LANMAN Domain in which to enumerate servers", HFILL }},
2363
2364                 { &hf_computer_name,
2365                         { "Computer Name", "lanman.computer_name", FT_STRING, BASE_NONE,
2366                         NULL, 0, "LANMAN Computer Name", HFILL }},
2367
2368                 { &hf_user_name,
2369                         { "User Name", "lanman.user_name", FT_STRING, BASE_NONE,
2370                         NULL, 0, "LANMAN User Name", HFILL }},
2371
2372                 { &hf_workstation_domain,
2373                         { "Workstation Domain", "lanman.workstation_domain", FT_STRING, BASE_NONE,
2374                         NULL, 0, "LANMAN Workstation Domain", HFILL }},
2375
2376                 { &hf_workstation_major,
2377                         { "Workstation Major Version", "lanman.workstation_major", FT_UINT8, BASE_DEC,
2378                         NULL, 0, "LANMAN Workstation Major Version", HFILL }},
2379
2380                 { &hf_workstation_minor,
2381                         { "Workstation Minor Version", "lanman.workstation_minor", FT_UINT8, BASE_DEC,
2382                         NULL, 0, "LANMAN Workstation Minor Version", HFILL }},
2383
2384                 { &hf_logon_domain,
2385                         { "Logon Domain", "lanman.logon_domain", FT_STRING, BASE_NONE,
2386                         NULL, 0, "LANMAN Logon Domain", HFILL }},
2387
2388                 { &hf_other_domains,
2389                         { "Other Domains", "lanman.other_domains", FT_STRING, BASE_NONE,
2390                         NULL, 0, "LANMAN Other Domains", HFILL }},
2391
2392                 { &hf_password,
2393                         { "Password", "lanman.password", FT_STRING, BASE_NONE,
2394                         NULL, 0, "LANMAN Password", HFILL }},
2395
2396                 { &hf_workstation_name,
2397                         { "Workstation Name", "lanman.workstation_name", FT_STRING, BASE_NONE,
2398                         NULL, 0, "LANMAN Workstation Name", HFILL }},
2399
2400                 { &hf_ustruct_size,
2401                         { "Length of UStruct", "lanman.ustruct_size", FT_UINT16, BASE_DEC,
2402                         NULL, 0, "LANMAN UStruct Length", HFILL }},
2403
2404                 { &hf_logon_code,
2405                         { "Logon Code", "lanman.logon_code", FT_UINT16, BASE_DEC,
2406                         VALS(status_vals), 0, "LANMAN Logon Code", HFILL }},
2407
2408                 { &hf_privilege_level,
2409                         { "Privilege Level", "lanman.privilege_level", FT_UINT16, BASE_DEC,
2410                         VALS(privilege_vals), 0, "LANMAN Privilege Level", HFILL }},
2411
2412                 { &hf_operator_privileges,
2413                         { "Operator Privileges", "lanman.operator_privileges", FT_UINT32, BASE_DEC,
2414                         VALS(op_privilege_vals), 0, "LANMAN Operator Privileges", HFILL }},
2415
2416                 { &hf_num_logons,
2417                         { "Number of Logons", "lanman.num_logons", FT_UINT16, BASE_DEC,
2418                         NULL, 0, "LANMAN Number of Logons", HFILL }},
2419
2420                 { &hf_bad_pw_count,
2421                         { "Bad Password Count", "lanman.bad_pw_count", FT_UINT16, BASE_DEC,
2422                         NULL, 0, "LANMAN Number of incorrect passwords entered since last successful login", HFILL }},
2423
2424                 { &hf_last_logon,
2425                         { "Last Logon Date/Time", "lanman.last_logon", FT_ABSOLUTE_TIME, BASE_NONE,
2426                         NULL, 0, "LANMAN Date and time of last logon", HFILL }},
2427
2428                 { &hf_last_logoff,
2429                         { "Last Logoff Date/Time", "lanman.last_logoff", FT_ABSOLUTE_TIME, BASE_NONE,
2430                         NULL, 0, "LANMAN Date and time of last logoff", HFILL }},
2431
2432                 { &hf_logoff_time,
2433                         { "Logoff Date/Time", "lanman.logoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
2434                         NULL, 0, "LANMAN Date and time when user should log off", HFILL }},
2435
2436                 { &hf_kickoff_time,
2437                         { "Kickoff Date/Time", "lanman.kickoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
2438                         NULL, 0, "LANMAN Date and time when user will be logged off", HFILL }},
2439
2440                 { &hf_password_age,
2441                         { "Password Age", "lanman.password_age", FT_RELATIVE_TIME, BASE_NONE,
2442                         NULL, 0, "LANMAN Time since user last changed his/her password", HFILL }},
2443
2444                 { &hf_password_can_change,
2445                         { "Password Can Change", "lanman.password_can_change", FT_ABSOLUTE_TIME, BASE_NONE,
2446                         NULL, 0, "LANMAN Date and time when user can change their password", HFILL }},
2447
2448                 { &hf_password_must_change,
2449                         { "Password Must Change", "lanman.password_must_change", FT_ABSOLUTE_TIME, BASE_NONE,
2450                         NULL, 0, "LANMAN Date and time when user must change their password", HFILL }},
2451
2452                 { &hf_script_path,
2453                         { "Script Path", "lanman.script_path", FT_STRING, BASE_NONE,
2454                         NULL, 0, "LANMAN Pathname of user's logon script", HFILL }},
2455
2456                 { &hf_logoff_code,
2457                         { "Logoff Code", "lanman.logoff_code", FT_UINT16, BASE_DEC,
2458                         VALS(status_vals), 0, "LANMAN Logoff Code", HFILL }},
2459
2460                 { &hf_duration,
2461                         { "Duration of Session", "lanman.duration", FT_RELATIVE_TIME, BASE_NONE,
2462                         NULL, 0, "LANMAN Number of seconds the user was logged on", HFILL }},
2463
2464                 { &hf_user_comment,
2465                         { "User Comment", "lanman.user_comment", FT_STRING, BASE_NONE,
2466                         NULL, 0, "LANMAN User Comment", HFILL }},
2467
2468                 { &hf_full_name,
2469                         { "Full Name", "lanman.full_name", FT_STRING, BASE_NONE,
2470                         NULL, 0, "LANMAN Full Name", HFILL }},
2471
2472                 { &hf_homedir,
2473                         { "Home Directory", "lanman.homedir", FT_STRING, BASE_NONE,
2474                         NULL, 0, "LANMAN Home Directory", HFILL }},
2475
2476                 { &hf_parameters,
2477                         { "Parameters", "lanman.parameters", FT_STRING, BASE_NONE,
2478                         NULL, 0, "LANMAN Parameters", HFILL }},
2479
2480                 { &hf_logon_server,
2481                         { "Logon Server", "lanman.logon_server", FT_STRING, BASE_NONE,
2482                         NULL, 0, "LANMAN Logon Server", HFILL }},
2483
2484                 /* XXX - we should have a value_string table for this */
2485                 { &hf_country_code,
2486                         { "Country Code", "lanman.country_code", FT_UINT16, BASE_DEC,
2487                         NULL, 0, "LANMAN Country Code", HFILL }},
2488
2489                 { &hf_workstations,
2490                         { "Workstations", "lanman.workstations", FT_STRING, BASE_NONE,
2491                         NULL, 0, "LANMAN Workstations", HFILL }},
2492
2493                 { &hf_max_storage,
2494                         { "Max Storage", "lanman.max_storage", FT_UINT32, BASE_DEC,
2495                         NULL, 0, "LANMAN Max Storage", HFILL }},
2496
2497                 { &hf_units_per_week,
2498                         { "Units Per Week", "lanman.units_per_week", FT_UINT16, BASE_DEC,
2499                         NULL, 0, "LANMAN Units Per Week", HFILL }},
2500
2501                 { &hf_logon_hours,
2502                         { "Logon Hours", "lanman.logon_hours", FT_BYTES, BASE_NONE,
2503                         NULL, 0, "LANMAN Logon Hours", HFILL }},
2504
2505                 /* XXX - we should have a value_string table for this */
2506                 { &hf_code_page,
2507                         { "Code Page", "lanman.code_page", FT_UINT16, BASE_DEC,
2508                         NULL, 0, "LANMAN Code Page", HFILL }},
2509
2510                 { &hf_new_password,
2511                         { "New Password", "lanman.new_password", FT_BYTES, BASE_HEX,
2512                         NULL, 0, "LANMAN New Password (encrypted)", HFILL }},
2513
2514                 { &hf_old_password,
2515                         { "Old Password", "lanman.old_password", FT_BYTES, BASE_HEX,
2516                         NULL, 0, "LANMAN Old Password (encrypted)", HFILL }},
2517
2518                 { &hf_reserved,
2519                         { "Reserved", "lanman.reserved", FT_UINT32, BASE_HEX,
2520                         NULL, 0, "LANMAN Reserved", HFILL }},
2521
2522         };
2523         static gint *ett[] = {
2524                 &ett_lanman,
2525                 &ett_lanman_servers,
2526                 &ett_lanman_server,
2527                 &ett_lanman_shares,
2528                 &ett_lanman_share,
2529         };
2530
2531         proto_smb_lanman = proto_register_protocol(
2532                 "Microsoft Windows Lanman Remote API Protocol", "LANMAN", "lanman");
2533         proto_register_field_array(proto_smb_lanman, hf, array_length(hf));
2534         proto_register_subtree_array(ett, array_length(ett));
2535 }