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