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