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