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