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