2 XXX Fixme : shouldnt show [malformed frame] for long packets
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
11 * $Id: packet-smb-pipe.c,v 1.66 2002/01/21 07:36:42 guy Exp $
13 * Ethereal - Network traffic analyzer
14 * By Gerald Combs <gerald@ethereal.com>
15 * Copyright 1998 Gerald Combs
17 * Copied from packet-pop.c
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.
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.
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.
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
52 #include <epan/packet.h>
53 #include <epan/conversation.h>
55 #include "packet-smb-pipe.h"
56 #include "packet-smb-browse.h"
57 #include "packet-dcerpc.h"
58 #include "reassemble.h"
60 static int proto_smb_pipe = -1;
61 static int hf_pipe_function = -1;
62 static int hf_pipe_priority = -1;
63 static int hf_pipe_peek_available = -1;
64 static int hf_pipe_peek_remaining = -1;
65 static int hf_pipe_peek_status = -1;
66 static int hf_pipe_getinfo_info_level = -1;
67 static int hf_pipe_getinfo_output_buffer_size = -1;
68 static int hf_pipe_getinfo_input_buffer_size = -1;
69 static int hf_pipe_getinfo_maximum_instances = -1;
70 static int hf_pipe_getinfo_current_instances = -1;
71 static int hf_pipe_getinfo_pipe_name_length = -1;
72 static int hf_pipe_getinfo_pipe_name = -1;
73 static int hf_pipe_write_raw_bytes_written = -1;
75 static gint ett_smb_pipe = -1;
76 static gint ett_smb_pipe_fragments = -1;
78 static int proto_smb_lanman = -1;
79 static int hf_function_code = -1;
80 static int hf_param_desc = -1;
81 static int hf_return_desc = -1;
82 static int hf_aux_data_desc = -1;
83 static int hf_detail_level = -1;
84 static int hf_recv_buf_len = -1;
85 static int hf_send_buf_len = -1;
86 static int hf_continuation_from = -1;
87 static int hf_status = -1;
88 static int hf_convert = -1;
89 static int hf_ecount = -1;
90 static int hf_acount = -1;
91 static int hf_share_name = -1;
92 static int hf_share_type = -1;
93 static int hf_share_comment = -1;
94 static int hf_share_permissions = -1;
95 static int hf_share_max_uses = -1;
96 static int hf_share_current_uses = -1;
97 static int hf_share_path = -1;
98 static int hf_share_password = -1;
99 static int hf_server_name = -1;
100 static int hf_server_major = -1;
101 static int hf_server_minor = -1;
102 static int hf_server_comment = -1;
103 static int hf_abytes = -1;
104 static int hf_current_time = -1;
105 static int hf_msecs = -1;
106 static int hf_hour = -1;
107 static int hf_minute = -1;
108 static int hf_second = -1;
109 static int hf_hundredths = -1;
110 static int hf_tzoffset = -1;
111 static int hf_timeinterval = -1;
112 static int hf_day = -1;
113 static int hf_month = -1;
114 static int hf_year = -1;
115 static int hf_weekday = -1;
116 static int hf_enumeration_domain = -1;
117 static int hf_computer_name = -1;
118 static int hf_user_name = -1;
119 static int hf_workstation_domain = -1;
120 static int hf_workstation_major = -1;
121 static int hf_workstation_minor = -1;
122 static int hf_logon_domain = -1;
123 static int hf_other_domains = -1;
124 static int hf_password = -1;
125 static int hf_workstation_name = -1;
126 static int hf_ustruct_size = -1;
127 static int hf_logon_code = -1;
128 static int hf_privilege_level = -1;
129 static int hf_operator_privileges = -1;
130 static int hf_num_logons = -1;
131 static int hf_bad_pw_count = -1;
132 static int hf_last_logon = -1;
133 static int hf_last_logoff = -1;
134 static int hf_logoff_time = -1;
135 static int hf_kickoff_time = -1;
136 static int hf_password_age = -1;
137 static int hf_password_can_change = -1;
138 static int hf_password_must_change = -1;
139 static int hf_script_path = -1;
140 static int hf_logoff_code = -1;
141 static int hf_duration = -1;
142 static int hf_user_comment = -1;
143 static int hf_full_name = -1;
144 static int hf_homedir = -1;
145 static int hf_parameters = -1;
146 static int hf_logon_server = -1;
147 static int hf_country_code = -1;
148 static int hf_workstations = -1;
149 static int hf_max_storage = -1;
150 static int hf_units_per_week = -1;
151 static int hf_logon_hours = -1;
152 static int hf_code_page = -1;
153 static int hf_new_password = -1;
154 static int hf_old_password = -1;
155 static int hf_reserved = -1;
157 static gint ett_lanman = -1;
158 static gint ett_lanman_shares = -1;
159 static gint ett_lanman_share = -1;
160 static gint ett_lanman_servers = -1;
161 static gint ett_lanman_server = -1;
163 static dissector_handle_t data_handle;
168 * ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt
170 * among other documents.
173 static const value_string status_vals[] = {
175 {5, "User has insufficient privilege"},
176 {65, "Network access is denied"},
177 {86, "The specified password is invalid"},
178 {SMBE_moredata, "Additional data is available"},
179 {2114, "Service is not running on the remote computer"},
180 {2123, "Supplied buffer is too small"},
181 {2141, "Server is not configured for transactions (IPC$ not shared)"},
182 {2212, "An error occurred while loading or running the logon script"},
183 {2214, "The logon was not validated by any server"},
184 {2217, "The logon server is running an older software version"},
185 {2221, "The user name was not found"},
186 {2240, "The user is not allowed to logon from this computer"},
187 {2241, "The user is not allowed to logon at this time"},
188 {2242, "The user password has expired"},
189 {2243, "The password cannot be changed"},
190 {2246, "The password is too short"},
194 static const value_string share_type_vals[] = {
195 {0, "Directory tree"},
196 {1, "Printer queue"},
197 {2, "Communications device"},
202 static const value_string privilege_vals[] = {
205 {2, "Administrator"},
209 static const value_string op_privilege_vals[] = {
210 {0, "Print operator"},
211 {1, "Communications operator"},
212 {2, "Server operator"},
213 {3, "Accounts operator"},
217 static const value_string weekday_vals[] = {
229 add_word_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
230 proto_tree *tree, int convert, int hf_index)
235 proto_tree_add_item(tree, hf_index, tvb, offset, 2, TRUE);
237 WParam = tvb_get_letohs(tvb, offset);
238 proto_tree_add_text(tree, tvb, offset, 2,
239 "Word Param: %u (0x%04X)", WParam, WParam);
246 add_dword_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
247 proto_tree *tree, int convert, int hf_index)
252 proto_tree_add_item(tree, hf_index, tvb, offset, 4, TRUE);
254 LParam = tvb_get_letohl(tvb, offset);
255 proto_tree_add_text(tree, tvb, offset, 4,
256 "Doubleword Param: %u (0x%08X)", LParam, LParam);
263 add_byte_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
264 proto_tree *tree, int convert, int hf_index)
269 proto_tree_add_item(tree, hf_index, tvb, offset, count, TRUE);
272 BParam = tvb_get_guint8(tvb, offset);
273 proto_tree_add_text(tree, tvb, offset, count,
274 "Byte Param: %u (0x%02X)",
277 proto_tree_add_text(tree, tvb, offset, count,
278 "Bytes Param: %s, type is wrong",
279 tvb_bytes_to_str(tvb, offset, count));
287 add_pad_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
288 proto_tree *tree, int convert, int hf_index)
291 * This is for parameters that have descriptor entries but that
292 * are, in practice, just padding.
299 add_null_pointer_param(tvbuff_t *tvb, int offset, int count,
300 packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
302 if (hf_index != -1) {
303 proto_tree_add_text(tree, tvb, offset, 0,
305 proto_registrar_get_name(hf_index));
307 proto_tree_add_text(tree, tvb, offset, 0,
308 "String Param (Null pointer)");
313 add_string_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
314 proto_tree *tree, int convert, int hf_index)
318 string_len = tvb_strsize(tvb, offset);
319 if (hf_index != -1) {
320 proto_tree_add_item(tree, hf_index, tvb, offset, string_len,
323 proto_tree_add_text(tree, tvb, offset, string_len,
325 tvb_format_text(tvb, offset, string_len));
327 offset += string_len;
332 get_pointer_value(tvbuff_t *tvb, int offset, int convert, int *cptrp, int *lenp)
337 /* pointer to string */
338 cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
342 if (tvb_offset_exists(tvb, cptr) &&
343 (string_len = tvb_strnlen(tvb, cptr, -1)) != -1) {
344 string_len++; /* include the terminating '\0' */
346 return tvb_format_text(tvb, cptr, string_len - 1);
352 add_pointer_param(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
353 proto_tree *tree, int convert, int hf_index)
359 string = get_pointer_value(tvb, offset, convert, &cptr, &string_len);
363 if (string != NULL) {
364 if (hf_index != -1) {
365 proto_tree_add_item(tree, hf_index, tvb, cptr,
368 proto_tree_add_text(tree, tvb, cptr, string_len,
369 "String Param: %s", string);
372 if (hf_index != -1) {
373 proto_tree_add_text(tree, tvb, 0, 0,
374 "%s: <String goes past end of frame>",
375 proto_registrar_get_name(hf_index));
377 proto_tree_add_text(tree, tvb, 0, 0,
378 "String Param: <String goes past end of frame>");
386 add_detail_level(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
387 proto_tree *tree, int convert, int hf_index)
389 struct smb_info *smb_info = pinfo->private_data;
390 smb_transact_info_t *trp = smb_info->sip->extra_info;
393 level = tvb_get_letohs(tvb, offset);
394 if (!pinfo->fd->flags.visited)
395 trp->info_level = level; /* remember this for the response */
396 proto_tree_add_uint(tree, hf_index, tvb, offset, 2, level);
402 add_max_uses(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
403 proto_tree *tree, int convert, int hf_index)
407 WParam = tvb_get_letohs(tvb, offset);
408 if (WParam == 0xffff) { /* -1 */
409 proto_tree_add_uint_format(tree, hf_index, tvb,
412 proto_registrar_get_name(hf_index));
414 proto_tree_add_uint(tree, hf_index, tvb,
422 add_server_type(tvbuff_t *tvb, int offset, int count,
423 packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
425 dissect_smb_server_type_flags(tvb, pinfo, tree, offset, FALSE);
431 add_server_type_info(tvbuff_t *tvb, int offset, int count,
432 packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
434 dissect_smb_server_type_flags(tvb, pinfo, tree, offset, TRUE);
440 add_reltime(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
441 proto_tree *tree, int convert, int hf_index)
445 nstime.secs = tvb_get_letohl(tvb, offset);
447 proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
448 &nstime, "%s: %s", proto_registrar_get_name(hf_index),
449 time_secs_to_str(nstime.secs));
455 * Sigh. These are for handling Microsoft's annoying almost-UNIX-time-but-
456 * it's-local-time-not-UTC time.
459 add_abstime_common(tvbuff_t *tvb, int offset, int count,
460 packet_info *pinfo, proto_tree *tree, int convert, int hf_index,
461 const char *absent_name)
466 nstime.secs = tvb_get_letohl(tvb, offset);
468 if (nstime.secs == -1) {
469 proto_tree_add_time_format(tree, hf_index, tvb, offset, 4,
470 &nstime, "%s: %s", proto_registrar_get_name(hf_index),
474 * Run it through "gmtime()" to break it down, and then
475 * run it through "mktime()" to put it back together
478 tmp = gmtime(&nstime.secs);
479 tmp->tm_isdst = -1; /* we don't know if it's DST or not */
480 nstime.secs = mktime(tmp);
481 proto_tree_add_time(tree, hf_index, tvb, offset, 4,
489 add_abstime_absent_never(tvbuff_t *tvb, int offset, int count,
490 packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
492 return add_abstime_common(tvb, offset, count, pinfo, tree,
493 convert, hf_index, "Never");
497 add_abstime_absent_unknown(tvbuff_t *tvb, int offset, int count,
498 packet_info *pinfo, proto_tree *tree, int convert, int hf_index)
500 return add_abstime_common(tvb, offset, count, pinfo, tree,
501 convert, hf_index, "Unknown");
505 add_nlogons(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
506 proto_tree *tree, int convert, int hf_index)
510 nlogons = tvb_get_letohs(tvb, offset);
511 if (nlogons == 0xffff) /* -1 */
512 proto_tree_add_uint_format(tree, hf_index, tvb, offset, 2,
513 nlogons, "%s: Unknown",
514 proto_registrar_get_name(hf_index));
516 proto_tree_add_uint(tree, hf_index, tvb, offset, 2,
523 add_max_storage(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
524 proto_tree *tree, int convert, int hf_index)
528 max_storage = tvb_get_letohl(tvb, offset);
529 if (max_storage == 0xffffffff)
530 proto_tree_add_uint_format(tree, hf_index, tvb, offset, 4,
531 max_storage, "%s: No limit",
532 proto_registrar_get_name(hf_index));
534 proto_tree_add_uint(tree, hf_index, tvb, offset, 4,
541 add_logon_hours(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
542 proto_tree *tree, int convert, int hf_index)
546 /* pointer to string */
547 cptr = (tvb_get_letohl(tvb, offset)&0xffff)-convert;
551 /* XXX - should actually carve up the bits */
552 proto_tree_add_item(tree, hf_index, tvb, cptr, 21, TRUE);
558 add_tzoffset(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
559 proto_tree *tree, int convert, int hf_index)
563 tzoffset = tvb_get_letohs(tvb, offset);
565 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
566 tzoffset, "%s: %s east of UTC",
567 proto_registrar_get_name(hf_index),
568 time_secs_to_str(-tzoffset*60));
569 } else if (tzoffset > 0) {
570 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
571 tzoffset, "%s: %s west of UTC",
572 proto_registrar_get_name(hf_index),
573 time_secs_to_str(tzoffset*60));
575 proto_tree_add_int_format(tree, hf_tzoffset, tvb, offset, 2,
576 tzoffset, "%s: at UTC",
577 proto_registrar_get_name(hf_index));
584 add_timeinterval(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
585 proto_tree *tree, int convert, int hf_index)
587 guint16 timeinterval;
589 timeinterval = tvb_get_letohs(tvb, offset);
590 proto_tree_add_uint_format(tree, hf_timeinterval, tvb, offset, 2,
591 timeinterval, "%s: %f seconds", proto_registrar_get_name(hf_index),
598 add_logon_args(tvbuff_t *tvb, int offset, int count, packet_info *pinfo,
599 proto_tree *tree, int convert, int hf_index)
602 proto_tree_add_text(tree, tvb, offset, count,
603 "Bogus NetWkstaUserLogon parameters: length is %d, should be 54",
610 proto_tree_add_item(tree, hf_user_name, tvb, offset, 21, TRUE);
617 proto_tree_add_item(tree, hf_password, tvb, offset, 15, TRUE);
623 /* workstation name */
624 proto_tree_add_item(tree, hf_workstation_name, tvb, offset, 16, TRUE);
630 * The following data structure describes the Remote API requests we
633 * Simply fill in the number and parameter information.
634 * Try to keep them in order.
636 * We will extend this data structure as we try to decode more.
640 * This is a pointer to a function to process an item.
642 typedef int (*item_func)(tvbuff_t *, int, int, packet_info *, proto_tree *,
646 * Type of an item; determines what parameter strings are valid for
650 PARAM_NONE, /* for the end-of-list stopper */
651 PARAM_WORD, /* 'W' or 'h' - 16-bit word */
652 PARAM_DWORD, /* 'D' or 'i' - 32-bit word */
653 PARAM_BYTES, /* 'B' or 'b' or 'g' or 'O' - one or more bytes */
654 PARAM_STRINGZ, /* 'z' or 'O' - null-terminated string */
658 * This structure describes an item; "hf_index" points to the index
659 * for the field corresponding to that item, "func" points to the
660 * function to use to add that item to the tree, and "type" is the
661 * type that the item is supposed to have.
670 * This structure describes a list of items; each list of items
671 * has a corresponding detail level.
675 const item_t *item_list;
681 proto_item *(*req_data_item)(tvbuff_t *, packet_info *,
684 const item_t *req_data;
685 const item_t *req_aux_data;
687 proto_item *(*resp_data_item)(tvbuff_t *, packet_info *,
690 proto_item *(*resp_data_element_item)(tvbuff_t *, packet_info *,
692 gint *ett_resp_data_element_item;
693 const item_list_t *resp_data_list;
694 const item_t *resp_aux_data;
697 static int no_hf = -1; /* for padding crap */
699 static const item_t lm_params_req_netshareenum[] = {
700 { &hf_detail_level, add_detail_level, PARAM_WORD },
701 { &hf_recv_buf_len, add_word_param, PARAM_WORD },
702 { NULL, NULL, PARAM_NONE }
705 static const item_t lm_params_resp_netshareenum[] = {
706 { &hf_acount, add_word_param, PARAM_WORD },
707 { NULL, NULL, PARAM_NONE }
711 * Create a subtree for all available shares.
714 netshareenum_shares_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
718 return proto_tree_add_text(tree, tvb, offset, -1,
725 * Create a subtree for a share.
728 netshareenum_share_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
732 return proto_tree_add_text(tree, tvb, offset, -1,
733 "Share %.13s", tvb_get_ptr(tvb, offset, 13));
738 static const item_t lm_null[] = {
739 { NULL, NULL, PARAM_NONE }
742 static const item_list_t lm_null_list[] = {
746 static const item_t lm_data_resp_netshareenum_1[] = {
747 { &hf_share_name, add_byte_param, PARAM_BYTES },
748 { &no_hf, add_pad_param, PARAM_BYTES },
749 { &hf_share_type, add_word_param, PARAM_WORD },
750 { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
751 { NULL, NULL, PARAM_NONE }
754 static const item_list_t lm_data_resp_netshareenum[] = {
755 { 1, lm_data_resp_netshareenum_1 },
759 static const item_t lm_params_req_netsharegetinfo[] = {
760 { &hf_share_name, add_string_param, PARAM_STRINGZ },
761 { &hf_detail_level, add_detail_level, PARAM_WORD },
762 { NULL, NULL, PARAM_NONE }
765 static const item_t lm_params_resp_netsharegetinfo[] = {
766 { &hf_abytes, add_word_param, PARAM_WORD },
767 { NULL, NULL, PARAM_NONE }
770 static const item_t lm_data_resp_netsharegetinfo_0[] = {
771 { &hf_share_name, add_byte_param, PARAM_BYTES },
772 { NULL, NULL, PARAM_NONE }
775 static const item_t lm_data_resp_netsharegetinfo_1[] = {
776 { &hf_share_name, add_byte_param, PARAM_BYTES },
777 { &no_hf, add_pad_param, PARAM_BYTES },
778 { &hf_share_type, add_word_param, PARAM_WORD },
779 { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
780 { NULL, NULL, PARAM_NONE }
783 static const item_t lm_data_resp_netsharegetinfo_2[] = {
784 { &hf_share_name, add_byte_param, PARAM_BYTES },
785 { &no_hf, add_pad_param, PARAM_BYTES },
786 { &hf_share_type, add_word_param, PARAM_WORD },
787 { &hf_share_comment, add_pointer_param, PARAM_STRINGZ },
788 { &hf_share_permissions, add_word_param, PARAM_WORD }, /* XXX - do as bit fields */
789 { &hf_share_max_uses, add_max_uses, PARAM_WORD },
790 { &hf_share_current_uses, add_word_param, PARAM_WORD },
791 { &hf_share_path, add_pointer_param, PARAM_STRINGZ },
792 { &hf_share_password, add_byte_param, PARAM_BYTES },
793 { NULL, NULL, PARAM_NONE }
796 static const item_list_t lm_data_resp_netsharegetinfo[] = {
797 { 0, lm_data_resp_netsharegetinfo_0 },
798 { 1, lm_data_resp_netsharegetinfo_1 },
799 { 2, lm_data_resp_netsharegetinfo_2 },
803 static const item_t lm_params_req_netservergetinfo[] = {
804 { &hf_detail_level, add_detail_level, PARAM_WORD },
805 { NULL, NULL, PARAM_NONE }
808 static const item_t lm_params_resp_netservergetinfo[] = {
809 { &hf_abytes, add_word_param, PARAM_WORD },
810 { NULL, NULL, PARAM_NONE }
813 static const item_t lm_data_serverinfo_0[] = {
814 { &hf_server_name, add_byte_param, PARAM_BYTES },
815 { NULL, NULL, PARAM_NONE }
818 static const item_t lm_data_serverinfo_1[] = {
819 { &hf_server_name, add_byte_param, PARAM_BYTES },
820 { &hf_server_major, add_byte_param, PARAM_BYTES },
821 { &hf_server_minor, add_byte_param, PARAM_BYTES },
822 { &no_hf, add_server_type, PARAM_DWORD },
823 { &hf_server_comment, add_pointer_param, PARAM_STRINGZ },
824 { NULL, NULL, PARAM_NONE }
827 static const item_list_t lm_data_serverinfo[] = {
828 { 0, lm_data_serverinfo_0 },
829 { 1, lm_data_serverinfo_1 },
833 static const item_t lm_params_req_netusergetinfo[] = {
834 { &hf_detail_level, add_detail_level, PARAM_WORD },
835 { NULL, NULL, PARAM_NONE }
838 static const item_t lm_params_resp_netusergetinfo[] = {
839 { &hf_abytes, add_word_param, PARAM_WORD },
840 { NULL, NULL, PARAM_NONE }
843 static const item_t lm_data_resp_netusergetinfo_11[] = {
844 { &hf_user_name, add_byte_param, PARAM_BYTES },
845 { &no_hf, add_pad_param, PARAM_BYTES },
846 { &hf_user_comment, add_pointer_param, PARAM_STRINGZ },
847 { &hf_full_name, add_pointer_param, PARAM_STRINGZ },
848 { &hf_privilege_level, add_word_param, PARAM_WORD },
849 { &hf_operator_privileges, add_dword_param, PARAM_DWORD },
850 { &hf_password_age, add_reltime, PARAM_DWORD },
851 { &hf_homedir, add_pointer_param, PARAM_STRINGZ },
852 { &hf_parameters, add_pointer_param, PARAM_STRINGZ },
853 { &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
854 { &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
855 { &hf_bad_pw_count, add_word_param, PARAM_WORD },
856 { &hf_num_logons, add_nlogons, PARAM_WORD },
857 { &hf_logon_server, add_pointer_param, PARAM_STRINGZ },
858 { &hf_country_code, add_word_param, PARAM_WORD },
859 { &hf_workstations, add_pointer_param, PARAM_STRINGZ },
860 { &hf_max_storage, add_max_storage, PARAM_DWORD },
861 { &hf_logon_hours, add_logon_hours, PARAM_DWORD },
862 { &hf_code_page, add_word_param, PARAM_WORD },
863 { NULL, NULL, PARAM_NONE }
866 static const item_list_t lm_data_resp_netusergetinfo[] = {
867 { 11, lm_data_resp_netusergetinfo_11 },
872 * Has no detail level; make it the default.
874 static const item_t lm_data_resp_netremotetod_nolevel[] = {
875 { &hf_current_time, add_abstime_absent_unknown, PARAM_DWORD },
876 { &hf_msecs, add_dword_param, PARAM_DWORD },
877 { &hf_hour, add_byte_param, PARAM_BYTES },
878 { &hf_minute, add_byte_param, PARAM_BYTES },
879 { &hf_second, add_byte_param, PARAM_BYTES },
880 { &hf_hundredths, add_byte_param, PARAM_BYTES },
881 { &hf_tzoffset, add_tzoffset, PARAM_WORD },
882 { &hf_timeinterval, add_timeinterval, PARAM_WORD },
883 { &hf_day, add_byte_param, PARAM_BYTES },
884 { &hf_month, add_byte_param, PARAM_BYTES },
885 { &hf_year, add_word_param, PARAM_WORD },
886 { &hf_weekday, add_byte_param, PARAM_BYTES },
887 { NULL, NULL, PARAM_NONE }
890 static const item_list_t lm_data_resp_netremotetod[] = {
891 { -1, lm_data_resp_netremotetod_nolevel },
894 static const item_t lm_params_req_netserverenum2[] = {
895 { &hf_detail_level, add_detail_level, PARAM_WORD },
896 { &no_hf, add_server_type_info, PARAM_DWORD },
897 { &hf_enumeration_domain, add_string_param, PARAM_STRINGZ },
898 { NULL, NULL, PARAM_NONE }
902 * Create a subtree for all servers.
905 netserverenum2_servers_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
909 return proto_tree_add_text(tree, tvb, offset, -1,
916 * Create a subtree for a share.
919 netserverenum2_server_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
923 return proto_tree_add_text(tree, tvb, offset, -1,
924 "Server %.16s", tvb_get_ptr(tvb, offset, 16));
928 static const item_t lm_params_resp_netserverenum2[] = {
929 { &hf_acount, add_word_param, PARAM_WORD },
930 { NULL, NULL, PARAM_NONE }
933 static const item_t lm_params_req_netwkstagetinfo[] = {
934 { &hf_detail_level, add_detail_level, PARAM_WORD },
935 { NULL, NULL, PARAM_NONE }
938 static const item_t lm_params_resp_netwkstagetinfo[] = {
939 { &hf_abytes, add_word_param, PARAM_WORD },
940 { NULL, NULL, PARAM_NONE }
943 static const item_t lm_data_resp_netwkstagetinfo_10[] = {
944 { &hf_computer_name, add_pointer_param, PARAM_STRINGZ },
945 { &hf_user_name, add_pointer_param, PARAM_STRINGZ },
946 { &hf_workstation_domain, add_pointer_param, PARAM_STRINGZ },
947 { &hf_workstation_major, add_byte_param, PARAM_BYTES },
948 { &hf_workstation_minor, add_byte_param, PARAM_BYTES },
949 { &hf_logon_domain, add_pointer_param, PARAM_STRINGZ },
950 { &hf_other_domains, add_pointer_param, PARAM_STRINGZ },
951 { NULL, NULL, PARAM_NONE }
954 static const item_list_t lm_data_resp_netwkstagetinfo[] = {
955 { 10, lm_data_resp_netwkstagetinfo_10 },
959 static const item_t lm_params_req_netwkstauserlogon[] = {
960 { &no_hf, add_pointer_param, PARAM_STRINGZ },
961 { &no_hf, add_pointer_param, PARAM_STRINGZ },
962 { &hf_detail_level, add_detail_level, PARAM_WORD },
963 { &no_hf, add_logon_args, PARAM_BYTES },
964 { &hf_ustruct_size, add_word_param, PARAM_WORD },
965 { NULL, NULL, PARAM_NONE }
968 static const item_t lm_params_resp_netwkstauserlogon[] = {
969 { &hf_abytes, add_word_param, PARAM_WORD },
970 { NULL, NULL, PARAM_NONE }
973 static const item_t lm_data_resp_netwkstauserlogon_1[] = {
974 { &hf_logon_code, add_word_param, PARAM_WORD },
975 { &hf_user_name, add_byte_param, PARAM_BYTES },
976 { &no_hf, add_pad_param, PARAM_BYTES },
977 { &hf_privilege_level, add_word_param, PARAM_WORD },
978 { &hf_operator_privileges, add_dword_param, PARAM_DWORD },
979 { &hf_num_logons, add_nlogons, PARAM_WORD },
980 { &hf_bad_pw_count, add_word_param, PARAM_WORD },
981 { &hf_last_logon, add_abstime_absent_unknown, PARAM_DWORD },
982 { &hf_last_logoff, add_abstime_absent_unknown, PARAM_DWORD },
983 { &hf_logoff_time, add_abstime_absent_never, PARAM_DWORD },
984 { &hf_kickoff_time, add_abstime_absent_never, PARAM_DWORD },
985 { &hf_password_age, add_reltime, PARAM_DWORD },
986 { &hf_password_can_change, add_abstime_absent_never, PARAM_DWORD },
987 { &hf_password_must_change, add_abstime_absent_never, PARAM_DWORD },
988 { &hf_server_name, add_pointer_param, PARAM_STRINGZ },
989 { &hf_logon_domain, add_pointer_param, PARAM_STRINGZ },
990 { &hf_script_path, add_pointer_param, PARAM_STRINGZ },
991 { &hf_reserved, add_dword_param, PARAM_DWORD },
992 { NULL, NULL, PARAM_NONE }
995 static const item_list_t lm_data_resp_netwkstauserlogon[] = {
996 { 1, lm_data_resp_netwkstauserlogon_1 },
1000 static const item_t lm_params_req_netwkstauserlogoff[] = {
1001 { &hf_user_name, add_byte_param, PARAM_BYTES },
1002 { &no_hf, add_pad_param, PARAM_BYTES },
1003 { &hf_workstation_name, add_byte_param, PARAM_BYTES },
1004 { NULL, NULL, PARAM_NONE }
1007 static const item_t lm_params_resp_netwkstauserlogoff[] = {
1008 { &hf_abytes, add_word_param, PARAM_WORD },
1009 { NULL, NULL, PARAM_NONE }
1012 static const item_t lm_data_resp_netwkstauserlogoff_1[] = {
1013 { &hf_logoff_code, add_word_param, PARAM_WORD },
1014 { &hf_duration, add_reltime, PARAM_DWORD },
1015 { &hf_num_logons, add_nlogons, PARAM_WORD },
1016 { NULL, NULL, PARAM_NONE }
1019 static const item_list_t lm_data_resp_netwkstauserlogoff[] = {
1020 { 1, lm_data_resp_netwkstauserlogoff_1 },
1024 static const item_t lm_params_req_samoemchangepassword[] = {
1025 { &hf_user_name, add_string_param, PARAM_STRINGZ },
1026 { NULL, NULL, PARAM_NONE }
1029 static const item_t lm_data_req_samoemchangepassword[] = {
1030 { &hf_new_password, add_byte_param, PARAM_BYTES },
1031 { &hf_old_password, add_byte_param, PARAM_BYTES },
1032 { NULL, NULL, PARAM_NONE }
1035 #define LANMAN_NETSHAREENUM 0
1036 #define LANMAN_NETSHAREGETINFO 1
1037 #define LANMAN_NETSERVERGETINFO 13
1038 #define LANMAN_NETGROUPGETUSERS 52
1039 #define LANMAN_NETUSERGETINFO 56
1040 #define LANMAN_NETUSERGETGROUPS 59
1041 #define LANMAN_NETWKSTAGETINFO 63
1042 #define LANMAN_DOSPRINTQENUM 69
1043 #define LANMAN_DOSPRINTQGETINFO 70
1044 #define LANMAN_WPRINTQUEUEPAUSE 74
1045 #define LANMAN_WPRINTQUEUERESUME 75
1046 #define LANMAN_WPRINTJOBENUMERATE 76
1047 #define LANMAN_WPRINTJOBGETINFO 77
1048 #define LANMAN_RDOSPRINTJOBDEL 81
1049 #define LANMAN_RDOSPRINTJOBPAUSE 82
1050 #define LANMAN_RDOSPRINTJOBRESUME 83
1051 #define LANMAN_WPRINTDESTENUM 84
1052 #define LANMAN_WPRINTDESTGETINFO 85
1053 #define LANMAN_NETREMOTETOD 91
1054 #define LANMAN_WPRINTQUEUEPURGE 103
1055 #define LANMAN_NETSERVERENUM2 104
1056 #define LANMAN_WACCESSGETUSERPERMS 105
1057 #define LANMAN_SETUSERPASSWORD 115
1058 #define LANMAN_NETWKSTAUSERLOGON 132
1059 #define LANMAN_NETWKSTAUSERLOGOFF 133
1060 #define LANMAN_PRINTJOBINFO 147
1061 #define LANMAN_WPRINTDRIVERENUM 205
1062 #define LANMAN_WPRINTQPROCENUM 206
1063 #define LANMAN_WPRINTPORTENUM 207
1064 #define LANMAN_SAMOEMCHANGEPASSWORD 214
1066 static const struct lanman_desc lmd[] = {
1067 { LANMAN_NETSHAREENUM,
1068 lm_params_req_netshareenum,
1073 lm_params_resp_netshareenum,
1074 netshareenum_shares_list,
1076 netshareenum_share_entry,
1078 lm_data_resp_netshareenum,
1081 { LANMAN_NETSHAREGETINFO,
1082 lm_params_req_netsharegetinfo,
1087 lm_params_resp_netsharegetinfo,
1092 lm_data_resp_netsharegetinfo,
1095 { LANMAN_NETSERVERGETINFO,
1096 lm_params_req_netservergetinfo,
1101 lm_params_resp_netservergetinfo,
1109 { LANMAN_NETUSERGETINFO,
1110 lm_params_req_netusergetinfo,
1115 lm_params_resp_netusergetinfo,
1120 lm_data_resp_netusergetinfo,
1123 { LANMAN_NETREMOTETOD,
1134 lm_data_resp_netremotetod,
1137 { LANMAN_NETSERVERENUM2,
1138 lm_params_req_netserverenum2,
1143 lm_params_resp_netserverenum2,
1144 netserverenum2_servers_list,
1145 &ett_lanman_servers,
1146 netserverenum2_server_entry,
1151 { LANMAN_NETWKSTAGETINFO,
1152 lm_params_req_netwkstagetinfo,
1157 lm_params_resp_netwkstagetinfo,
1162 lm_data_resp_netwkstagetinfo,
1165 { LANMAN_NETWKSTAUSERLOGON,
1166 lm_params_req_netwkstauserlogon,
1171 lm_params_resp_netwkstauserlogon,
1176 lm_data_resp_netwkstauserlogon,
1179 { LANMAN_NETWKSTAUSERLOGOFF,
1180 lm_params_req_netwkstauserlogoff,
1185 lm_params_resp_netwkstauserlogoff,
1190 lm_data_resp_netwkstauserlogoff,
1193 { LANMAN_SAMOEMCHANGEPASSWORD,
1194 lm_params_req_samoemchangepassword,
1197 lm_data_req_samoemchangepassword,
1222 static const struct lanman_desc *
1223 find_lanman(int lanman_num)
1227 for (i = 0; lmd[i].lanman_num != -1; i++) {
1228 if (lmd[i].lanman_num == lanman_num)
1234 static const guchar *
1235 get_count(const guchar *desc, int *countp)
1240 if (!isdigit(*desc)) {
1241 *countp = 1; /* no count was supplied */
1245 while ((c = *desc) != '\0' && isdigit(c)) {
1246 count = (count * 10) + c - '0';
1250 *countp = count; /* XXX - what if it's 0? */
1255 dissect_request_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
1256 proto_tree *tree, const guchar *desc, const item_t *items,
1257 gboolean *has_data_p)
1265 *has_data_p = FALSE;
1266 while ((c = *desc++) != '\0') {
1271 * A 16-bit word value in the request.
1273 if (items->func == NULL) {
1275 * We've run out of items in the table;
1276 * fall back on the default.
1278 offset = add_word_param(tvb, offset, 0, pinfo,
1280 } else if (items->type != PARAM_WORD) {
1282 * Descriptor character is 'W', but this
1283 * isn't a word parameter.
1285 WParam = tvb_get_letohs(tvb, offset);
1286 proto_tree_add_text(tree, tvb, offset, 2,
1287 "%s: Value is %u (0x%04X), type is wrong (W)",
1288 (*items->hf_index == -1) ?
1290 proto_registrar_get_name(*items->hf_index),
1295 offset = (*items->func)(tvb, offset, 0, pinfo,
1296 tree, 0, *items->hf_index);
1303 * A 32-bit doubleword value in the request.
1305 if (items->func == NULL) {
1307 * We've run out of items in the table;
1308 * fall back on the default.
1310 offset = add_dword_param(tvb, offset, 0, pinfo,
1312 } else if (items->type != PARAM_DWORD) {
1314 * Descriptor character is 'D', but this
1315 * isn't a doubleword parameter.
1317 LParam = tvb_get_letohl(tvb, offset);
1318 proto_tree_add_text(tree, tvb, offset, 2,
1319 "%s: Value is %u (0x%08X), type is wrong (D)",
1320 (*items->hf_index == -1) ?
1321 "Doubleword Param" :
1322 proto_registrar_get_name(*items->hf_index),
1327 offset = (*items->func)(tvb, offset, 0, pinfo,
1328 tree, 0, *items->hf_index);
1335 * A byte or multi-byte value in the request.
1337 desc = get_count(desc, &count);
1338 if (items->func == NULL) {
1340 * We've run out of items in the table;
1341 * fall back on the default.
1343 offset = add_byte_param(tvb, offset, count,
1344 pinfo, tree, 0, -1);
1345 } else if (items->type != PARAM_BYTES) {
1347 * Descriptor character is 'b', but this
1348 * isn't a byte/bytes parameter.
1350 proto_tree_add_text(tree, tvb, offset, count,
1351 "%s: Value is %s, type is wrong (b)",
1352 (*items->hf_index == -1) ?
1354 proto_registrar_get_name(*items->hf_index),
1355 tvb_bytes_to_str(tvb, offset, count));
1359 offset = (*items->func)(tvb, offset, count,
1360 pinfo, tree, 0, *items->hf_index);
1369 if (items->func == NULL) {
1371 * We've run out of items in the table;
1372 * fall back on the default.
1374 add_null_pointer_param(tvb, offset, 0,
1375 pinfo, tree, 0, -1);
1378 * If "*items->hf_index" is -1, this is
1379 * a reserved must-be-null field; don't
1380 * clutter the protocol tree by putting
1383 if (*items->hf_index != -1) {
1384 add_null_pointer_param(tvb,
1385 offset, 0, pinfo, tree, 0,
1394 * A null-terminated ASCII string.
1396 if (items->func == NULL) {
1398 * We've run out of items in the table;
1399 * fall back on the default.
1401 offset = add_string_param(tvb, offset, 0,
1402 pinfo, tree, 0, -1);
1403 } else if (items->type != PARAM_STRINGZ) {
1405 * Descriptor character is 'z', but this
1406 * isn't a string parameter.
1408 string_len = tvb_strsize(tvb, offset);
1409 proto_tree_add_text(tree, tvb, offset, string_len,
1410 "%s: Value is %s, type is wrong (z)",
1411 (*items->hf_index == -1) ?
1413 proto_registrar_get_name(*items->hf_index),
1414 tvb_format_text(tvb, offset, string_len));
1415 offset += string_len;
1418 offset = (*items->func)(tvb, offset, 0,
1419 pinfo, tree, 0, *items->hf_index);
1426 * One or more pad bytes.
1428 desc = get_count(desc, &count);
1429 proto_tree_add_text(tree, tvb, offset, count,
1436 * 16-bit receive buffer length.
1438 proto_tree_add_item(tree, hf_recv_buf_len, tvb,
1445 * 32-bit send buffer offset.
1446 * This appears not to be sent over the wire.
1453 * 16-bit send buffer length.
1454 * This also appears not to be sent over the wire.
1466 dissect_response_parameters(tvbuff_t *tvb, int offset, packet_info *pinfo,
1467 proto_tree *tree, const guchar *desc, const item_t *items,
1468 gboolean *has_data_p, gboolean *has_ent_count_p, guint16 *ent_count_p)
1475 *has_data_p = FALSE;
1476 *has_ent_count_p = FALSE;
1477 while ((c = *desc++) != '\0') {
1482 * 32-bit receive buffer offset.
1489 * A byte or series of bytes is returned.
1491 desc = get_count(desc, &count);
1492 if (items->func == NULL) {
1494 * We've run out of items in the table;
1495 * fall back on the default.
1497 offset = add_byte_param(tvb, offset, count,
1498 pinfo, tree, 0, -1);
1499 } else if (items->type != PARAM_BYTES) {
1501 * Descriptor character is 'b', but this
1502 * isn't a byte/bytes parameter.
1504 proto_tree_add_text(tree, tvb, offset, count,
1505 "%s: Value is %s, type is wrong (g)",
1506 (*items->hf_index == -1) ?
1508 proto_registrar_get_name(*items->hf_index),
1509 tvb_bytes_to_str(tvb, offset, count));
1513 offset = (*items->func)(tvb, offset, count,
1514 pinfo, tree, 0, *items->hf_index);
1521 * A 16-bit word is received.
1523 if (items->func == NULL) {
1525 * We've run out of items in the table;
1526 * fall back on the default.
1528 offset = add_word_param(tvb, offset, 0, pinfo,
1530 } else if (items->type != PARAM_WORD) {
1532 * Descriptor character is 'h', but this
1533 * isn't a word parameter.
1535 WParam = tvb_get_letohs(tvb, offset);
1536 proto_tree_add_text(tree, tvb, offset, 2,
1537 "%s: Value is %u (0x%04X), type is wrong (W)",
1538 (*items->hf_index == -1) ?
1540 proto_registrar_get_name(*items->hf_index),
1545 offset = (*items->func)(tvb, offset, 0, pinfo,
1546 tree, 0, *items->hf_index);
1553 * A 32-bit doubleword is received.
1555 if (items->func == NULL) {
1557 * We've run out of items in the table;
1558 * fall back on the default.
1560 offset = add_dword_param(tvb, offset, 0, pinfo,
1562 } else if (items->type != PARAM_DWORD) {
1564 * Descriptor character is 'i', but this
1565 * isn't a doubleword parameter.
1567 LParam = tvb_get_letohl(tvb, offset);
1568 proto_tree_add_text(tree, tvb, offset, 2,
1569 "%s: Value is %u (0x%08X), type is wrong (i)",
1570 (*items->hf_index == -1) ?
1571 "Doubleword Param" :
1572 proto_registrar_get_name(*items->hf_index),
1577 offset = (*items->func)(tvb, offset, 0, pinfo,
1578 tree, 0, *items->hf_index);
1585 * A 16-bit entry count is returned.
1587 WParam = tvb_get_letohs(tvb, offset);
1588 proto_tree_add_uint(tree, hf_ecount, tvb, offset, 2,
1591 *has_ent_count_p = TRUE;
1592 *ent_count_p = WParam; /* Save this for later retrieval */
1603 dissect_transact_data(tvbuff_t *tvb, int offset, int convert,
1604 packet_info *pinfo, proto_tree *tree, const guchar *desc,
1605 const item_t *items, guint16 *aux_count_p)
1615 if (aux_count_p != NULL)
1618 while ((c = *desc++) != '\0') {
1623 * A 16-bit word value.
1624 * XXX - handle the count?
1626 desc = get_count(desc, &count);
1627 if (items->func == NULL) {
1629 * We've run out of items in the table;
1630 * fall back on the default.
1632 offset = add_word_param(tvb, offset, 0, pinfo,
1634 } else if (items->type != PARAM_WORD) {
1636 * Descriptor character is 'W', but this
1637 * isn't a word parameter.
1639 WParam = tvb_get_letohs(tvb, offset);
1640 proto_tree_add_text(tree, tvb, offset, 2,
1641 "%s: Value is %u (0x%04X), type is wrong (W)",
1642 (*items->hf_index == -1) ?
1644 proto_registrar_get_name(*items->hf_index),
1649 offset = (*items->func)(tvb, offset, 0, pinfo,
1650 tree, convert, *items->hf_index);
1657 * A 32-bit doubleword value.
1658 * XXX - handle the count?
1660 desc = get_count(desc, &count);
1661 if (items->func == NULL) {
1663 * We've run out of items in the table;
1664 * fall back on the default.
1666 offset = add_dword_param(tvb, offset, 0, pinfo,
1668 } else if (items->type != PARAM_DWORD) {
1670 * Descriptor character is 'D', but this
1671 * isn't a doubleword parameter.
1673 LParam = tvb_get_letohl(tvb, offset);
1674 proto_tree_add_text(tree, tvb, offset, 2,
1675 "%s: Value is %u (0x%08X), type is wrong (D)",
1676 (*items->hf_index == -1) ?
1677 "Doubleword Param" :
1678 proto_registrar_get_name(*items->hf_index),
1683 offset = (*items->func)(tvb, offset, 0, pinfo,
1684 tree, convert, *items->hf_index);
1691 * A byte or multi-byte value.
1693 desc = get_count(desc, &count);
1694 if (items->func == NULL) {
1696 * We've run out of items in the table;
1697 * fall back on the default.
1699 offset = add_byte_param(tvb, offset, count,
1700 pinfo, tree, convert, -1);
1701 } else if (items->type != PARAM_BYTES) {
1703 * Descriptor character is 'B', but this
1704 * isn't a byte/bytes parameter.
1706 proto_tree_add_text(tree, tvb, offset, count,
1707 "%s: Value is %s, type is wrong (B)",
1708 (*items->hf_index == -1) ?
1710 proto_registrar_get_name(*items->hf_index),
1711 tvb_bytes_to_str(tvb, offset, count));
1715 offset = (*items->func)(tvb, offset, count,
1716 pinfo, tree, convert, *items->hf_index);
1725 if (items->func == NULL) {
1727 * We've run out of items in the table;
1728 * fall back on the default.
1730 add_null_pointer_param(tvb, offset, 0,
1731 pinfo, tree, convert, -1);
1734 * If "*items->hf_index" is -1, this is
1735 * a reserved must-be-null field; don't
1736 * clutter the protocol tree by putting
1739 if (*items->hf_index != -1) {
1740 add_null_pointer_param(tvb,
1741 offset, 0, pinfo, tree, convert,
1750 * A pointer to a null-terminated ASCII string.
1752 if (items->func == NULL) {
1754 * We've run out of items in the table;
1755 * fall back on the default.
1757 offset = add_pointer_param(tvb, offset, 0,
1758 pinfo, tree, convert, -1);
1759 } else if (items->type != PARAM_STRINGZ) {
1761 * Descriptor character is 'z', but this
1762 * isn't a string parameter.
1764 string = get_pointer_value(tvb, offset,
1765 convert, &cptr, &string_len);
1767 proto_tree_add_text(tree, tvb, cptr, string_len,
1768 "%s: Value is %s, type is wrong (z)",
1769 (*items->hf_index == -1) ?
1771 proto_registrar_get_name(*items->hf_index),
1775 offset = (*items->func)(tvb, offset, 0,
1776 pinfo, tree, convert, *items->hf_index);
1783 * 16-bit auxiliary data structure count.
1786 WParam = tvb_get_letohs(tvb, offset);
1787 proto_tree_add_text(tree, tvb, offset, 2,
1789 "Auxiliary data structure count",
1792 if (aux_count_p != NULL)
1793 *aux_count_p = WParam; /* Save this for later retrieval */
1803 static const value_string commands[] = {
1804 {LANMAN_NETSHAREENUM, "NetShareEnum"},
1805 {LANMAN_NETSHAREGETINFO, "NetShareGetInfo"},
1806 {LANMAN_NETSERVERGETINFO, "NetServerGetInfo"},
1807 {LANMAN_NETGROUPGETUSERS, "NetGroupGetUsers"},
1808 {LANMAN_NETUSERGETINFO, "NetUserGetInfo"},
1809 {LANMAN_NETUSERGETGROUPS, "NetUserGetGroups"},
1810 {LANMAN_NETWKSTAGETINFO, "NetWkstaGetInfo"},
1811 {LANMAN_DOSPRINTQENUM, "DOSPrintQEnum"},
1812 {LANMAN_DOSPRINTQGETINFO, "DOSPrintQGetInfo"},
1813 {LANMAN_WPRINTQUEUEPAUSE, "WPrintQueuePause"},
1814 {LANMAN_WPRINTQUEUERESUME, "WPrintQueueResume"},
1815 {LANMAN_WPRINTJOBENUMERATE, "WPrintJobEnumerate"},
1816 {LANMAN_WPRINTJOBGETINFO, "WPrintJobGetInfo"},
1817 {LANMAN_RDOSPRINTJOBDEL, "RDOSPrintJobDel"},
1818 {LANMAN_RDOSPRINTJOBPAUSE, "RDOSPrintJobPause"},
1819 {LANMAN_RDOSPRINTJOBRESUME, "RDOSPrintJobResume"},
1820 {LANMAN_WPRINTDESTENUM, "WPrintDestEnum"},
1821 {LANMAN_WPRINTDESTGETINFO, "WPrintDestGetInfo"},
1822 {LANMAN_NETREMOTETOD, "NetRemoteTOD"},
1823 {LANMAN_WPRINTQUEUEPURGE, "WPrintQueuePurge"},
1824 {LANMAN_NETSERVERENUM2, "NetServerEnum2"},
1825 {LANMAN_WACCESSGETUSERPERMS, "WAccessGetUserPerms"},
1826 {LANMAN_SETUSERPASSWORD, "SetUserPassword"},
1827 {LANMAN_NETWKSTAUSERLOGON, "NetWkstaUserLogon"},
1828 {LANMAN_NETWKSTAUSERLOGOFF, "NetWkstaUserLogoff"},
1829 {LANMAN_PRINTJOBINFO, "PrintJobInfo"},
1830 {LANMAN_WPRINTDRIVERENUM, "WPrintDriverEnum"},
1831 {LANMAN_WPRINTQPROCENUM, "WPrintQProcEnum"},
1832 {LANMAN_WPRINTPORTENUM, "WPrintPortEnum"},
1833 {LANMAN_SAMOEMCHANGEPASSWORD, "SamOEMChangePassword"},
1838 dissect_response_data(tvbuff_t *tvb, packet_info *pinfo, int convert,
1839 proto_tree *tree, struct smb_info *smb_info,
1840 const struct lanman_desc *lanman, gboolean has_ent_count,
1843 smb_transact_info_t *trp = smb_info->sip->extra_info;
1844 const item_list_t *resp_data_list;
1845 int offset, start_offset;
1846 const item_t *resp_data;
1847 proto_item *data_item;
1848 proto_tree *data_tree;
1849 proto_item *entry_item;
1850 proto_tree *entry_tree;
1855 * Find the item table for the matching request's detail level.
1857 for (resp_data_list = lanman->resp_data_list;
1858 resp_data_list->level != -1; resp_data_list++) {
1859 if (resp_data_list->level == trp->info_level)
1862 resp_data = resp_data_list->item_list;
1865 if (lanman->resp_data_item != NULL) {
1867 * Create a protocol tree item for the data.
1869 data_item = (*lanman->resp_data_item)(tvb,
1870 pinfo, tree, offset);
1871 data_tree = proto_item_add_subtree(data_item,
1872 *lanman->ett_resp_data);
1875 * Just leave it at the top level.
1881 if (trp->data_descrip == NULL) {
1883 * This could happen if we only dissected
1884 * part of the request to which this is a
1885 * reply, e.g. if the request was split
1886 * across TCP segments and we weren't doing
1887 * TCP desegmentation, or if we had a snapshot
1888 * length that was too short.
1890 * We can't dissect the data; just show it
1893 proto_tree_add_text(tree, tvb, offset, -1,
1894 "Data (no descriptor available)");
1895 offset += tvb_length_remaining(tvb, offset);
1898 * If we have an entry count, show all the entries,
1899 * with each one having a protocol tree item.
1901 * Otherwise, we just show one returned item, with
1902 * no protocol tree item.
1906 for (i = 0; i < ent_count; i++) {
1907 start_offset = offset;
1908 if (has_ent_count) {
1910 * Create a protocol tree item for the
1914 (*lanman->resp_data_element_item)
1915 (tvb, pinfo, data_tree, offset);
1916 entry_tree = proto_item_add_subtree(
1918 *lanman->ett_resp_data_element_item);
1921 * Just leave it at the current
1925 entry_tree = data_tree;
1928 offset = dissect_transact_data(tvb, offset,
1929 convert, pinfo, entry_tree,
1930 trp->data_descrip, resp_data, &aux_count);
1932 /* auxiliary data */
1933 if (trp->aux_data_descrip != NULL) {
1934 for (j = 0; j < aux_count; j++) {
1935 offset = dissect_transact_data(
1936 tvb, offset, convert,
1939 lanman->resp_aux_data, NULL);
1943 if (entry_item != NULL) {
1945 * Set the length of the protocol tree
1946 * item for the entry.
1948 proto_item_set_len(entry_item,
1949 offset - start_offset);
1954 if (data_item != NULL) {
1956 * Set the length of the protocol tree item
1959 proto_item_set_len(data_item, offset);
1964 dissect_pipe_lanman(tvbuff_t *pd_tvb, tvbuff_t *p_tvb, tvbuff_t *d_tvb,
1965 packet_info *pinfo, proto_tree *parent_tree)
1967 smb_info_t *smb_info = pinfo->private_data;
1968 smb_transact_info_t *trp = smb_info->sip->extra_info;
1969 int offset = 0, start_offset;
1973 const struct lanman_desc *lanman;
1974 proto_item *item = NULL;
1975 proto_tree *tree = NULL;
1976 guint descriptor_len;
1977 const gchar *param_descrip, *data_descrip, *aux_data_descrip = NULL;
1979 gboolean has_ent_count;
1980 guint16 ent_count, aux_count;
1982 proto_item *data_item;
1983 proto_tree *data_tree;
1985 if (!proto_is_protocol_enabled(proto_smb_lanman))
1987 if (smb_info->request && p_tvb == NULL) {
1989 * Requests must have parameters.
1993 pinfo->current_proto = "LANMAN";
1995 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
1996 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LANMAN");
2000 item = proto_tree_add_item(parent_tree, proto_smb_lanman,
2001 pd_tvb, 0, -1, FALSE);
2002 tree = proto_item_add_subtree(item, ett_lanman);
2005 if (smb_info->request) { /* this is a request */
2007 cmd = tvb_get_letohs(p_tvb, offset);
2008 if (check_col(pinfo->cinfo, COL_INFO)) {
2009 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Request", val_to_str(cmd, commands, "Unknown Command:0x%02x"));
2011 proto_tree_add_uint(tree, hf_function_code, p_tvb, offset, 2,
2016 * If we haven't already done so, save the function code in
2017 * the structure we were handed, so that it's available to
2018 * the code parsing the reply, and initialize the detail
2019 * level to -1, meaning "unknown".
2021 if (!pinfo->fd->flags.visited) {
2022 trp->lanman_cmd = cmd;
2023 trp->info_level = -1;
2024 trp->param_descrip=NULL;
2025 trp->data_descrip=NULL;
2026 trp->aux_data_descrip=NULL;
2029 /* parameter descriptor */
2030 descriptor_len = tvb_strsize(p_tvb, offset);
2031 proto_tree_add_item(tree, hf_param_desc, p_tvb, offset,
2032 descriptor_len, TRUE);
2033 param_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2034 if (!pinfo->fd->flags.visited) {
2036 * Save the parameter descriptor for future use.
2038 g_assert(trp->param_descrip == NULL);
2039 trp->param_descrip = g_strdup(param_descrip);
2041 offset += descriptor_len;
2043 /* return descriptor */
2044 descriptor_len = tvb_strsize(p_tvb, offset);
2045 proto_tree_add_item(tree, hf_return_desc, p_tvb, offset,
2046 descriptor_len, TRUE);
2047 data_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2048 if (!pinfo->fd->flags.visited) {
2050 * Save the return descriptor for future use.
2052 g_assert(trp->data_descrip == NULL);
2053 trp->data_descrip = g_strdup(data_descrip);
2055 offset += descriptor_len;
2057 lanman = find_lanman(cmd);
2059 /* request parameters */
2060 start_offset = offset;
2061 offset = dissect_request_parameters(p_tvb, offset, pinfo, tree,
2062 param_descrip, lanman->req, &has_data);
2064 /* auxiliary data descriptor */
2065 if (tvb_reported_length_remaining(p_tvb, offset) > 0){
2067 * There are more parameters left, so the next
2068 * item is the auxiliary data descriptor.
2070 descriptor_len = tvb_strsize(p_tvb, offset);
2071 proto_tree_add_item(tree, hf_return_desc, p_tvb, offset,
2072 descriptor_len, TRUE);
2073 aux_data_descrip = tvb_get_ptr(p_tvb, offset, descriptor_len);
2074 if (!pinfo->fd->flags.visited) {
2076 * Save the auxiliary data descriptor for
2079 g_assert(trp->aux_data_descrip == NULL);
2080 trp->aux_data_descrip =
2081 g_strdup(aux_data_descrip);
2083 offset += descriptor_len;
2086 /* reset offset, we now start dissecting the data area */
2088 if (has_data && d_tvb && tvb_reported_length(d_tvb) != 0) {
2090 * There's a send buffer item in the descriptor
2091 * string, and the data count in the transaction
2092 * is non-zero, so there's data to dissect.
2095 if (lanman->req_data_item != NULL) {
2097 * Create a protocol tree item for the data.
2099 data_item = (*lanman->req_data_item)(d_tvb,
2100 pinfo, tree, offset);
2101 data_tree = proto_item_add_subtree(data_item,
2102 *lanman->ett_req_data);
2105 * Just leave it at the top level.
2112 offset = dissect_transact_data(d_tvb, offset, -1,
2113 pinfo, data_tree, data_descrip, lanman->req_data,
2114 &aux_count); /* XXX - what about strings? */
2116 /* auxiliary data */
2117 if (aux_data_descrip != NULL) {
2118 for (i = 0; i < aux_count; i++) {
2119 offset = dissect_transact_data(d_tvb,
2120 offset, -1, pinfo, data_tree,
2122 lanman->req_aux_data, NULL);
2126 if (data_item != NULL) {
2128 * Set the length of the protocol tree item
2131 proto_item_set_len(data_item, offset);
2136 * This is a response.
2137 * Have we seen the request to which it's a response?
2140 return FALSE; /* no - can't dissect it */
2142 /* ok we have seen this one before */
2144 /* if it looks like an interim response, update COL_INFO and return */
2145 if( ( (p_tvb==NULL) || (tvb_reported_length(p_tvb)==0) )
2146 && ( (d_tvb==NULL) || (tvb_reported_length(d_tvb)==0) ) ){
2148 if (check_col(pinfo->cinfo, COL_INFO)) {
2149 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Interim Response",
2150 val_to_str(trp->lanman_cmd, commands, "Unknown Command (0x%02x)"));
2152 proto_tree_add_uint(tree, hf_function_code, p_tvb, 0, 0, trp->lanman_cmd);
2157 if (check_col(pinfo->cinfo, COL_INFO)) {
2158 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Response",
2159 val_to_str(trp->lanman_cmd, commands, "Unknown Command (0x%02x)"));
2161 proto_tree_add_uint(tree, hf_function_code, p_tvb, 0, 0,
2164 lanman = find_lanman(trp->lanman_cmd);
2166 /* response parameters */
2169 status = tvb_get_letohs(p_tvb, offset);
2170 proto_tree_add_uint(tree, hf_status, p_tvb, offset, 2, status);
2174 convert = tvb_get_letohs(p_tvb, offset);
2175 proto_tree_add_uint(tree, hf_convert, p_tvb, offset, 2, convert);
2178 /* rest of the parameters */
2179 offset = dissect_response_parameters(p_tvb, offset, pinfo, tree,
2180 trp->param_descrip, lanman->resp, &has_data,
2181 &has_ent_count, &ent_count);
2184 /* reset offset, we now start dissecting the data area */
2187 if (has_data && d_tvb && tvb_reported_length(d_tvb) > 0) {
2189 * There's a receive buffer item in the descriptor
2190 * string, and the data count in the transaction
2191 * is non-zero, so there's data to dissect.
2193 dissect_response_data(d_tvb, pinfo, convert, tree,
2194 smb_info, lanman, has_ent_count, ent_count);
2202 proto_register_pipe_lanman(void)
2204 static hf_register_info hf[] = {
2205 { &hf_function_code,
2206 { "Function Code", "lanman.function_code", FT_UINT16, BASE_DEC,
2207 VALS(commands), 0, "LANMAN Function Code/Command", HFILL }},
2210 { "Parameter Descriptor", "lanman.param_desc", FT_STRING, BASE_NONE,
2211 NULL, 0, "LANMAN Parameter Descriptor", HFILL }},
2214 { "Return Descriptor", "lanman.ret_desc", FT_STRING, BASE_NONE,
2215 NULL, 0, "LANMAN Return Descriptor", HFILL }},
2217 { &hf_aux_data_desc,
2218 { "Auxiliary Data Descriptor", "lanman.aux_data_desc", FT_STRING, BASE_NONE,
2219 NULL, 0, "LANMAN Auxiliary Data Descriptor", HFILL }},
2222 { "Detail Level", "lanman.level", FT_UINT16, BASE_DEC,
2223 NULL, 0, "LANMAN Detail Level", HFILL }},
2226 { "Receive Buffer Length", "lanman.recv_buf_len", FT_UINT16, BASE_DEC,
2227 NULL, 0, "LANMAN Receive Buffer Length", HFILL }},
2230 { "Send Buffer Length", "lanman.send_buf_len", FT_UINT16, BASE_DEC,
2231 NULL, 0, "LANMAN Send Buffer Length", HFILL }},
2233 { &hf_continuation_from,
2234 { "Continuation from message in frame", "lanman.continuation_from", FT_UINT32, BASE_DEC,
2235 NULL, 0, "This is a LANMAN continuation from the message in the frame in question", HFILL }},
2238 { "Status", "lanman.status", FT_UINT16, BASE_DEC,
2239 VALS(status_vals), 0, "LANMAN Return status", HFILL }},
2242 { "Convert", "lanman.convert", FT_UINT16, BASE_DEC,
2243 NULL, 0, "LANMAN Convert", HFILL }},
2246 { "Entry Count", "lanman.entry_count", FT_UINT16, BASE_DEC,
2247 NULL, 0, "LANMAN Number of Entries", HFILL }},
2250 { "Available Entries", "lanman.available_count", FT_UINT16, BASE_DEC,
2251 NULL, 0, "LANMAN Number of Available Entries", HFILL }},
2254 { "Share Name", "lanman.share.name", FT_STRING, BASE_NONE,
2255 NULL, 0, "LANMAN Name of Share", HFILL }},
2258 { "Share Type", "lanman.share.type", FT_UINT16, BASE_DEC,
2259 VALS(share_type_vals), 0, "LANMAN Type of Share", HFILL }},
2261 { &hf_share_comment,
2262 { "Share Comment", "lanman.share.comment", FT_STRING, BASE_NONE,
2263 NULL, 0, "LANMAN Share Comment", HFILL }},
2265 { &hf_share_permissions,
2266 { "Share Permissions", "lanman.share.permissions", FT_UINT16, BASE_DEC,
2267 NULL, 0, "LANMAN Permissions on share", HFILL }},
2269 { &hf_share_max_uses,
2270 { "Share Max Uses", "lanman.share.max_uses", FT_UINT16, BASE_DEC,
2271 NULL, 0, "LANMAN Max connections allowed to share", HFILL }},
2273 { &hf_share_current_uses,
2274 { "Share Current Uses", "lanman.share.current_uses", FT_UINT16, BASE_DEC,
2275 NULL, 0, "LANMAN Current connections to share", HFILL }},
2278 { "Share Path", "lanman.share.path", FT_STRING, BASE_NONE,
2279 NULL, 0, "LANMAN Share Path", HFILL }},
2281 { &hf_share_password,
2282 { "Share Password", "lanman.share.password", FT_STRING, BASE_NONE,
2283 NULL, 0, "LANMAN Share Password", HFILL }},
2286 { "Server Name", "lanman.server.name", FT_STRING, BASE_NONE,
2287 NULL, 0, "LANMAN Name of Server", HFILL }},
2290 { "Major Version", "lanman.server.major", FT_UINT8, BASE_DEC,
2291 NULL, 0, "LANMAN Server Major Version", HFILL }},
2294 { "Minor Version", "lanman.server.minor", FT_UINT8, BASE_DEC,
2295 NULL, 0, "LANMAN Server Minor Version", HFILL }},
2297 { &hf_server_comment,
2298 { "Server Comment", "lanman.server.comment", FT_STRING, BASE_NONE,
2299 NULL, 0, "LANMAN Server Comment", HFILL }},
2302 { "Available Bytes", "lanman.available_bytes", FT_UINT16, BASE_DEC,
2303 NULL, 0, "LANMAN Number of Available Bytes", HFILL }},
2306 { "Current Date/Time", "lanman.current_time", FT_ABSOLUTE_TIME, BASE_NONE,
2307 NULL, 0, "LANMAN Current date and time, in seconds since 00:00:00, January 1, 1970", HFILL }},
2310 { "Milliseconds", "lanman.msecs", FT_UINT32, BASE_DEC,
2311 NULL, 0, "LANMAN Milliseconds since arbitrary time in the past (typically boot time)", HFILL }},
2314 { "Hour", "lanman.hour", FT_UINT8, BASE_DEC,
2315 NULL, 0, "LANMAN Current hour", HFILL }},
2318 { "Minute", "lanman.minute", FT_UINT8, BASE_DEC,
2319 NULL, 0, "LANMAN Current minute", HFILL }},
2322 { "Second", "lanman.second", FT_UINT8, BASE_DEC,
2323 NULL, 0, "LANMAN Current second", HFILL }},
2326 { "Hundredths of a second", "lanman.hundredths", FT_UINT8, BASE_DEC,
2327 NULL, 0, "LANMAN Current hundredths of a second", HFILL }},
2330 { "Time Zone Offset", "lanman.tzoffset", FT_INT16, BASE_DEC,
2331 NULL, 0, "LANMAN Offset of time zone from GMT, in minutes", HFILL }},
2334 { "Time Interval", "lanman.timeinterval", FT_UINT16, BASE_DEC,
2335 NULL, 0, "LANMAN .0001 second units per clock tick", HFILL }},
2338 { "Day", "lanman.day", FT_UINT8, BASE_DEC,
2339 NULL, 0, "LANMAN Current day", HFILL }},
2342 { "Month", "lanman.month", FT_UINT8, BASE_DEC,
2343 NULL, 0, "LANMAN Current month", HFILL }},
2346 { "Year", "lanman.year", FT_UINT16, BASE_DEC,
2347 NULL, 0, "LANMAN Current year", HFILL }},
2350 { "Weekday", "lanman.weekday", FT_UINT8, BASE_DEC,
2351 VALS(weekday_vals), 0, "LANMAN Current day of the week", HFILL }},
2353 { &hf_enumeration_domain,
2354 { "Enumeration Domain", "lanman.enumeration_domain", FT_STRING, BASE_NONE,
2355 NULL, 0, "LANMAN Domain in which to enumerate servers", HFILL }},
2357 { &hf_computer_name,
2358 { "Computer Name", "lanman.computer_name", FT_STRING, BASE_NONE,
2359 NULL, 0, "LANMAN Computer Name", HFILL }},
2362 { "User Name", "lanman.user_name", FT_STRING, BASE_NONE,
2363 NULL, 0, "LANMAN User Name", HFILL }},
2365 { &hf_workstation_domain,
2366 { "Workstation Domain", "lanman.workstation_domain", FT_STRING, BASE_NONE,
2367 NULL, 0, "LANMAN Workstation Domain", HFILL }},
2369 { &hf_workstation_major,
2370 { "Workstation Major Version", "lanman.workstation_major", FT_UINT8, BASE_DEC,
2371 NULL, 0, "LANMAN Workstation Major Version", HFILL }},
2373 { &hf_workstation_minor,
2374 { "Workstation Minor Version", "lanman.workstation_minor", FT_UINT8, BASE_DEC,
2375 NULL, 0, "LANMAN Workstation Minor Version", HFILL }},
2378 { "Logon Domain", "lanman.logon_domain", FT_STRING, BASE_NONE,
2379 NULL, 0, "LANMAN Logon Domain", HFILL }},
2381 { &hf_other_domains,
2382 { "Other Domains", "lanman.other_domains", FT_STRING, BASE_NONE,
2383 NULL, 0, "LANMAN Other Domains", HFILL }},
2386 { "Password", "lanman.password", FT_STRING, BASE_NONE,
2387 NULL, 0, "LANMAN Password", HFILL }},
2389 { &hf_workstation_name,
2390 { "Workstation Name", "lanman.workstation_name", FT_STRING, BASE_NONE,
2391 NULL, 0, "LANMAN Workstation Name", HFILL }},
2394 { "Length of UStruct", "lanman.ustruct_size", FT_UINT16, BASE_DEC,
2395 NULL, 0, "LANMAN UStruct Length", HFILL }},
2398 { "Logon Code", "lanman.logon_code", FT_UINT16, BASE_DEC,
2399 VALS(status_vals), 0, "LANMAN Logon Code", HFILL }},
2401 { &hf_privilege_level,
2402 { "Privilege Level", "lanman.privilege_level", FT_UINT16, BASE_DEC,
2403 VALS(privilege_vals), 0, "LANMAN Privilege Level", HFILL }},
2405 { &hf_operator_privileges,
2406 { "Operator Privileges", "lanman.operator_privileges", FT_UINT32, BASE_DEC,
2407 VALS(op_privilege_vals), 0, "LANMAN Operator Privileges", HFILL }},
2410 { "Number of Logons", "lanman.num_logons", FT_UINT16, BASE_DEC,
2411 NULL, 0, "LANMAN Number of Logons", HFILL }},
2414 { "Bad Password Count", "lanman.bad_pw_count", FT_UINT16, BASE_DEC,
2415 NULL, 0, "LANMAN Number of incorrect passwords entered since last successful login", HFILL }},
2418 { "Last Logon Date/Time", "lanman.last_logon", FT_ABSOLUTE_TIME, BASE_NONE,
2419 NULL, 0, "LANMAN Date and time of last logon", HFILL }},
2422 { "Last Logoff Date/Time", "lanman.last_logoff", FT_ABSOLUTE_TIME, BASE_NONE,
2423 NULL, 0, "LANMAN Date and time of last logoff", HFILL }},
2426 { "Logoff Date/Time", "lanman.logoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
2427 NULL, 0, "LANMAN Date and time when user should log off", HFILL }},
2430 { "Kickoff Date/Time", "lanman.kickoff_time", FT_ABSOLUTE_TIME, BASE_NONE,
2431 NULL, 0, "LANMAN Date and time when user will be logged off", HFILL }},
2434 { "Password Age", "lanman.password_age", FT_RELATIVE_TIME, BASE_NONE,
2435 NULL, 0, "LANMAN Time since user last changed his/her password", HFILL }},
2437 { &hf_password_can_change,
2438 { "Password Can Change", "lanman.password_can_change", FT_ABSOLUTE_TIME, BASE_NONE,
2439 NULL, 0, "LANMAN Date and time when user can change their password", HFILL }},
2441 { &hf_password_must_change,
2442 { "Password Must Change", "lanman.password_must_change", FT_ABSOLUTE_TIME, BASE_NONE,
2443 NULL, 0, "LANMAN Date and time when user must change their password", HFILL }},
2446 { "Script Path", "lanman.script_path", FT_STRING, BASE_NONE,
2447 NULL, 0, "LANMAN Pathname of user's logon script", HFILL }},
2450 { "Logoff Code", "lanman.logoff_code", FT_UINT16, BASE_DEC,
2451 VALS(status_vals), 0, "LANMAN Logoff Code", HFILL }},
2454 { "Duration of Session", "lanman.duration", FT_RELATIVE_TIME, BASE_NONE,
2455 NULL, 0, "LANMAN Number of seconds the user was logged on", HFILL }},
2458 { "User Comment", "lanman.user_comment", FT_STRING, BASE_NONE,
2459 NULL, 0, "LANMAN User Comment", HFILL }},
2462 { "Full Name", "lanman.full_name", FT_STRING, BASE_NONE,
2463 NULL, 0, "LANMAN Full Name", HFILL }},
2466 { "Home Directory", "lanman.homedir", FT_STRING, BASE_NONE,
2467 NULL, 0, "LANMAN Home Directory", HFILL }},
2470 { "Parameters", "lanman.parameters", FT_STRING, BASE_NONE,
2471 NULL, 0, "LANMAN Parameters", HFILL }},
2474 { "Logon Server", "lanman.logon_server", FT_STRING, BASE_NONE,
2475 NULL, 0, "LANMAN Logon Server", HFILL }},
2477 /* XXX - we should have a value_string table for this */
2479 { "Country Code", "lanman.country_code", FT_UINT16, BASE_DEC,
2480 NULL, 0, "LANMAN Country Code", HFILL }},
2483 { "Workstations", "lanman.workstations", FT_STRING, BASE_NONE,
2484 NULL, 0, "LANMAN Workstations", HFILL }},
2487 { "Max Storage", "lanman.max_storage", FT_UINT32, BASE_DEC,
2488 NULL, 0, "LANMAN Max Storage", HFILL }},
2490 { &hf_units_per_week,
2491 { "Units Per Week", "lanman.units_per_week", FT_UINT16, BASE_DEC,
2492 NULL, 0, "LANMAN Units Per Week", HFILL }},
2495 { "Logon Hours", "lanman.logon_hours", FT_BYTES, BASE_NONE,
2496 NULL, 0, "LANMAN Logon Hours", HFILL }},
2498 /* XXX - we should have a value_string table for this */
2500 { "Code Page", "lanman.code_page", FT_UINT16, BASE_DEC,
2501 NULL, 0, "LANMAN Code Page", HFILL }},
2504 { "New Password", "lanman.new_password", FT_BYTES, BASE_HEX,
2505 NULL, 0, "LANMAN New Password (encrypted)", HFILL }},
2508 { "Old Password", "lanman.old_password", FT_BYTES, BASE_HEX,
2509 NULL, 0, "LANMAN Old Password (encrypted)", HFILL }},
2512 { "Reserved", "lanman.reserved", FT_UINT32, BASE_HEX,
2513 NULL, 0, "LANMAN Reserved", HFILL }},
2516 static gint *ett[] = {
2518 &ett_lanman_servers,
2524 proto_smb_lanman = proto_register_protocol(
2525 "Microsoft Windows Lanman Remote API Protocol", "LANMAN", "lanman");
2526 proto_register_field_array(proto_smb_lanman, hf, array_length(hf));
2527 proto_register_subtree_array(ett, array_length(ett));
2530 static heur_dissector_list_t smb_transact_heur_subdissector_list;
2533 dissect_pipe_dcerpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree,
2534 proto_tree *tree, guint32 fid)
2536 dcerpc_private_info dcerpc_priv;
2537 smb_info_t *smb_priv = (smb_info_t *)pinfo->private_data;
2539 gboolean save_fragmented;
2541 dcerpc_priv.transport_type = DCERPC_TRANSPORT_SMB;
2542 dcerpc_priv.data.smb.fid = fid;
2544 pinfo->private_data = &dcerpc_priv;
2546 /* offer desegmentation service to DCERPC */
2547 pinfo->can_desegment=0;
2548 pinfo->desegment_offset = 0;
2549 pinfo->desegment_len = 0;
2550 if(smb_dcerpc_reassembly){
2551 pinfo->can_desegment=2;
2554 save_fragmented = pinfo->fragmented;
2556 /* see if this packet is already desegmented */
2557 if(smb_dcerpc_reassembly && pinfo->fd->flags.visited){
2558 fragment_data *fd_head;
2561 fd_head=fragment_get(pinfo, pinfo->fd->num ,
2562 dcerpc_fragment_table);
2563 if(fd_head && fd_head->flags&FD_DEFRAGMENTED){
2568 new_tvb = tvb_new_real_data(fd_head->data,
2569 fd_head->datalen, fd_head->datalen,
2571 tvb_set_child_real_data_tvbuff(d_tvb, new_tvb);
2572 pinfo->fd->data_src=g_slist_append(pinfo->fd->data_src,
2574 pinfo->fragmented=FALSE;
2578 /* list what segments we have */
2579 it = proto_tree_add_text(tree, d_tvb, 0, 0, "Fragments");
2580 tr = proto_item_add_subtree(it, ett_smb_pipe_fragments);
2581 for(fd=fd_head->next;fd;fd=fd->next){
2582 proto_tree_add_text(tr, d_tvb, 0, 0, "Frame:%u Data:%u-%u",
2583 fd->frame, fd->offset, fd->offset+fd->len-1);
2588 result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb,
2589 pinfo, parent_tree);
2590 pinfo->private_data = smb_priv;
2592 /* check if dissector wanted us to desegment the data */
2593 if(smb_dcerpc_reassembly && !pinfo->fd->flags.visited && pinfo->desegment_len){
2594 fragment_add(d_tvb, 0, pinfo, pinfo->fd->num,
2595 dcerpc_fragment_table,
2596 0, tvb_length(d_tvb), TRUE);
2597 fragment_set_tot_len(pinfo, pinfo->fd->num,
2598 dcerpc_fragment_table,
2599 pinfo->desegment_len+tvb_length(d_tvb));
2600 /* since the other fragments are in normal ReadAndX and WriteAndX calls
2601 we must make sure we can map FID values to this defragmentation
2603 /* first remove any old mappings */
2604 if(g_hash_table_lookup(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid)){
2605 g_hash_table_remove(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid);
2607 g_hash_table_insert(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid,
2608 (void *)pinfo->fd->num);
2610 /* clear out the variables */
2611 pinfo->can_desegment=0;
2612 pinfo->desegment_offset = 0;
2613 pinfo->desegment_len = 0;
2616 call_dissector(data_handle, d_tvb, pinfo, parent_tree);
2618 pinfo->fragmented = save_fragmented;
2623 proto_register_pipe_dcerpc(void)
2625 register_heur_dissector_list("smb_transact", &smb_transact_heur_subdissector_list);
2628 #define CALL_NAMED_PIPE 0x54
2629 #define WAIT_NAMED_PIPE 0x53
2630 #define PEEK_NAMED_PIPE 0x23
2631 #define Q_NM_P_HAND_STATE 0x21
2632 #define SET_NM_P_HAND_STATE 0x01
2633 #define Q_NM_PIPE_INFO 0x22
2634 #define TRANSACT_NM_PIPE 0x26
2635 #define RAW_READ_NM_PIPE 0x11
2636 #define RAW_WRITE_NM_PIPE 0x31
2638 static const value_string functions[] = {
2639 {CALL_NAMED_PIPE, "CallNamedPipe"},
2640 {WAIT_NAMED_PIPE, "WaitNamedPipe"},
2641 {PEEK_NAMED_PIPE, "PeekNamedPipe"},
2642 {Q_NM_P_HAND_STATE, "QNmPHandState"},
2643 {SET_NM_P_HAND_STATE, "SetNmPHandState"},
2644 {Q_NM_PIPE_INFO, "QNmPipeInfo"},
2645 {TRANSACT_NM_PIPE, "TransactNmPipe"},
2646 {RAW_READ_NM_PIPE, "RawReadNmPipe"},
2647 {RAW_WRITE_NM_PIPE, "RawWriteNmPipe"},
2651 static const value_string pipe_status[] = {
2652 {1, "Disconnected by server"},
2654 {3, "Connection to server is OK"},
2655 {4, "Server end of pipe is closed"},
2659 #define PIPE_LANMAN 1
2660 #define PIPE_DCERPC 2
2662 /* decode the SMB pipe protocol
2664 pipe is the name of the pipe, e.g. LANMAN
2665 smb_info->trans_subcmd is set to the symbolic constant matching the mailslot name
2668 smb_info->trans_subcmd gives us which pipe this response is for
2671 dissect_pipe_smb(tvbuff_t *sp_tvb, tvbuff_t *s_tvb, tvbuff_t *pd_tvb,
2672 tvbuff_t *p_tvb, tvbuff_t *d_tvb, const char *pipe,
2673 packet_info *pinfo, proto_tree *tree)
2675 smb_info_t *smb_info;
2676 smb_transact_info_t *tri;
2678 proto_item *pipe_item = NULL;
2679 proto_tree *pipe_tree = NULL;
2686 if (!proto_is_protocol_enabled(proto_smb_pipe))
2688 pinfo->current_proto = "SMB Pipe";
2690 smb_info = pinfo->private_data;
2695 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
2696 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMB Pipe");
2698 if (check_col(pinfo->cinfo, COL_INFO)) {
2699 col_set_str(pinfo->cinfo, COL_INFO,
2700 smb_info->request ? "Request" : "Response");
2703 if (smb_info->sip != NULL)
2704 tri = smb_info->sip->extra_info;
2709 * Set up a subtree for the pipe protocol. (It might not contain
2713 sp_len = tvb_length(sp_tvb);
2717 pipe_item = proto_tree_add_item(tree, proto_smb_pipe,
2718 sp_tvb, 0, sp_len, FALSE);
2719 pipe_tree = proto_item_add_subtree(pipe_item, ett_smb_pipe);
2724 * Do we have any setup words at all?
2726 if (s_tvb != NULL && tvb_length(s_tvb) != 0) {
2728 * Yes. The first of them is the function.
2730 function = tvb_get_letohs(s_tvb, offset);
2731 proto_tree_add_uint(pipe_tree, hf_pipe_function, s_tvb,
2732 offset, 2, function);
2734 if (check_col(pinfo->cinfo, COL_INFO)) {
2735 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2736 val_to_str(function, functions, "Unknown function (0x%04x)"),
2737 smb_info->request ? "Request" : "Response");
2740 tri->function = function;
2743 * The second of them depends on the function.
2747 case CALL_NAMED_PIPE:
2748 case WAIT_NAMED_PIPE:
2752 proto_tree_add_item(pipe_tree, hf_pipe_priority, s_tvb,
2756 case PEEK_NAMED_PIPE:
2757 case Q_NM_P_HAND_STATE:
2758 case SET_NM_P_HAND_STATE:
2759 case Q_NM_PIPE_INFO:
2760 case TRANSACT_NM_PIPE:
2761 case RAW_READ_NM_PIPE:
2762 case RAW_WRITE_NM_PIPE:
2766 fid = tvb_get_letohs(s_tvb, 2);
2767 add_fid(s_tvb, pinfo, pipe_tree, offset, 2, fid);
2774 * It's something unknown.
2775 * XXX - put it into the tree?
2782 * This is either a response or a pipe transaction with
2783 * no setup information.
2785 * In the former case, we can get that information from
2786 * the matching request, if we saw it.
2788 * In the latter case, there is no function or FID.
2790 if (tri != NULL && tri->function != -1) {
2791 function = tri->function;
2792 proto_tree_add_uint(pipe_tree, hf_pipe_function, NULL,
2794 if (check_col(pinfo->cinfo, COL_INFO)) {
2795 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
2796 val_to_str(function, functions, "Unknown function (0x%04x)"),
2797 smb_info->request ? "Request" : "Response");
2801 add_fid(NULL, pinfo, pipe_tree, 0, 0, fid);
2809 * XXX - put the byte count and the pipe name into the tree as well;
2810 * that requires us to fetch a possibly-Unicode string.
2813 if(smb_info->request){
2814 if(strncmp(pipe,"LANMAN",6) == 0){
2815 trans_subcmd=PIPE_LANMAN;
2817 /* assume it is DCERPC */
2818 trans_subcmd=PIPE_DCERPC;
2821 if (!pinfo->fd->flags.visited)
2822 tri->trans_subcmd = trans_subcmd;
2824 trans_subcmd = tri->trans_subcmd;
2828 * We don't know what type of pipe transaction this
2829 * was, so indicate that we didn't dissect it.
2836 case CALL_NAMED_PIPE:
2837 case TRANSACT_NM_PIPE:
2838 switch(trans_subcmd){
2841 return dissect_pipe_lanman(pd_tvb, p_tvb, d_tvb, pinfo,
2847 * Only dissect this if we know the FID.
2852 return dissect_pipe_dcerpc(d_tvb, pinfo, tree,
2861 * We don't know the function; we dissect only LANMAN
2862 * pipe messages, not RPC pipe messages, in that case.
2864 switch(trans_subcmd){
2866 return dissect_pipe_lanman(pd_tvb, p_tvb, d_tvb, pinfo,
2872 case WAIT_NAMED_PIPE:
2875 case PEEK_NAMED_PIPE:
2877 * Request contains no parameters or data.
2879 if (!smb_info->request) {
2883 proto_tree_add_item(pipe_tree, hf_pipe_peek_available,
2884 p_tvb, offset, 2, TRUE);
2886 proto_tree_add_item(pipe_tree, hf_pipe_peek_remaining,
2887 p_tvb, offset, 2, TRUE);
2889 proto_tree_add_item(pipe_tree, hf_pipe_peek_status,
2890 p_tvb, offset, 2, TRUE);
2895 case Q_NM_P_HAND_STATE:
2897 * Request contains no parameters or data.
2899 if (!smb_info->request) {
2902 offset = dissect_ipc_state(p_tvb, pinfo, pipe_tree, 0,
2907 case SET_NM_P_HAND_STATE:
2909 * Response contains no parameters or data.
2911 if (smb_info->request) {
2914 offset = dissect_ipc_state(p_tvb, pinfo, pipe_tree, 0,
2919 case Q_NM_PIPE_INFO:
2921 if (smb_info->request) {
2926 * Request contains an information level.
2928 info_level = tvb_get_letohs(p_tvb, offset);
2929 proto_tree_add_uint(pipe_tree, hf_pipe_getinfo_info_level,
2930 p_tvb, offset, 2, info_level);
2932 if (!pinfo->fd->flags.visited)
2933 tri->info_level = info_level;
2935 guint8 pipe_namelen;
2940 switch (tri->info_level) {
2943 proto_tree_add_item(pipe_tree,
2944 hf_pipe_getinfo_output_buffer_size,
2945 d_tvb, offset, 2, TRUE);
2947 proto_tree_add_item(pipe_tree,
2948 hf_pipe_getinfo_input_buffer_size,
2949 d_tvb, offset, 2, TRUE);
2951 proto_tree_add_item(pipe_tree,
2952 hf_pipe_getinfo_maximum_instances,
2953 d_tvb, offset, 1, TRUE);
2955 proto_tree_add_item(pipe_tree,
2956 hf_pipe_getinfo_current_instances,
2957 d_tvb, offset, 1, TRUE);
2959 pipe_namelen = tvb_get_guint8(d_tvb, offset);
2960 proto_tree_add_uint(pipe_tree,
2961 hf_pipe_getinfo_pipe_name_length,
2962 d_tvb, offset, 1, pipe_namelen);
2964 /* XXX - can this be Unicode? */
2965 proto_tree_add_item(pipe_tree,
2966 hf_pipe_getinfo_pipe_name,
2967 d_tvb, offset, pipe_namelen, TRUE);
2973 case RAW_READ_NM_PIPE:
2975 * Request contains no parameters or data.
2977 if (!smb_info->request) {
2981 offset = dissect_file_data(d_tvb, pinfo, pipe_tree, 0,
2982 tvb_reported_length(d_tvb),
2983 tvb_reported_length(d_tvb));
2987 case RAW_WRITE_NM_PIPE:
2989 if (smb_info->request) {
2993 offset = dissect_file_data(d_tvb, pinfo, pipe_tree,
2994 offset, tvb_reported_length(d_tvb),
2995 tvb_reported_length(d_tvb));
2999 proto_tree_add_item(pipe_tree,
3000 hf_pipe_write_raw_bytes_written,
3001 p_tvb, offset, 2, TRUE);
3010 proto_register_smb_pipe(void)
3012 static hf_register_info hf[] = {
3013 { &hf_pipe_function,
3014 { "Function", "pipe.function", FT_UINT16, BASE_HEX,
3015 VALS(functions), 0, "SMB Pipe Function Code", HFILL }},
3016 { &hf_pipe_priority,
3017 { "Priority", "pipe.priority", FT_UINT16, BASE_DEC,
3018 NULL, 0, "SMB Pipe Priority", HFILL }},
3019 { &hf_pipe_peek_available,
3020 { "Available Bytes", "pipe.peek.available_bytes", FT_UINT16, BASE_DEC,
3021 NULL, 0, "Total number of bytes available to be read from the pipe", HFILL }},
3022 { &hf_pipe_peek_remaining,
3023 { "Bytes Remaining", "pipe.peek.remaining_bytes", FT_UINT16, BASE_DEC,
3024 NULL, 0, "Total number of bytes remaining in the message at the head of the pipe", HFILL }},
3025 { &hf_pipe_peek_status,
3026 { "Pipe Status", "pipe.peek.status", FT_UINT16, BASE_DEC,
3027 VALS(pipe_status), 0, "Pipe status", HFILL }},
3028 { &hf_pipe_getinfo_info_level,
3029 { "Information Level", "pipe.getinfo.info_level", FT_UINT16, BASE_DEC,
3030 NULL, 0, "Information level of information to return", HFILL }},
3031 { &hf_pipe_getinfo_output_buffer_size,
3032 { "Output Buffer Size", "pipe.getinfo.output_buffer_size", FT_UINT16, BASE_DEC,
3033 NULL, 0, "Actual size of buffer for outgoing (server) I/O", HFILL }},
3034 { &hf_pipe_getinfo_input_buffer_size,
3035 { "Input Buffer Size", "pipe.getinfo.input_buffer_size", FT_UINT16, BASE_DEC,
3036 NULL, 0, "Actual size of buffer for incoming (client) I/O", HFILL }},
3037 { &hf_pipe_getinfo_maximum_instances,
3038 { "Maximum Instances", "pipe.getinfo.maximum_instances", FT_UINT8, BASE_DEC,
3039 NULL, 0, "Maximum allowed number of instances", HFILL }},
3040 { &hf_pipe_getinfo_current_instances,
3041 { "Current Instances", "pipe.getinfo.current_instances", FT_UINT8, BASE_DEC,
3042 NULL, 0, "Current number of instances", HFILL }},
3043 { &hf_pipe_getinfo_pipe_name_length,
3044 { "Pipe Name Length", "pipe.getinfo.pipe_name_length", FT_UINT8, BASE_DEC,
3045 NULL, 0, "Length of pipe name", HFILL }},
3046 { &hf_pipe_getinfo_pipe_name,
3047 { "Pipe Name", "pipe.getinfo.pipe_name", FT_STRING, BASE_NONE,
3048 NULL, 0, "Name of pipe", HFILL }},
3049 { &hf_pipe_write_raw_bytes_written,
3050 { "Bytes Written", "pipe.write_raw.bytes_written", FT_UINT16, BASE_DEC,
3051 NULL, 0, "Number of bytes written to the pipe", HFILL }},
3053 static gint *ett[] = {
3055 &ett_smb_pipe_fragments,
3058 proto_smb_pipe = proto_register_protocol(
3059 "SMB Pipe Protocol", "SMB Pipe", "pipe");
3061 proto_register_field_array(proto_smb_pipe, hf, array_length(hf));
3062 proto_register_subtree_array(ett, array_length(ett));
3066 proto_reg_handoff_smb_pipe(void)
3068 data_handle = find_dissector("data");