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