2 * Routines for smb packet dissection
3 * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
5 * $Id: packet-smb-pipe.c,v 1.15 2001/01/03 06:55:32 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
9 * Copyright 1998 Gerald Combs
11 * Copied from packet-pop.c
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
47 #include "conversation.h"
49 #include "alignment.h"
52 static int proto_smb_lanman = -1;
54 static gint ett_lanman = -1;
55 static gint ett_lanman_servers = -1;
56 static gint ett_lanman_server = -1;
57 static gint ett_lanman_shares = -1;
58 static gint ett_lanman_share = -1;
59 static gint ett_lanman_flags = -1;
64 * ftp://ftp.microsoft.com/developr/drg/CIFS/cifsrap2.txt
66 * among other documents.
70 * The following data structure describes the LANMAN requests we understand
72 * Simply fill in the number, name, and parameter names if you know them
73 * Try to keep them in order
75 * We will extend this data structure as we try to decode more ...
82 char **req_data; /* Hmmm, not flexible enough */
87 static char *lm_params_req_0[] = {"Detail Level", "Return Buffer Size", NULL};
88 static char *lm_params_req_1[] = {"Share Name", "Detail Level", "Receive Buffer Size", NULL};
89 static char *lm_params_resp_1[] = {"Returned Data Len", NULL};
90 static char *lm_params_req_13[] = {"Detail Level", "Receive Buffer Size", NULL};
91 static char *lm_params_req_56[] = {"User Name", "Detail Level", "Receive Buffer Size", NULL};
92 static char *lm_params_req_104[] = {"Detail Level", "Return Buffer Size", "Server Type", "Domain", NULL};
93 static char *lm_params_req_132[] = {"Reserved1", "Reserved2", "Detail Level", "UserInfoStruct?", "Length of UStruct", "Receive Buffer Size", NULL};
94 static char *lm_params_req_133[] = {"Reserved1", "Reserved2", "Detail Level", "UserInfoStruct?", "Length of UStruct", "Receive Buffer Size", NULL};
96 static char *lm_null_params[] = {NULL};
98 struct lanman_desc lmd[] = {
99 {0, "NetShareEnum", lm_params_req_0, lm_null_params, lm_null_params, lm_null_params},
100 {1, "NetShareGetInfo", lm_params_req_1, lm_null_params, lm_params_resp_1, lm_null_params},
101 {13, "NetServerGetInfo", lm_params_req_13, lm_null_params, lm_null_params, lm_null_params},
102 {52, "NetGroupGetUsers", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
103 {56, "NetUserGetInfo", lm_params_req_56, lm_null_params, lm_null_params, lm_null_params},
104 {59, "NetUserGetGroups", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
105 {63, "NetWkstaGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
106 {69, "DOSPrintQEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
107 {70, "DOSPrintQGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
108 {74, "WPrintQueuePause", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
109 {75, "WPrintQueueResume", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
110 {76, "WPrintJobEnumerate", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
111 {77, "WPrintJobGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
112 {81, "RDOSPrintJobDel", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
113 {82, "RDOSPrintJobPause", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
114 {83, "RDOSPrintJobResume", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
115 {84, "WPrintDestEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
116 {85, "WPrintDestGetInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
117 {91, "NetRemoteTOD", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
118 {103, "WPrintQueuePurge", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
119 {104, "NetServerEnum2", lm_params_req_104, lm_null_params, lm_null_params, lm_null_params},
120 {105, "WAccessGetUserPerms", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
121 {115, "SetUserPassword", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
122 {132, "NetWkstaUserLogon", lm_params_req_132, lm_null_params, lm_null_params, lm_null_params},
123 {133, "NetWkstaUserLogoff", lm_params_req_133, lm_null_params, lm_null_params, lm_null_params},
124 {147, "PrintJobInfo", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
125 {205, "WPrintDriverEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
126 {206, "WPrintQProcEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
127 {207, "WPrintPortEnum", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
128 {214, "SamOEMChangePassword", lm_null_params, lm_null_params, lm_null_params, lm_null_params},
129 {-1, NULL, NULL,NULL, NULL, NULL}
133 find_lanman(int lanman_num)
137 /* FIXME, This could be more efficient */
139 while (lmd[i].lanman_num != -1) {
141 if (lmd[i].lanman_num == lanman_num) {
156 #define NETSHAREENUM 0x00 /* 00 */
157 #define NETSERVERENUM2 0x68 /* 104 */
159 void dissect_server_flags(proto_tree *tree, int offset, int length, int flags)
161 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
162 decode_boolean_bitfield(flags, 0x0001, length*8, "Workstation", "Not Workstation"));
163 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
164 decode_boolean_bitfield(flags, 0x0002, length*8, "Server", "Not Server"));
165 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
166 decode_boolean_bitfield(flags, 0x0004, length*8, "SQL Server", "Not SQL Server"));
167 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
168 decode_boolean_bitfield(flags, 0x0008, length*8, "Domain Controller", "Not Domain Controller"));
169 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
170 decode_boolean_bitfield(flags, 0x0010, length*8, "Backup Controller", "Not Backup Controller"));
171 proto_tree_add_text(tree, NullTVB, offset, 4, "%s",
172 decode_boolean_bitfield(flags, 0x0020, length*8, "Time Source", "Not Time Source"));
173 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
174 decode_boolean_bitfield(flags, 0x0040, length*8, "Apple Server", "Not Apple Server"));
175 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
176 decode_boolean_bitfield(flags, 0x0080, length*8, "Novell Server", "Not Novell Server"));
177 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
178 decode_boolean_bitfield(flags, 0x0100, length*8, "Domain Member Server", "Not Domain Member Server"));
179 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
180 decode_boolean_bitfield(flags, 0x0200, length*8, "Print Queue Server", "Not Print Queue Server"));
181 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
182 decode_boolean_bitfield(flags, 0x0400, length*8, "Dialin Server", "Not Dialin Server"));
183 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
184 decode_boolean_bitfield(flags, 0x0800, length*8, "Xenix Server", "Not Xenix Server"));
185 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
186 decode_boolean_bitfield(flags, 0x1000, length*8, "NT Workstation", "Not NT Workstation"));
187 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
188 decode_boolean_bitfield(flags, 0x2000, length*8, "Windows for Workgroups", "Not Windows for Workgroups"));
189 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
190 decode_boolean_bitfield(flags, 0x8000, length*8, "NT Server", "Not NT Server"));
191 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
192 decode_boolean_bitfield(flags, 0x10000, length*8, "Potential Browser", "Not Potential Browser"));
193 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
194 decode_boolean_bitfield(flags, 0x20000, length*8, "Backup Browser", "Not Backup Browser"));
195 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
196 decode_boolean_bitfield(flags, 0x40000, length*8, "Master Browser", "Not Master Browser"));
197 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
198 decode_boolean_bitfield(flags, 0x80000, length*8, "Domain Master Browser", "Not Domain Master Browser"));
199 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
200 decode_boolean_bitfield(flags, 0x100000, length*8, "OSF", "Not OSF"));
201 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
202 decode_boolean_bitfield(flags, 0x200000, length*8, "VMS", "Not VMS"));
203 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
204 decode_boolean_bitfield(flags, 0x400000, length*8, "Windows 95 or above", "Not Windows 95 or above"));
205 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
206 decode_boolean_bitfield(flags, 0x40000000, length*8, "Local List Only", "Not Local List Only"));
207 proto_tree_add_text(tree, NullTVB, offset, length, "%s",
208 decode_boolean_bitfield(flags, 0x80000000, length*8, "Domain Enum", "Not Domain Enum"));
214 static char *p_desc = NULL, *d_desc = NULL, *data = NULL, *params = NULL;
215 static int p_count, d_count, p_offset, d_offset, d_current = 0, p_current = 0;
216 static int pd_p_current = 0, pd_d_current = 0, in_params = 0, need_data = 0;
217 static int lm_ent_count = 0, lm_act_count = 0;
219 /* Initialize the various data structure */
221 dissect_transact_engine_init(const u_char *pd, const char *param_desc, const char *data_desc, int SMB_offset, int ParameterOffset, int ParameterCount, int DataOffset, int DataCount)
225 p_count = ParameterCount;
230 lm_ent_count = lm_act_count = 0;
231 pd_d_current = DataOffset;
232 pd_p_current = ParameterOffset;
233 in_params = need_data = 0;
235 if (p_desc) g_free(p_desc);
236 p_desc = g_malloc(strlen(param_desc) + 1);
237 strcpy(p_desc, param_desc);
239 if (d_desc) g_free(d_desc);
240 d_desc= g_malloc(strlen(data_desc) + 1);
241 strcpy(d_desc, data_desc);
243 if (params) g_free(params);
244 params = g_malloc(p_count);
245 memcpy(params, pd + ParameterOffset, ParameterCount);
247 if (data) g_free(data);
248 data = g_malloc(d_count);
249 memcpy(data, pd + DataOffset, DataCount);
267 int get_byte_count(const u_char *p_data)
270 int count = 0, off = 0;
272 while (p_data[off] && isdigit(p_data[off])) {
274 count = (count * 10) + (int)p_data[off++] - (int)'0';
282 /* Dissect the next item, if Name is null, call it by its data type */
283 /* We pull out the next item in the appropriate place and display it */
284 /* We display the parameters first, then the data, then any auxilliary data */
286 int dissect_transact_next(const u_char *pd, char *Name, int dirn, proto_tree *tree)
291 const char /**Bytes,*/ *AsciiZ = NULL;
296 if (p_desc[p_offset] == 0) return 0; /* No more ... */
300 case 0: /* We are in the params area ... */
302 switch (p_desc[p_offset++]) {
306 if (dirn == 0) { /* We need to process the data ... */
314 case 'h': /* A WORD parameter received */
318 WParam = GSHORT(pd, pd_p_current);
320 proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (%04X)", (Name) ? Name : "Returned Word", WParam, WParam);
324 lm_act_count = WParam;
332 case 'e': /* An ent count .. */
334 if (dirn == 0) { /* Only relevant in a response */
336 WParam = GSHORT(pd, pd_p_current);
338 proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: (%04X)", (Name) ? Name : "Entry Count", WParam);
342 lm_ent_count = WParam; /* Save this for later retrieval */
350 case 'W': /* Word Parameter */
352 if (dirn == 1) { /* A request ... */
354 /* Insert a word param */
356 WParam = GSHORT(pd, pd_p_current);
358 proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (%04X)", (Name) ? Name : "Word Param", WParam, WParam);
362 return 1; /* That's it here ... we have dissected a param */
368 case 'i': /* A long word is returned */
372 LParam = GWORD(pd, pd_p_current);
374 proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u (0x%08X)", (Name) ? Name : "Returned Long Word", LParam, LParam);
384 case 'D': /* Double Word parameter */
388 LParam = GWORD(pd, pd_p_current);
390 proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u (0x%08X)", (Name) ? Name : "DWord Param", LParam, LParam);
394 return 1; /* That's it here */
400 case 'g': /* A byte or series of bytes is returned */
404 bc = get_byte_count(p_desc + p_offset);
406 proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "B", (bc) ? bc : 1, format_text( pd + pd_p_current, (bc) ? bc : 1));
408 pd_p_current += (bc) ? bc : 1;
416 case 'b': /* A byte or series of bytes */
420 bc = get_byte_count(p_desc + p_offset); /* This is not clean */
422 /*Bytes = g_malloc(bc + 1); / * Is this needed ? */
424 proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "B", (bc) ? bc : 1, format_text(pd + pd_p_current, (bc) ? bc : 1));
426 pd_p_current += (bc) ? bc : 1;
428 return 1; /* That's it here ... */
434 case 'O': /* A null pointer */
438 proto_tree_add_text(tree, NullTVB, pd_p_current, 0, "%s: Null Pointer", (Name) ? Name : "Unknown");
440 return 1; /* That's it here */
446 case 'z': /* An AsciiZ string */
450 AsciiZ = pd + pd_p_current;
452 proto_tree_add_text(tree, NullTVB, pd_p_current, strlen(AsciiZ) + 1, "%s: %s", (Name) ? Name : "AsciiZ", AsciiZ);
454 pd_p_current += strlen(AsciiZ) + 1;
456 return 1; /* That's it here ... */
462 case 'F': /* One or more pad bytes */
466 bc = get_byte_count(pd);
468 proto_tree_add_text(tree, NullTVB, pd_p_current, bc, "%s%u: %s", (Name) ? Name : "Pad", bc, format_text(pd + pd_p_current, bc));
472 return 1; /* That's it here */
478 case 'L': /* Receive buffer len: Short */
482 WParam = GSHORT(pd, pd_p_current);
484 proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u (0x%04X)", (Name) ? Name : "Receive Buffer Len", WParam, WParam);
488 return 1; /* That's it here ... */
494 case 's': /* Send buf ... */
500 LParam = GWORD(pd, pd_p_current);
502 proto_tree_add_text(tree, NullTVB, pd_p_current, 4, "%s: %u", (Name) ? Name : "Send Buffer Ptr", LParam);
506 return 1; /* That's it here ... */
516 WParam = GSHORT(pd, pd_p_current);
518 proto_tree_add_text(tree, NullTVB, pd_p_current, 2, "%s: %u", (Name) ? Name : "Send Buffer Len", WParam);
536 case 1: /* We are in the data area ... */
548 static const value_string share_type_vals[] = {
549 {0, "Directory tree"},
550 {1, "Printer queue"},
551 {2, "Communications device"},
557 dissect_pipe_lanman(const u_char *pd, int offset, frame_data *fd,
558 proto_tree *parent, proto_tree *tree, struct smb_info si,
559 int max_data, int SMB_offset, int errcode, int dirn,
560 const u_char *command, int DataOffset, int DataCount,
561 int ParameterOffset, int ParameterCount) {
564 guint32 loc_offset = SMB_offset + ParameterOffset;
565 guint16 FunctionCode;
569 const char *ParameterDescriptor;
570 const char *ReturnDescriptor;
571 proto_tree *lanman_tree = NULL, *flags_tree = NULL;
573 struct lanman_desc *lanman;
574 guint32 string_offset;
576 if (check_col(fd, COL_PROTOCOL))
577 col_add_fstr(fd, COL_PROTOCOL, "LANMAN");
579 if (dirn == 1) { /* The request side */
581 FunctionCode = GSHORT(pd, loc_offset);
583 si.request_val -> last_lanman_cmd = FunctionCode;
585 switch (FunctionCode) {
587 case NETSHAREENUM: /* Never decode this at the moment ... */
589 if (check_col(fd, COL_INFO)) {
591 col_add_fstr(fd, COL_INFO, "NetShareEnum Request");
597 ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, SMB_offset + ParameterOffset, ParameterCount, FALSE);
598 lanman_tree = proto_item_add_subtree(ti, ett_lanman);
600 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Function Code: NetShareEnum");
606 ParameterDescriptor = pd + loc_offset;
608 si.request_val -> trans_response_seen = 0;
610 if (si.request_val -> last_param_descrip) g_free(si.request_val -> last_param_descrip);
611 si.request_val -> last_param_descrip = g_malloc(strlen(ParameterDescriptor) + 1);
612 if (si.request_val -> last_param_descrip)
613 strcpy(si.request_val -> last_param_descrip, ParameterDescriptor);
617 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ParameterDescriptor) + 1, "Parameter Descriptor: %s", ParameterDescriptor);
621 loc_offset += strlen(ParameterDescriptor) + 1;
623 ReturnDescriptor = pd + loc_offset;
625 if (si.request_val -> last_data_descrip) g_free(si.request_val -> last_data_descrip);
626 si.request_val -> last_data_descrip = g_malloc(strlen(ReturnDescriptor) + 1);
627 if (si.request_val -> last_data_descrip)
628 strcpy(si.request_val -> last_data_descrip, ReturnDescriptor);
632 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ReturnDescriptor) + 1, "Return Descriptor: %s", ReturnDescriptor);
636 loc_offset += strlen(ReturnDescriptor) + 1;
638 Level = GSHORT(pd, loc_offset);
642 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Detail Level: %u", Level);
648 RecvBufLen = GSHORT(pd, loc_offset);
652 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Receive Buffer Length: %u", RecvBufLen);
660 case NETSERVERENUM2: /* Process a NetServerEnum2 */
662 if (check_col(fd, COL_INFO)) {
664 col_add_fstr(fd, COL_INFO, "NetServerEnum2 %s", dirn ? "Request" : "Response");
670 ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, SMB_offset + ParameterOffset, ParameterCount, FALSE);
671 lanman_tree = proto_item_add_subtree(ti, ett_lanman);
673 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Function Code: NetServerEnum2");
679 ParameterDescriptor = pd + loc_offset;
681 /* Now, save these for later */
683 si.request_val -> trans_response_seen = 0;
685 if (si.request_val -> last_param_descrip) g_free(si.request_val -> last_param_descrip);
686 si.request_val -> last_param_descrip = g_malloc(strlen(ParameterDescriptor) + 1);
687 if (si.request_val -> last_param_descrip)
688 strcpy(si.request_val -> last_param_descrip, ParameterDescriptor);
692 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ParameterDescriptor) + 1, "Parameter Descriptor: %s", ParameterDescriptor);
696 loc_offset += strlen(ParameterDescriptor) + 1;
698 ReturnDescriptor = pd + loc_offset;
700 if (si.request_val -> last_data_descrip) g_free(si.request_val -> last_data_descrip);
702 si.request_val -> last_data_descrip = g_malloc(strlen(ReturnDescriptor) + 1);
703 if (si.request_val -> last_data_descrip)
704 strcpy(si.request_val -> last_data_descrip, ReturnDescriptor);
708 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ReturnDescriptor) + 1, "Return Descriptor: %s", ReturnDescriptor);
712 loc_offset += strlen(ReturnDescriptor) + 1;
714 Level = GSHORT(pd, loc_offset);
715 si.request_val -> last_level = Level;
719 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Info Detail Level: %u", Level);
725 RecvBufLen = GSHORT(pd, loc_offset);
729 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Receive Buffer Length: %u", RecvBufLen);
735 Flags = GWORD(pd, loc_offset);
739 ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 4, "Server Types Required: 0x%08X", Flags);
740 flags_tree = proto_item_add_subtree(ti, ett_lanman_flags);
741 dissect_server_flags(flags_tree, loc_offset, 4, Flags);
750 default: /* Just try to handle what is there ... */
752 lanman = find_lanman(FunctionCode);
754 if (check_col(fd, COL_INFO)) {
757 col_add_fstr(fd, COL_INFO, "%s Request", lanman -> lanman_name);
760 col_add_fstr(fd, COL_INFO, "Unknown LANMAN Request: %u", FunctionCode);
766 ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, SMB_offset + ParameterOffset, ParameterCount, FALSE);
767 lanman_tree = proto_item_add_subtree(ti, ett_lanman);
770 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "%s Request", lanman -> lanman_name);
773 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Function Code: Unknown LANMAN Request: %u", FunctionCode);
780 ParameterDescriptor = pd + loc_offset;
782 si.request_val -> trans_response_seen = 0;
784 if (si.request_val -> last_param_descrip) g_free(si.request_val -> last_param_descrip);
785 si.request_val -> last_param_descrip = g_malloc(strlen(ParameterDescriptor) + 1);
786 if (si.request_val -> last_param_descrip)
787 strcpy(si.request_val -> last_param_descrip, ParameterDescriptor);
791 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ParameterDescriptor) + 1, "Parameter Descriptor: %s", ParameterDescriptor);
795 loc_offset += strlen(ParameterDescriptor) + 1;
797 ReturnDescriptor = pd + loc_offset;
799 if (si.request_val -> last_data_descrip) g_free(si.request_val -> last_data_descrip);
800 si.request_val -> last_data_descrip = g_malloc(strlen(ReturnDescriptor) + 1);
801 if (si.request_val -> last_data_descrip)
802 strcpy(si.request_val -> last_data_descrip, ReturnDescriptor);
806 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, strlen(ReturnDescriptor) + 1, "Return Descriptor: %s", ReturnDescriptor);
810 loc_offset += strlen(ReturnDescriptor) + 1;
814 int i = 0; /* Counter for names below */
817 dissect_transact_engine_init(pd, ParameterDescriptor, ReturnDescriptor,SMB_offset, loc_offset, ParameterCount, DataOffset, DataCount);
819 if (lanman) name = lanman -> req[i]; /* Must be OK ... */
821 while (dissect_transact_next(pd, name, dirn, lanman_tree))
822 if (name) name = lanman -> req[++i];
829 else { /* Dirn == 0, response */
834 guint32 loc_offset = 0;
836 proto_tree *server_tree = NULL, *flags_tree = NULL, *share_tree = NULL;
838 FunctionCode = si.request_val -> last_lanman_cmd;
841 * If we have already seen the response to this transact, simply
842 * record it as a continuation ...
845 /*$$ printf("TransResponseSeen = %u\n", si.request_val -> trans_response_seen);
847 if (si.request_val -> trans_response_seen == 1) {
849 if (check_col(fd, COL_INFO)) {
850 col_add_fstr(fd, COL_INFO, "Transact Continuation");
855 ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, SMB_offset + DataOffset, END_OF_FRAME, FALSE);
857 lanman_tree = proto_item_add_subtree(ti, ett_lanman);
859 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, END_OF_FRAME, "Payload: %s", format_text(pd + SMB_offset + DataOffset, END_OF_FRAME));
868 si.request_val -> trans_response_seen = 1;
870 switch (FunctionCode) {
874 if (check_col(fd, COL_INFO)) {
876 col_add_fstr(fd, COL_INFO, "NetShareEnum Response");
882 ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, SMB_offset + ParameterOffset, END_OF_FRAME, FALSE);
883 lanman_tree = proto_item_add_subtree(ti, ett_lanman);
885 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 0, "Function Code: NetShareEnum");
889 si.request_val -> trans_response_seen = 1;
891 loc_offset = SMB_offset + ParameterOffset;
893 Status = GSHORT(pd, loc_offset);
897 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
903 Convert = GSHORT(pd, loc_offset);
907 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
913 EntCount = GSHORT(pd, loc_offset);
917 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Entry Count: %u", EntCount);
923 AvailCount = GSHORT(pd, loc_offset);
927 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Available Entries: %u", AvailCount);
935 ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, AvailCount * 20, "Available Shares");
937 share_tree = proto_item_add_subtree(ti, ett_lanman_shares);
941 for (i = 1; i <= EntCount; i++) {
942 const gchar *Share = pd + loc_offset;
944 const gchar *Comment;
945 proto_tree *share = NULL;
946 proto_item *ti = NULL;
950 ti = proto_tree_add_text(share_tree, NullTVB, loc_offset, 20, "Share %s", Share);
951 share = proto_item_add_subtree(ti, ett_lanman_share);
958 proto_tree_add_text(share, NullTVB, loc_offset, 13, "Share Name: %s", Share);
964 loc_offset += 1; /* Pad byte ... */
966 Flags = GSHORT(pd, loc_offset);
970 proto_tree_add_text(share, NullTVB, loc_offset, 2, "Share Type: %s",
971 val_to_str(Flags, share_type_vals, "Unknown (%u)"));
977 /* XXX - should check whether all of the string is within the
979 string_offset = SMB_offset + DataOffset + (GWORD(pd, loc_offset) & 0xFFFF) - Convert;
980 if (IS_DATA_IN_FRAME(string_offset))
981 Comment = pd + string_offset;
983 Comment = "<String goes past end of frame>";
987 proto_tree_add_text(share, NullTVB, loc_offset, 4, "Share Comment: %s", Comment);
999 if (check_col(fd, COL_INFO)) {
1001 col_add_fstr(fd, COL_INFO, "NetServerEnum2 %s", dirn ? "Request" : "Response");
1007 ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, SMB_offset + ParameterOffset, END_OF_FRAME, FALSE);
1008 lanman_tree = proto_item_add_subtree(ti, ett_lanman);
1010 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Function Code: NetServerEnum2");
1014 loc_offset = SMB_offset + ParameterOffset;
1015 Status = GSHORT(pd, loc_offset);
1019 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
1025 Convert = GSHORT(pd, loc_offset);
1029 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
1035 EntCount = GSHORT(pd, loc_offset);
1039 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Entry Count: %u", EntCount);
1045 AvailCount = GSHORT(pd, loc_offset);
1049 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Available Entries: %u", AvailCount);
1057 ti = proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 26 * AvailCount, "Servers");
1060 printf("Null value returned from proto_tree_add_text\n");
1065 server_tree = proto_item_add_subtree(ti, ett_lanman_servers);
1069 /* Make sure we don't go past the end of the capture buffer */
1071 for (i = 1; (i <= EntCount) && ((pi.captured_len - loc_offset) >= 16); i++) {
1072 const gchar *Server = pd + loc_offset;
1075 guint32 ServerFlags;
1076 const gchar *Comment;
1077 proto_tree *server = NULL;
1082 ti = proto_tree_add_text(server_tree, NullTVB, loc_offset,
1083 (si.request_val -> last_level) ? 26 : 16,
1084 "Server %s", Server);
1085 server = proto_item_add_subtree(ti, ett_lanman_server);
1092 proto_tree_add_text(server, NullTVB, loc_offset, 16, "Server Name: %s", Server);
1098 if (si.request_val -> last_level) { /* Print out the rest of the info */
1100 ServerMajor = GBYTE(pd, loc_offset);
1104 proto_tree_add_text(server, NullTVB, loc_offset, 1, "Major Version: %u", ServerMajor);
1110 ServerMinor = GBYTE(pd, loc_offset);
1114 proto_tree_add_text(server, NullTVB, loc_offset, 1, "Minor Version: %u", ServerMinor);
1120 ServerFlags = GWORD(pd, loc_offset);
1124 ti = proto_tree_add_text(server, NullTVB, loc_offset, 4, "Server Type: 0x%08X", ServerFlags);
1125 flags_tree = proto_item_add_subtree(ti, ett_lanman_flags);
1126 dissect_server_flags(flags_tree, loc_offset, 4, ServerFlags);
1132 /* XXX - should check whether all of the string is within the
1134 string_offset = SMB_offset + DataOffset + (GWORD(pd, loc_offset) & 0xFFFF) - Convert;
1135 if (IS_DATA_IN_FRAME(string_offset))
1136 Comment = pd + string_offset;
1138 Comment = "<String goes past end of frame>";
1142 proto_tree_add_text(server, NullTVB, loc_offset, 4, "Server Comment: %s", Comment);
1156 lanman = find_lanman(si.request_val -> last_lanman_cmd);
1158 if (check_col(fd, COL_INFO)) {
1161 col_add_fstr(fd, COL_INFO, "%s Response", lanman -> lanman_name);
1164 col_add_fstr(fd, COL_INFO, "Unknown LANMAN Response: %u", FunctionCode);
1170 ti = proto_tree_add_item(parent, proto_smb_lanman, NullTVB, SMB_offset + ParameterOffset, END_OF_FRAME, FALSE);
1171 lanman_tree = proto_item_add_subtree(ti, ett_lanman);
1173 proto_tree_add_text(lanman_tree, NullTVB, 0, 0, "%s Response", lanman -> lanman_name);
1176 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 0, "Function Code: Unknown LANMAN Response: %u", FunctionCode);
1180 loc_offset = SMB_offset + ParameterOffset;
1182 Status = GSHORT(pd, loc_offset);
1186 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Status: %u", Status);
1192 Convert = GSHORT(pd, loc_offset);
1196 proto_tree_add_text(lanman_tree, NullTVB, loc_offset, 2, "Convert: %u", Convert);
1207 dissect_transact_engine_init(pd, si.request_val -> last_param_descrip, si.request_val -> last_data_descrip, SMB_offset, loc_offset, ParameterCount, DataOffset, DataCount);
1209 if (lanman) name = lanman -> resp[i];
1211 while (dissect_transact_next(pd, name, dirn, lanman_tree))
1212 if (name) name = lanman -> resp[++i];
1228 dissect_pipe_smb(const u_char *pd, int offset, frame_data *fd, proto_tree *parent, proto_tree *tree, struct smb_info si, int max_data, int SMB_offset, int errcode, int dirn, const u_char *command, int DataOffset, int DataCount, int ParameterOffset, int ParameterCount)
1231 if (!proto_is_protocol_enabled(proto_smb_lanman))
1234 if (command != NULL && strcmp(command, "LANMAN") == 0) { /* Try to decode a LANMAN */
1236 return dissect_pipe_lanman(pd, offset, fd, parent, tree, si, max_data, SMB_offset, errcode, dirn, command, DataOffset, DataCount, ParameterOffset, ParameterCount);
1248 register_proto_smb_pipe( void){
1251 static gint *ett[] = {
1254 &ett_lanman_servers,
1262 proto_smb_lanman = proto_register_protocol(
1263 "Microsoft Windows Lanman Protocol", "LANMAN", "lanman");
1265 proto_register_subtree_array(ett, array_length(ett));