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