xref: /titanic_52/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_smb.c (revision c7158ae983f5a04c4a998f468ecefba6d23ba721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * References used throughout this code:
31  *
32  * [CIFS/1.0] : A Common Internet File System (CIFS/1.0) Protocol
33  *		Internet Engineering Task Force (IETF) draft
34  *		Paul J. Leach, Microsoft, Dec. 1997
35  *
36  * [X/Open-SMB] : X/Open CAE Specification;
37  *		Protocols for X/Open PC Interworking: SMB, Version 2
38  *		X/Open Document Number: C209
39  */
40 
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #include "snoop.h"
47 
48 /* some macros just for compactness */
49 #define	GETLINE get_line(0, 0)
50 #define	DECARGS int flags, uchar_t *data, int len, char *extrainfo
51 
52 /*
53  * SMB Format (header)
54  * [X/Open-SMB, Sec. 5.1]
55  */
56 struct smb {
57 	uchar_t idf[4]; /*  identifier, contains 0xff, 'SMB'  */
58 	uchar_t com;    /*  command code  */
59 	uchar_t rcls;   /*  error class  */
60 	uchar_t res;
61 	uchar_t err[2]; /*  error code  */
62 	uchar_t flags;
63 	uchar_t flags2[2];
64 	uchar_t re[12];
65 	uchar_t tid[2];
66 	uchar_t pid[2];
67 	uchar_t uid[2];
68 	uchar_t mid[2];
69 	/*
70 	 * immediately after the above 32 byte header:
71 	 *   unsigned char  WordCount;
72 	 *   unsigned short ParameterWords[ WordCount ];
73 	 *   unsigned short ByteCount;
74 	 *   unsigned char  ParameterBytes[ ByteCount ];
75 	 */
76 };
77 
78 /* smb flags */
79 #define	SERVER_RESPONSE	0x80
80 
81 static void interpret_sesssetupX(DECARGS);
82 static void interpret_tconX(DECARGS);
83 static void interpret_trans(DECARGS);
84 static void interpret_trans2(DECARGS);
85 static void interpret_negprot(DECARGS);
86 static void interpret_default(DECARGS);
87 
88 /*
89  * Trans2 subcommand codes
90  * [X/Open-SMB, Sec. 16.1.7]
91  */
92 #define	TRANS2_OPEN 0x00
93 #define	TRANS2_FIND_FIRST 0x01
94 #define	TRANS2_FIND_NEXT2 0x02
95 #define	TRANS2_QUERY_FS_INFORMATION 0x03
96 #define	TRANS2_QUERY_PATH_INFORMATION 0x05
97 #define	TRANS2_SET_PATH_INFORMATION 0x06
98 #define	TRANS2_QUERY_FILE_INFORMATION 0x07
99 #define	TRANS2_SET_FILE_INFORMATION 0x08
100 #define	TRANS2_CREATE_DIRECTORY 0x0D
101 
102 
103 struct decode {
104 	char *name;
105 	void (*func)(DECARGS);
106 	char *callfmt;
107 	char *replyfmt;
108 };
109 
110 /*
111  * SMB command codes (function names)
112  * [X/Open-SMB, Sec. 5.2]
113  */
114 static struct decode SMBtable[256] = {
115 	/* 0x00 */
116 	{ "mkdir", 0, 0, 0 },
117 	{ "rmdir", 0, 0, 0 },
118 	{ "open", 0, 0, 0 },
119 	{ "create", 0, 0, 0 },
120 
121 	{
122 		"close", 0,
123 		/* [X/Open-SMB, Sec. 7.10] */
124 		"WFileID\0lLastModTime\0wByteCount\0\0",
125 		"wByteCount\0\0"
126 	},
127 
128 	{ "flush", 0, 0, 0 },
129 	{ "unlink", 0, 0, 0 },
130 
131 	{
132 		"mv", 0,
133 		/* [X/Open-SMB, Sec. 7.11] */
134 		"wFileAttributes\0wByteCount\0"
135 		"r\0UFileName\0r\0UNewPath\0\0",
136 		"wByteCount\0\0"
137 	},
138 
139 	{
140 		"getatr", 0,
141 		/* [X/Open-SMB, Sec. 8.4] */
142 		"dBytecount\0r\0UFileName\0\0",
143 		"wFileAttributes\0lTime\0lSize\0R\0R\0R\0"
144 		"R\0R\0wByteCount\0\0"
145 	},
146 
147 	{ "setatr", 0, 0, 0 },
148 
149 	{
150 		"read", 0,
151 		/* [X/Open-SMB, Sec. 7.4] */
152 		"WFileID\0wI/0 Bytes\0LFileOffset\0"
153 		"WBytesLeft\0wByteCount\0\0",
154 		"WDataLength\0R\0R\0R\0R\0wByteCount\0\0"
155 	},
156 
157 	{
158 		"write", 0,
159 		/* [X/Open-SMB, Sec. 7.5] */
160 		"WFileID\0wI/0 Bytes\0LFileOffset\0WBytesLeft\0"
161 		"wByteCount\0\0",
162 		"WDataLength\0wByteCount\0\0"
163 	},
164 
165 	{ "lock", 0, 0, 0 },
166 	{ "unlock", 0, 0, 0 },
167 	{ "ctemp", 0, 0, 0 },
168 	{ "mknew", 0, 0, 0 },
169 
170 	/* 0x10 */
171 	{
172 		"chkpth", 0,
173 		/* [X/Open-SMB, Sec. 8.7] */
174 		"wByteCount\0r\0UFile\0\0",
175 		"wByteCount\0\0"
176 	},
177 
178 	{ "exit", 0, 0, 0 },
179 	{ "lseek", 0, 0, 0 },
180 	{ "lockread", 0, 0, 0 },
181 	{ "writeunlock", 0, 0, 0 },
182 	{ 0, 0, 0, 0 },
183 	{ 0, 0, 0, 0 },
184 	{ 0, 0, 0, 0 },
185 	{ 0, 0, 0, 0 },
186 	{ 0, 0, 0, 0 },
187 
188 	{
189 		"readbraw", 0,
190 		/* [X/Open-SMB, Sec. 10.1] */
191 		"WFileID\0LFileOffset\0wMaxCount\0"
192 		"wMinCount\0lTimeout\0R\0wByteCount\0\0", 0
193 	},
194 
195 	{ "readbmpx", 0, 0, 0 },
196 	{ "readbs", 0, 0, 0 },
197 	{ "writebraw", 0, 0, 0 },
198 	{ "writebmpx", 0, 0, 0 },
199 	{ "writebs", 0, 0, 0 },
200 
201 	/* 0x20 */
202 	{ "writec", 0, 0, 0 },
203 	{ "qrysrv", 0, 0, 0 },
204 	{ "setattrE", 0, 0, 0 },
205 	{ "getattrE", 0, 0, 0 },
206 
207 	{
208 		"lockingX", 0,
209 		/* [X/Open-SMB, Sec. 12.2] */
210 		"wChainedCommand\0wNextOffset\0WFileID\0"
211 		"wLockType\0lOpenTimeout\0"
212 		"W#Unlocks\0W#Locks\0wByteCount\0\0", 0
213 	},
214 
215 	{ "trans", interpret_trans, 0, 0 },
216 	{ "transs", 0, 0, 0 },
217 	{ "ioctl", 0, 0, 0 },
218 	{ "ioctls", 0, 0, 0 },
219 	{ "copy", 0, 0, 0 },
220 	{ "move", 0, 0, 0 },
221 	{ "echo", 0, 0, 0 },
222 	{ "writeclose", 0, 0, 0 },
223 
224 	{
225 		"openX", 0,
226 		/* [X/Open-SMB, Sec. 12.1] */
227 		"wChainedCommand\0wNextOffset\0wFlags\0"
228 		"wMode\0wSearchAttributes\0wFileAttributes\0"
229 		"lTime\0wOpenFunction\0lFileSize\0lOpenTimeout\0"
230 		"R\0R\0wByteCount\0r\0UFileName\0\0",
231 		"wChainedCommand\0wNextOffset\0WFileID\0"
232 		"wAttributes\0lTime\0LSize\0wOpenMode\0"
233 		"wFileType\0wDeviceState\0wActionTaken\0"
234 		"lUniqueFileID\0R\0wBytecount\0\0"
235 	},
236 
237 	{ "readX", 0, 0, 0 },
238 	{ "writeX", 0, 0, 0 },
239 
240 	/* 0x30 */
241 	{ 0, 0, 0, 0 },
242 	{ "closeTD", 0, 0, 0 },
243 	{ "trans2", interpret_trans2, 0, 0 },
244 	{ "trans2s", 0, 0, 0 },
245 	{
246 		"findclose", 0,
247 		/* [X/Open-SMB, Sec. 15.4 ] */
248 		"WFileID\0wByteCount\0\0",
249 		"wByteCount\0\0"
250 	},
251 	{ 0, 0, 0, 0 },
252 	{ 0, 0, 0, 0 },
253 	{ 0, 0, 0, 0 },
254 	{ 0, 0, 0, 0 },
255 	{ 0, 0, 0, 0 },
256 	{ 0, 0, 0, 0 },
257 	{ 0, 0, 0, 0 },
258 	{ 0, 0, 0, 0 },
259 	{ 0, 0, 0, 0 },
260 	{ 0, 0, 0, 0 },
261 	{ 0, 0, 0, 0 },
262 
263 	/* 0x40 */
264 	{ 0, 0, 0, 0 },
265 	{ 0, 0, 0, 0 },
266 	{ 0, 0, 0, 0 },
267 	{ 0, 0, 0, 0 },
268 	{ 0, 0, 0, 0 },
269 	{ 0, 0, 0, 0 },
270 	{ 0, 0, 0, 0 },
271 	{ 0, 0, 0, 0 },
272 	{ 0, 0, 0, 0 },
273 	{ 0, 0, 0, 0 },
274 	{ 0, 0, 0, 0 },
275 	{ 0, 0, 0, 0 },
276 	{ 0, 0, 0, 0 },
277 	{ 0, 0, 0, 0 },
278 	{ 0, 0, 0, 0 },
279 	{ 0, 0, 0, 0 },
280 
281 	/* 0x50 */
282 	{ 0, 0, 0, 0 },
283 	{ 0, 0, 0, 0 },
284 	{ 0, 0, 0, 0 },
285 	{ 0, 0, 0, 0 },
286 	{ 0, 0, 0, 0 },
287 	{ 0, 0, 0, 0 },
288 	{ 0, 0, 0, 0 },
289 	{ 0, 0, 0, 0 },
290 	{ 0, 0, 0, 0 },
291 	{ 0, 0, 0, 0 },
292 	{ 0, 0, 0, 0 },
293 	{ 0, 0, 0, 0 },
294 	{ 0, 0, 0, 0 },
295 	{ 0, 0, 0, 0 },
296 	{ 0, 0, 0, 0 },
297 	{ 0, 0, 0, 0 },
298 
299 	/* 0x60 */
300 	{ 0, 0, 0, 0 },
301 	{ 0, 0, 0, 0 },
302 	{ 0, 0, 0, 0 },
303 	{ 0, 0, 0, 0 },
304 	{ 0, 0, 0, 0 },
305 	{ 0, 0, 0, 0 },
306 	{ 0, 0, 0, 0 },
307 	{ 0, 0, 0, 0 },
308 	{ 0, 0, 0, 0 },
309 	{ 0, 0, 0, 0 },
310 	{ 0, 0, 0, 0 },
311 	{ 0, 0, 0, 0 },
312 	{ 0, 0, 0, 0 },
313 	{ 0, 0, 0, 0 },
314 	{ 0, 0, 0, 0 },
315 	{ 0, 0, 0, 0 },
316 
317 	/* 0x70 */
318 	{ "tcon", 0, 0, 0 },
319 	{
320 		"tdis", 0,
321 		/* [X/Open-SMB, Sec. 6.3] */
322 		"wByteCount\0\0",
323 		"wByteCount\0\0"
324 	},
325 	{ "negprot", interpret_negprot, 0, 0 },
326 	{ "sesssetupX", interpret_sesssetupX, 0, 0 },
327 	{
328 		"uloggoffX", 0,
329 		/* [X/Open-SMB, Sec. 15.5] */
330 		"wChainedCommand\0wNextOffset\0\0",
331 		"wChainedCommnad\0wNextOffset\0\0" },
332 	{ "tconX", interpret_tconX, 0, 0 },
333 	{ 0, 0, 0, 0 },
334 	{ 0, 0, 0, 0 },
335 	{ 0, 0, 0, 0 },
336 	{ 0, 0, 0, 0 },
337 	{ 0, 0, 0, 0 },
338 	{ 0, 0, 0, 0 },
339 	{ 0, 0, 0, 0 },
340 	{ 0, 0, 0, 0 },
341 	{ 0, 0, 0, 0 },
342 	{ 0, 0, 0, 0 },
343 
344 	/* 0x80 */
345 	{ "dskattr", 0, 0, 0 },
346 	{ "search", 0, 0, 0 },
347 	{ "ffirst", 0, 0, 0 },
348 	{ "funique", 0, 0, 0 },
349 	{ "fclose", 0, 0, 0 },
350 	{ 0, 0, 0, 0 },
351 	{ 0, 0, 0, 0 },
352 	{ 0, 0, 0, 0 },
353 	{ 0, 0, 0, 0 },
354 	{ 0, 0, 0, 0 },
355 	{ 0, 0, 0, 0 },
356 	{ 0, 0, 0, 0 },
357 	{ 0, 0, 0, 0 },
358 	{ 0, 0, 0, 0 },
359 	{ 0, 0, 0, 0 },
360 	{ 0, 0, 0, 0 },
361 
362 	/* 0x90 */
363 	{ 0, 0, 0, 0 },
364 	{ 0, 0, 0, 0 },
365 	{ 0, 0, 0, 0 },
366 	{ 0, 0, 0, 0 },
367 	{ 0, 0, 0, 0 },
368 	{ 0, 0, 0, 0 },
369 	{ 0, 0, 0, 0 },
370 	{ 0, 0, 0, 0 },
371 	{ 0, 0, 0, 0 },
372 	{ 0, 0, 0, 0 },
373 	{ 0, 0, 0, 0 },
374 	{ 0, 0, 0, 0 },
375 	{ 0, 0, 0, 0 },
376 	{ 0, 0, 0, 0 },
377 	{ 0, 0, 0, 0 },
378 	{ 0, 0, 0, 0 },
379 
380 	/* 0xa0 */
381 	/*
382 	 * Command codes 0xa0 to 0xa7 are from
383 	 * [CIFS/1.0, Sec. 5.1]
384 	 */
385 	{ " NT_Trans", 0, 0, 0 },
386 	{ " NT_Trans2", 0, 0, 0 },
387 	{
388 		" NT_CreateX", 0,
389 		/* [CIFS/1.0, Sec. 4.2.1] */
390 		"wChainedCommand\0wNextOffset\0r\0"
391 		"wNameLength\0lCreateFlags\0lRootDirFID\0"
392 		"lDesiredAccess\0R\0R\0R\0R\0"
393 		"lNTFileAttributes\0lFileShareAccess\0"
394 		"R\0R\0lCreateOption\0lImpersonationLevel\0"
395 		"bSecurityFlags\0wByteCount\0r\0"
396 		"UFileName\0\0",
397 		"wChainedCommand\0wNextOffset\0"
398 		"bOplockLevel\0WFileID\0lCreateAction\0\0"
399 	},
400 	{ 0, 0, 0, 0 },
401 	{
402 		" NT_Cancel", 0,
403 		/* [CIFS/1.0, Sec. 4.1.8] */
404 		"wByteCount\0", 0
405 	},
406 	{ 0, 0, 0, 0 },
407 	{ 0, 0, 0, 0 },
408 	{ 0, 0, 0, 0 },
409 	{ 0, 0, 0, 0 },
410 	{ 0, 0, 0, 0 },
411 	{ 0, 0, 0, 0 },
412 	{ 0, 0, 0, 0 },
413 	{ 0, 0, 0, 0 },
414 	{ 0, 0, 0, 0 },
415 	{ 0, 0, 0, 0 },
416 	{ 0, 0, 0, 0 },
417 
418 	/* 0xb0 */
419 	{ 0, 0, 0, 0 },
420 	{ 0, 0, 0, 0 },
421 	{ 0, 0, 0, 0 },
422 	{ 0, 0, 0, 0 },
423 	{ 0, 0, 0, 0 },
424 	{ 0, 0, 0, 0 },
425 	{ 0, 0, 0, 0 },
426 	{ 0, 0, 0, 0 },
427 	{ 0, 0, 0, 0 },
428 	{ 0, 0, 0, 0 },
429 	{ 0, 0, 0, 0 },
430 	{ 0, 0, 0, 0 },
431 	{ 0, 0, 0, 0 },
432 	{ 0, 0, 0, 0 },
433 	{ 0, 0, 0, 0 },
434 	{ 0, 0, 0, 0 },
435 
436 	/* 0xc0 */
437 	{ "splopen", 0, 0, 0 },
438 	{ "splwr", 0, 0, 0 },
439 	{ "splclose", 0, 0, 0 },
440 	{ "splretq", 0, 0, 0 },
441 	{ 0, 0, 0, 0 },
442 	{ 0, 0, 0, 0 },
443 	{ 0, 0, 0, 0 },
444 	{ 0, 0, 0, 0 },
445 	{ 0, 0, 0, 0 },
446 	{ 0, 0, 0, 0 },
447 	{ 0, 0, 0, 0 },
448 	{ 0, 0, 0, 0 },
449 	{ 0, 0, 0, 0 },
450 	{ 0, 0, 0, 0 },
451 	{ 0, 0, 0, 0 },
452 	{ 0, 0, 0, 0 },
453 
454 	/* 0xd0 */
455 	{ "sends", 0, 0, 0 },
456 	{ "sendb", 0, 0, 0 },
457 	{ "fwdname", 0, 0, 0 },
458 	{ "cancelf", 0, 0, 0 },
459 	{ "getmac", 0, 0, 0 },
460 	{ "sendstrt", 0, 0, 0 },
461 	{ "sendend", 0, 0, 0 },
462 	{ "sendtxt", 0, 0, 0 },
463 	{ 0, 0, 0, 0 },
464 	{ 0, 0, 0, 0 },
465 	{ 0, 0, 0, 0 },
466 	{ 0, 0, 0, 0 },
467 	{ 0, 0, 0, 0 },
468 	{ 0, 0, 0, 0 },
469 	{ 0, 0, 0, 0 },
470 	{ 0, 0, 0, 0 },
471 
472 	/* 0xe0 */
473 	{ 0, 0, 0, 0 },
474 	{ 0, 0, 0, 0 },
475 	{ 0, 0, 0, 0 },
476 	{ 0, 0, 0, 0 },
477 	{ 0, 0, 0, 0 },
478 	{ 0, 0, 0, 0 },
479 	{ 0, 0, 0, 0 },
480 	{ 0, 0, 0, 0 },
481 	{ 0, 0, 0, 0 },
482 	{ 0, 0, 0, 0 },
483 	{ 0, 0, 0, 0 },
484 	{ 0, 0, 0, 0 },
485 	{ 0, 0, 0, 0 },
486 	{ 0, 0, 0, 0 },
487 	{ 0, 0, 0, 0 },
488 	{ 0, 0, 0, 0 },
489 
490 	/* 0xf0 */
491 	{ 0, 0, 0, 0 },
492 	{ 0, 0, 0, 0 },
493 	{ 0, 0, 0, 0 },
494 	{ 0, 0, 0, 0 },
495 	{ 0, 0, 0, 0 },
496 	{ 0, 0, 0, 0 },
497 	{ 0, 0, 0, 0 },
498 	{ 0, 0, 0, 0 },
499 	{ 0, 0, 0, 0 },
500 	{ 0, 0, 0, 0 },
501 	{ 0, 0, 0, 0 },
502 	{ 0, 0, 0, 0 },
503 	{ 0, 0, 0, 0 },
504 	{ 0, 0, 0, 0 },
505 	{ 0, 0, 0, 0 },
506 	{ 0, 0, 0, 0 }
507 };
508 
509 /* Helpers to get short and int values in Intel order. */
510 static ushort_t
511 get2(uchar_t *p) {
512 	return (p[0] + (p[1]<<8));
513 }
514 static uint_t
515 get4(uchar_t *p) {
516 	return (p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24));
517 }
518 
519 /*
520  * This is called by snoop_netbios.c.
521  * This is the external entry point.
522  */
523 void
524 interpret_smb(int flags, uchar_t *data, int len)
525 {
526 	struct smb *smb;
527 	char *call_reply_detail, *call_reply_sum;
528 	struct decode *decoder;
529 	char xtra[300];
530 	char *line;
531 
532 	smb = (struct smb *)data;
533 	decoder = &SMBtable[smb->com & 255];
534 	if (smb->flags & SERVER_RESPONSE) {
535 		call_reply_detail = "SERVER RESPONSE";
536 		call_reply_sum = "R";
537 	} else {
538 		call_reply_detail =	"CLIENT REQUEST";
539 		call_reply_sum = "C";
540 	}
541 	xtra[0] = '\0';
542 
543 	/*
544 	 * SMB Header description
545 	 * [X/Open-SMB, Sec. 5.1]
546 	 */
547 	if (flags & F_DTAIL) {
548 		show_header("SMB:  ", "SMB Header", len);
549 		show_space();
550 		sprintf(GETLINE, "%s", call_reply_detail);
551 
552 		(void) sprintf(GETLINE, "Command code = 0x%x",
553 				smb->com);
554 		if (decoder->name)
555 			(void) sprintf(GETLINE,
556 				"Command name =  SMB%s", decoder->name);
557 
558 		show_space();
559 		sprintf(GETLINE, "SMB Status:");
560 
561 		/* Error classes [X/Open-SMB, Sec. 5.6] */
562 		switch (smb->rcls) {
563 		case 0x00:
564 			sprintf(GETLINE,
565 				"   - Error class = No error");
566 			break;
567 		case 0x01:
568 			sprintf(GETLINE,
569 				"   - Error class = Operating System");
570 			break;
571 		case 0x02:
572 			sprintf(GETLINE,
573 				"   - Error class = LMX server");
574 			break;
575 		case 0x03:
576 			sprintf(GETLINE,
577 				"   - Error class = Hardware");
578 			break;
579 		case 0xff:
580 		default:
581 			sprintf(GETLINE,
582 				"   - Error class = Incorrect format.");
583 			break;
584 		}
585 
586 		if (smb->err[0] != 0x00) {
587 			sprintf(GETLINE,
588 				"   - Error code = %x", smb->err[0]);
589 		} else
590 			sprintf(GETLINE, "   - Error code = No error");
591 
592 		show_space();
593 
594 		sprintf(GETLINE, "Header:");
595 		sprintf(GETLINE, "   - Tree ID      (TID) = 0x%.4x",
596 			get2(smb->tid));
597 		sprintf(GETLINE, "   - Process ID   (PID) = 0x%.4x",
598 			get2(smb->pid));
599 		sprintf(GETLINE, "   - User ID      (UID) = 0x%.4x",
600 			get2(smb->uid));
601 		sprintf(GETLINE, "   - Multiplex ID (MID) = 0x%.4x",
602 			get2(smb->mid));
603 		sprintf(GETLINE, "   - Flags summary = 0x%.2x",
604 					smb->flags);
605 		sprintf(GETLINE, "   - Flags2 summary = 0x%.4x",
606 					get2(smb->flags2));
607 		show_space();
608 	}
609 
610 	if (decoder->func)
611 		(decoder->func)(flags, (uchar_t *)data, len, xtra);
612 	else
613 		interpret_default(flags, (uchar_t *)data, len, xtra);
614 
615 	if (flags & F_SUM) {
616 		line = get_sum_line();
617 		if (decoder->name)
618 			sprintf(line,
619 			"SMB %s Code=0x%x Name=SMB%s %sError=%x ",
620 			call_reply_sum, smb->com, decoder->name, xtra,
621 			smb->err[0]);
622 
623 		else sprintf(line, "SMB %s Code=0x%x Error=%x ",
624 					call_reply_sum, smb->com, smb->err[0]);
625 
626 		line += strlen(line);
627 	}
628 
629 	if (flags & F_DTAIL)
630 		show_trailer();
631 }
632 
633 static void
634 output_bytes(uchar_t *data, int bytecount)
635 {
636 	int i;
637 	char buff[80];
638 	char word[10];
639 
640 	buff[0] = word[0] = '\0';
641 	sprintf(GETLINE, "Byte values (in hex):");
642 	for (i = 0; i < bytecount; i++) {
643 		sprintf(word, "%.2x ", data[i]);
644 		strcat(buff, word);
645 		if ((i+1)%16 == 0 || i == (bytecount-1)) {
646 			sprintf(GETLINE, "%s", buff);
647 			strcpy(buff, "");
648 		}
649 	}
650 }
651 
652 /*
653  * Based on the Unicode Standard,  http://www.unicode.org/
654  * "The Unicode Standard: A Technical Introduction", June 1998
655  */
656 static int
657 unicode2ascii(char *outstr, int outlen, uchar_t *instr, int inlen)
658 {
659 	int i = 0, j = 0;
660 	char c;
661 
662 	while (i < inlen && j < (outlen-1)) {
663 		/* Show unicode chars >= 256 as '?' */
664 		if (instr[i+1])
665 			c = '?';
666 		else
667 			c = instr[i];
668 		if (c == '\0')
669 			break;
670 		outstr[j] = c;
671 		i += 2;
672 		j++;
673 	}
674 	outstr[j] = '\0';
675 	return (j);
676 }
677 
678 /*
679  * TRANS2 information levels
680  * [X/Open-SMB, Sec. 16.1.6]
681  */
682 static void
683 get_info_level(char *outstr, int value)
684 {
685 
686 	switch (value) {
687 	case 1:
688 		sprintf(outstr, "Standard"); break;
689 	case 2:
690 		sprintf(outstr, "Query EA Size"); break;
691 	case 3:
692 		sprintf(outstr, "Query EAS from List"); break;
693 	case 0x101:
694 		sprintf(outstr, "Directory Info"); break;
695 	case 0x102:
696 		sprintf(outstr, "Full Directory Info"); break;
697 	case 0x103:
698 		sprintf(outstr, "Names Info"); break;
699 	case 0x104:
700 		sprintf(outstr, "Both Directory Info"); break;
701 	default:
702 		sprintf(outstr, "Unknown"); break;
703 	}
704 }
705 
706 /*
707  * Interpret TRANS2_QUERY_PATH subcommand
708  * [X/Open-SMB, Sec. 16.7]
709  */
710 /* ARGSUSED */
711 static void
712 output_trans2_querypath(int flags, uchar_t *data, char *xtra)
713 {
714 	int length;
715 	char filename[256];
716 
717 	if (flags & F_SUM) {
718 		length = sprintf(xtra, "QueryPathInfo ");
719 		xtra += length;
720 		data += 6;
721 		(void) unicode2ascii(filename, 256, data, 512);
722 		sprintf(xtra, "File=%s ", filename);
723 	}
724 
725 	if (flags & F_DTAIL) {
726 		sprintf(GETLINE, "FunctionName = QueryPathInfo");
727 		sprintf(GETLINE, "InfoLevel = 0x%.4x",
728 			get2(data));
729 		data += 6;
730 		(void) unicode2ascii(filename, 256, data, 512);
731 		sprintf(GETLINE, "FileName = %s",
732 			filename);
733 	}
734 }
735 
736 /*
737  * Interpret TRANS2_QUERY_FILE subcommand
738  * [X/Open-SMB, Sec. 16.9]
739  */
740 /* ARGSUSED */
741 static void
742 output_trans2_queryfile(int flags, uchar_t *data, char *xtra)
743 {
744 	int length;
745 
746 	if (flags & F_SUM) {
747 		length = sprintf(xtra, "QueryFileInfo ");
748 		xtra += length;
749 		sprintf(xtra, "FileID=0x%x ", get2(data));
750 	}
751 
752 	if (flags & F_DTAIL) {
753 		sprintf(GETLINE, "FunctionName = QueryFileInfo");
754 		sprintf(GETLINE, "FileID = 0x%.4x",
755 			get2(data));
756 		data += 2;
757 		sprintf(GETLINE, "InfoLevel = 0x%.4x",
758 			get2(data));
759 	}
760 }
761 
762 /*
763  * Interpret TRANS2_SET_FILE subcommand
764  * [X/Open-SMB, Sec. 16.10]
765  */
766 /* ARGSUSED */
767 static void
768 output_trans2_setfile(int flags, uchar_t *data, char *xtra)
769 {
770 	int length;
771 
772 	if (flags & F_SUM) {
773 		length = sprintf(xtra, "SetFileInfo ");
774 		xtra += length;
775 		sprintf(xtra, "FileID=0x%x ", get2(data));
776 	}
777 
778 	if (flags & F_DTAIL) {
779 		sprintf(GETLINE, "FunctionName = SetFileInfo");
780 		sprintf(GETLINE, "FileID = 0x%.4x",
781 			get2(data));
782 		data += 2;
783 		sprintf(GETLINE, "InfoLevel = 0x%.4x",
784 			get2(data));
785 	}
786 }
787 
788 /*
789  * Interpret TRANS2_FIND_FIRST subcommand
790  * [X/Open-SMB, Sec. 16.3]
791  */
792 /* ARGSUSED */
793 static void
794 output_trans2_findfirst(int flags, uchar_t *data, char *xtra)
795 {
796 	int length;
797 	char filename[256];
798 	char infolevel[100];
799 
800 	if (flags & F_SUM) {
801 		length = sprintf(xtra, "Findfirst ");
802 		xtra += length;
803 		data += 12;
804 		(void) unicode2ascii(filename, 256, data, 512);
805 		sprintf(xtra, "File=%s ", filename);
806 	}
807 
808 	if (flags & F_DTAIL) {
809 		sprintf(GETLINE, "FunctionName = Findfirst");
810 		sprintf(GETLINE, "SearchAttributes = 0x%.4x",
811 			get2(data));
812 		data += 2;
813 		sprintf(GETLINE, "FindCount = 0x%.4x",
814 			get2(data));
815 		data += 2;
816 		sprintf(GETLINE, "FindFlags = 0x%.4x",
817 			get2(data));
818 		data += 2;
819 		get_info_level(infolevel, get2(data));
820 		sprintf(GETLINE, "InfoLevel = %s",
821 			infolevel);
822 		data += 6;
823 		(void) unicode2ascii(filename, 256, data, 512);
824 		sprintf(GETLINE, "FileName = %s",
825 			filename);
826 	}
827 }
828 
829 
830 /*
831  * Interpret TRANS2_FIND_NEXT subcommand
832  * [X/Open-SMB, Sec. 16.4]
833  */
834 /* ARGSUSED */
835 static void
836 output_trans2_findnext(int flags, uchar_t *data, char *xtra)
837 {
838 	int length;
839 	char filename[256];
840 	char infolevel[100];
841 
842 	if (flags & F_SUM) {
843 		length = sprintf(xtra, "Findnext ");
844 		xtra += length;
845 		data += 12;
846 		(void) unicode2ascii(filename, 256, data, 512);
847 		sprintf(xtra, "File=%s ", filename);
848 	}
849 
850 	if (flags & F_DTAIL) {
851 		sprintf(GETLINE, "FunctionName = Findnext");
852 		sprintf(GETLINE, "FileID = 0x%.4x",
853 			get2(data));
854 		data += 2;
855 		sprintf(GETLINE, "FindCount = 0x%.4x",
856 			get2(data));
857 		data += 2;
858 		get_info_level(infolevel, get2(data));
859 		sprintf(GETLINE, "InfoLevel = %s",
860 			infolevel);
861 		data += 2;
862 		sprintf(GETLINE, "FindKey = 0x%.8x",
863 			get4(data));
864 		data += 4;
865 		sprintf(GETLINE, "FindFlags = 0x%.4x",
866 			get2(data));
867 		data += 2;
868 		(void) unicode2ascii(filename, 256, data, 512);
869 		sprintf(GETLINE, "FileName = %s",
870 			filename);
871 	}
872 }
873 
874 /*
875  * Interpret a "Negprot" SMB
876  * [X/Open-SMB, Sec. 6.1]
877  */
878 /* ARGSUSED */
879 static void
880 interpret_negprot(int flags, uchar_t *data, int len, char *xtra)
881 {
882 	int length;
883 	int bytecount;
884 	char dialect[256];
885 	struct smb *smbdata;
886 	uchar_t *protodata;
887 
888 	smbdata  = (struct smb *)data;
889 	protodata = (uchar_t *)data + sizeof (struct smb);
890 	protodata++;			/* skip wordcount */
891 
892 	if (smbdata->flags & SERVER_RESPONSE) {
893 		if (flags & F_SUM) {
894 			sprintf(xtra, "Dialect#=%d ", protodata[0]);
895 		}
896 		if (flags & F_DTAIL) {
897 			sprintf(GETLINE, "Protocol Index = %d",
898 					protodata[0]);
899 		}
900 	} else {
901 		/*
902 		 * request packet:
903 		 * short bytecount;
904 		 * struct { char fmt; char name[]; } dialects
905 		 */
906 		bytecount = get2(protodata);
907 		protodata += 2;
908 		if (flags & F_SUM) {
909 			while (bytecount > 1) {
910 				length = sprintf(dialect, (char *)protodata+1);
911 				protodata += (length+2);
912 				bytecount -= (length+2);
913 			}
914 			sprintf(xtra, "LastDialect=%s ", dialect);
915 		}
916 		if (flags & F_DTAIL) {
917 			sprintf(GETLINE, "ByteCount = %d", bytecount);
918 			while (bytecount > 1) {
919 				length = sprintf(dialect, (char *)protodata+1);
920 				sprintf(GETLINE, "Dialect String = %s",
921 						dialect);
922 				protodata += (length+2);
923 				bytecount -= (length+2);
924 			}
925 		}
926 	}
927 }
928 
929 /*
930  * LAN Manager remote admin function names.
931  * [X/Open-SMB, Appendix B.8]
932  */
933 static const char *apinames[] = {
934 	"RNetShareEnum",
935 	"RNetShareGetInfo",
936 	"NetShareSetInfo",
937 	"NetShareAdd",
938 	"NetShareDel",
939 	"NetShareCheck",
940 	"NetSessionEnum",
941 	"NetSessionGetInfo",
942 	"NetSessionDel",
943 	"NetConnectionEnum",
944 	"NetFileEnum",
945 	"NetFileGetInfo",
946 	"NetFileClose",
947 	"RNetServerGetInfo",
948 	"NetServerSetInfo",
949 	"NetServerDiskEnum",
950 	"NetServerAdminCommand",
951 	"NetAuditOpen",
952 	"NetAuditClear",
953 	"NetErrorLogOpen",
954 	"NetErrorLogClear",
955 	"NetCharDevEnum",
956 	"NetCharDevGetInfo",
957 	"NetCharDevControl",
958 	"NetCharDevQEnum",
959 	"NetCharDevQGetInfo",
960 	"NetCharDevQSetInfo",
961 	"NetCharDevQPurge",
962 	"RNetCharDevQPurgeSelf",
963 	"NetMessageNameEnum",
964 	"NetMessageNameGetInfo",
965 	"NetMessageNameAdd",
966 	"NetMessageNameDel",
967 	"NetMessageNameFwd",
968 	"NetMessageNameUnFwd",
969 	"NetMessageBufferSend",
970 	"NetMessageFileSend",
971 	"NetMessageLogFileSet",
972 	"NetMessageLogFileGet",
973 	"NetServiceEnum",
974 	"RNetServiceInstall",
975 	"RNetServiceControl",
976 	"RNetAccessEnum",
977 	"RNetAccessGetInfo",
978 	"RNetAccessSetInfo",
979 	"RNetAccessAdd",
980 	"RNetAccessDel",
981 	"NetGroupEnum",
982 	"NetGroupAdd",
983 	"NetGroupDel",
984 	"NetGroupAddUser",
985 	"NetGroupDelUser",
986 	"NetGroupGetUsers",
987 	"NetUserEnum",
988 	"RNetUserAdd",
989 	"NetUserDel",
990 	"NetUserGetInfo",
991 	"RNetUserSetInfo",
992 	"RNetUserPasswordSet",
993 	"NetUserGetGroups",
994 	"NetWkstaLogon",
995 	"NetWkstaLogoff",
996 	"NetWkstaSetUID",
997 	"NetWkstaGetInfo",
998 	"NetWkstaSetInfo",
999 	"NetUseEnum",
1000 	"NetUseAdd",
1001 	"NetUseDel",
1002 	"NetUseGetInfo",
1003 	"DosPrintQEnum",
1004 	"DosPrintQGetInfo",
1005 	"DosPrintQSetInfo",
1006 	"DosPrintQAdd",
1007 	"DosPrintQDel",
1008 	"DosPrintQPause",
1009 	"DosPrintQContinue",
1010 	"DosPrintJobEnum",
1011 	"DosPrintJobGetInfo",
1012 	"RDosPrintJobSetInfo",
1013 	"DosPrintJobAdd",
1014 	"DosPrintJobSchedule",
1015 	"RDosPrintJobDel",
1016 	"RDosPrintJobPause",
1017 	"RDosPrintJobContinue",
1018 	"DosPrintDestEnum",
1019 	"DosPrintDestGetInfo",
1020 	"DosPrintDestControl",
1021 	"NetProfileSave",
1022 	"NetProfileLoad",
1023 	"NetStatisticsGet",
1024 	"NetStatisticsClear",
1025 	"NetRemoteTOD",
1026 	"NetBiosEnum",
1027 	"NetBiosGetInfo",
1028 	"NetServerEnum",
1029 	"I_NetServerEnum",
1030 	"NetServiceGetInfo",
1031 	"NetSplQmAbort",
1032 	"NetSplQmClose",
1033 	"NetSplQmEndDoc",
1034 	"NetSplQmOpen",
1035 	"NetSplQmStartDoc",
1036 	"NetSplQmWrite",
1037 	"DosPrintQPurge",
1038 	"NetServerEnum2"
1039 };
1040 static const int apimax = (
1041 	sizeof (apinames) /
1042 	sizeof (apinames[0]));
1043 
1044 /*
1045  * Interpret a "trans" SMB
1046  * [X/Open-SMB, Appendix B]
1047  *
1048  * This is very much like "trans2" below.
1049  */
1050 /* ARGSUSED */
1051 static void
1052 interpret_trans(int flags, uchar_t *data, int len, char *xtra)
1053 {
1054 	struct smb *smb;
1055 	uchar_t *vwv; /* word parameters */
1056 	int wordcount;
1057 	uchar_t *byteparms;
1058 	int bytecount;
1059 	int parambytes;
1060 	int paramoffset;
1061 	int setupcount;
1062 	int subcode;
1063 	uchar_t *setupdata;
1064 	uchar_t *params;
1065 	int apinum;
1066 	int isunicode;
1067 	char filename[256];
1068 
1069 	smb  = (struct smb *)data;
1070 	vwv = (uchar_t *)data + sizeof (struct smb);
1071 	wordcount = *vwv++;
1072 
1073 	byteparms = vwv + (2 * wordcount);
1074 	bytecount = get2(byteparms);
1075 	byteparms += 2;
1076 
1077 	/*
1078 	 * Print the lengths before we (potentially) bail out
1079 	 * due to lack of data (so the user knows why we did).
1080 	 */
1081 	if (flags & F_DTAIL) {
1082 		sprintf(GETLINE, "WordCount = %d", wordcount);
1083 		sprintf(GETLINE, "ByteCount = %d", bytecount);
1084 	}
1085 
1086 	/* Get length and location of params and setup data. */
1087 	if (!(smb->flags & SERVER_RESPONSE)) {
1088 		/* CALL */
1089 		if (wordcount < 14)
1090 			return;
1091 		parambytes  = get2(vwv + (2 *  9));
1092 		paramoffset = get2(vwv + (2 * 10));
1093 		setupcount = *(vwv + (2 * 13));
1094 		setupdata  =   vwv + (2 * 14);
1095 	} else {
1096 		/* REPLY */
1097 		if (wordcount < 10)
1098 			return;
1099 		parambytes  = get2(vwv + (2 * 3));
1100 		paramoffset = get2(vwv + (2 * 4));
1101 		setupcount = *(vwv + (2 *  9));
1102 		setupdata  =   vwv + (2 * 10);
1103 	}
1104 	if (setupcount > 0)
1105 		subcode = get2(setupdata);
1106 	else
1107 		subcode = -1; /* invalid */
1108 
1109 	/* The parameters are offset from the SMB header. */
1110 	params = data + paramoffset;
1111 	if (parambytes > 0)
1112 		apinum = params[0];
1113 	else
1114 		apinum = -1; /* invalid */
1115 
1116 	/* Is the pathname in unicode? */
1117 	isunicode = smb->flags2[1] & 0x80;
1118 
1119 	if (flags & F_DTAIL && !(smb->flags & SERVER_RESPONSE)) {
1120 		/* This is a CALL. */
1121 		/* print the word parameters */
1122 		sprintf(GETLINE, "TotalParamBytes = %d", get2(vwv));
1123 		sprintf(GETLINE, "TotalDataBytes = %d", get2(vwv+2));
1124 		sprintf(GETLINE, "MaxParamBytes = %d", get2(vwv+4));
1125 		sprintf(GETLINE, "MaxDataBytes = %d", get2(vwv+6));
1126 		sprintf(GETLINE, "MaxSetupWords = %d", vwv[8]);
1127 		sprintf(GETLINE, "TransFlags = 0x%.4x", get2(vwv+10));
1128 		sprintf(GETLINE, "Timeout = 0x%.8x", get4(vwv+12));
1129 		/* skip Reserved2 */
1130 		sprintf(GETLINE, "ParamBytes = 0x%.4x", parambytes);
1131 		sprintf(GETLINE, "ParamOffset = 0x%.4x", paramoffset);
1132 		sprintf(GETLINE, "DataBytes = 0x%.4x", get2(vwv+22));
1133 		sprintf(GETLINE, "DataOffset = 0x%.4x", get2(vwv+24));
1134 		sprintf(GETLINE, "SetupWords = %d", setupcount);
1135 
1136 		/* That finishes the VWV, now the misc. stuff. */
1137 		if (subcode >= 0)
1138 			sprintf(GETLINE, "Setup[0] = %d", subcode);
1139 		if (apinum >= 0)
1140 			sprintf(GETLINE, "APIcode = %d", apinum);
1141 		if (0 <= apinum && apinum < apimax)
1142 			sprintf(GETLINE, "APIname = %s", apinames[apinum]);
1143 
1144 		/* Finally, print the byte parameters. */
1145 		if (isunicode) {
1146 			byteparms += 1;  /* alignment padding */
1147 			(void) unicode2ascii(
1148 				filename, 256, byteparms, bytecount);
1149 		} else {
1150 			strcpy(filename, (char *)byteparms);
1151 		}
1152 		sprintf(GETLINE, "FileName = %s", filename);
1153 	}
1154 
1155 	if (flags & F_DTAIL && smb->flags & SERVER_RESPONSE) {
1156 		/* This is a REPLY. */
1157 		/* print the word parameters */
1158 		sprintf(GETLINE, "TotalParamBytes = %d", get2(vwv));
1159 		sprintf(GETLINE, "TotalDataBytes = %d", get2(vwv+2));
1160 		/* skip Reserved */
1161 		sprintf(GETLINE, "ParamBytes = 0x%.4x", parambytes);
1162 		sprintf(GETLINE, "ParamOffset = 0x%.4x", paramoffset);
1163 		sprintf(GETLINE, "ParamDispl. = 0x%.4x", get2(vwv+10));
1164 		sprintf(GETLINE, "DataBytes = 0x%.4x", get2(vwv+12));
1165 		sprintf(GETLINE, "DataOffset = 0x%.4x", get2(vwv+14));
1166 		sprintf(GETLINE, "DataDispl. = 0x%.4x", get2(vwv+16));
1167 		sprintf(GETLINE, "SetupWords = %d", setupcount);
1168 
1169 		output_bytes(byteparms, bytecount);
1170 	}
1171 }
1172 
1173 /*
1174  * Interpret a "TconX" SMB
1175  * [X/Open-SMB, Sec. 11.4]
1176  */
1177 /* ARGSUSED */
1178 static void
1179 interpret_tconX(int flags, uchar_t *data, int len, char *xtra)
1180 {
1181 	int length;
1182 	int bytecount;
1183 	int passwordlength;
1184 	int wordcount;
1185 	char tempstring[256];
1186 	struct smb *smbdata;
1187 	uchar_t *tcondata;
1188 
1189 	smbdata  = (struct smb *)data;
1190 	tcondata = (uchar_t *)data + sizeof (struct smb);
1191 	wordcount = *tcondata++;
1192 
1193 	if (flags & F_SUM && !(smbdata->flags & SERVER_RESPONSE)) {
1194 		tcondata += 6;
1195 		passwordlength = get2(tcondata);
1196 		tcondata = tcondata + 4 + passwordlength;
1197 		length = sprintf(tempstring, (char *)tcondata);
1198 		sprintf(xtra, "Share=%s ", tempstring);
1199 	}
1200 
1201 	if (flags & F_SUM && smbdata->flags & SERVER_RESPONSE) {
1202 		tcondata += 8;
1203 		length = sprintf(tempstring, (char *)tcondata);
1204 		sprintf(xtra, "Type=%s ", tempstring);
1205 	}
1206 
1207 	if (flags & F_DTAIL && !(smbdata->flags & SERVER_RESPONSE)) {
1208 		sprintf(GETLINE, "WordCount = %d", wordcount);
1209 		sprintf(GETLINE, "ChainedCommand = 0x%.2x",
1210 			tcondata[0]);
1211 		tcondata += 2;
1212 		sprintf(GETLINE, "NextOffset = 0x%.4x",
1213 			get2(tcondata));
1214 		tcondata += 2;
1215 		sprintf(GETLINE, "DisconnectFlag = 0x%.4x",
1216 			get2(tcondata));
1217 		tcondata += 2;
1218 		passwordlength = get2(tcondata);
1219 		sprintf(GETLINE, "PasswordLength = 0x%.4x",
1220 			passwordlength);
1221 		tcondata += 2;
1222 		bytecount = get2(tcondata);
1223 		sprintf(GETLINE, "ByteCount = %d", bytecount);
1224 		tcondata = tcondata + 2 + passwordlength;
1225 		length = sprintf(tempstring, (char *)tcondata);
1226 		tcondata += (length+1);
1227 		sprintf(GETLINE, "FileName = %s", tempstring);
1228 		length = sprintf(tempstring, (char *)tcondata);
1229 		tcondata += (length+1);
1230 		sprintf(GETLINE, "ServiceName = %s", tempstring);
1231 	}
1232 
1233 	if (flags & F_DTAIL && smbdata->flags & SERVER_RESPONSE) {
1234 		sprintf(GETLINE, "WordCount = %d", wordcount);
1235 		sprintf(GETLINE, "ChainedCommand = 0x%.2x",
1236 			tcondata[0]);
1237 		tcondata += 2;
1238 		sprintf(GETLINE, "NextOffset = 0x%.4x",
1239 			get2(tcondata));
1240 		tcondata += 2;
1241 		sprintf(GETLINE, "OptionalSupport = 0x%.4x",
1242 			get2(tcondata));
1243 		tcondata += 2;
1244 		bytecount = get2(tcondata);
1245 		sprintf(GETLINE, "ByteCount = %d", bytecount);
1246 		tcondata += 2;
1247 		length = sprintf(tempstring, (char *)tcondata);
1248 		tcondata += (length+1);
1249 		sprintf(GETLINE, "ServiceName = %s", tempstring);
1250 		length = sprintf(tempstring, (char *)tcondata);
1251 		tcondata += (length+1);
1252 		sprintf(GETLINE, "NativeFS = %s", tempstring);
1253 	}
1254 }
1255 
1256 /*
1257  * Interpret a "SesssetupX" SMB
1258  * [X/Open-SMB, Sec. 11.3]
1259  */
1260 /* ARGSUSED */
1261 static void
1262 interpret_sesssetupX(int flags, uchar_t *data, int len, char *xtra)
1263 {
1264 	int length;
1265 	int bytecount;
1266 	int passwordlength;
1267 	int isunicode;
1268 	int upasswordlength;
1269 	int wordcount;
1270 	int cap;
1271 	char tempstring[256];
1272 	struct smb *smbdata;
1273 	uchar_t *setupdata;
1274 
1275 	smbdata  = (struct smb *)data;
1276 	setupdata = (uchar_t *)data + sizeof (struct smb);
1277 	wordcount = *setupdata++;
1278 
1279 	isunicode = smbdata->flags2[1] & 0x80;
1280 
1281 	if (flags & F_SUM && !(smbdata->flags & SERVER_RESPONSE)) {
1282 		if (wordcount != 13)
1283 			return;
1284 		setupdata += 14;
1285 		passwordlength = get2(setupdata);
1286 		setupdata += 2;
1287 		upasswordlength = get2(setupdata);
1288 		setupdata += 6;
1289 		cap = get4(setupdata);
1290 		setupdata = setupdata + 6 + passwordlength + upasswordlength;
1291 		if (isunicode) {
1292 			setupdata += 1;
1293 			(void) unicode2ascii(tempstring, 256, setupdata, 256);
1294 			sprintf(xtra, "Username=%s ", tempstring);
1295 		} else {
1296 			length = sprintf(tempstring, (char *)setupdata);
1297 			sprintf(xtra, "Username=%s ", tempstring);
1298 		}
1299 	}
1300 
1301 	if (flags & F_DTAIL && !(smbdata->flags & SERVER_RESPONSE)) {
1302 		if (wordcount != 13)
1303 			return;
1304 		sprintf(GETLINE, "ChainedCommand = 0x%.2x",
1305 			setupdata[0]);
1306 		setupdata += 2;
1307 		sprintf(GETLINE, "NextOffset = 0x%.4x",
1308 			get2(setupdata));
1309 		setupdata += 2;
1310 		sprintf(GETLINE, "MaxBufferSize = 0x%.4x",
1311 			get2(setupdata));
1312 		setupdata += 2;
1313 		sprintf(GETLINE, "MaxMPXRequests = %d",
1314 			get2(setupdata));
1315 		setupdata += 2;
1316 		sprintf(GETLINE, "VCNumber = %d",
1317 			get2(setupdata));
1318 		setupdata += 2;
1319 		sprintf(GETLINE, "SessionKey = %d",
1320 			get4(setupdata));
1321 		setupdata += 4;
1322 		passwordlength = get2(setupdata);
1323 		sprintf(GETLINE, "PasswordLength = 0x%.4x",
1324 			passwordlength);
1325 		setupdata += 2;
1326 		upasswordlength = get2(setupdata);
1327 		sprintf(GETLINE, "UnicodePasswordLength = 0x%.4x",
1328 			upasswordlength);
1329 		setupdata += 6;
1330 		cap = get4(setupdata);
1331 		sprintf(GETLINE, "Capabilities = 0x%0.8x", cap);
1332 		setupdata += 4;
1333 		bytecount = get2(setupdata);
1334 		sprintf(GETLINE, "ByteCount = %d", bytecount);
1335 		setupdata = setupdata + 2 + passwordlength + upasswordlength;
1336 		if (isunicode) {
1337 			setupdata++;
1338 			length = 2*unicode2ascii(
1339 				tempstring, 256, setupdata, 256);
1340 			if (length == 2) {
1341 				sprintf(GETLINE,
1342 						"AccountName = %s", tempstring);
1343 				sprintf(GETLINE,
1344 						"DomainName = %s", tempstring);
1345 				setupdata += 3;
1346 			} else {
1347 				setupdata += length;
1348 				sprintf(GETLINE,
1349 						"AccountName = %s", tempstring);
1350 				length = 2*unicode2ascii(
1351 					tempstring, 256, setupdata, 256);
1352 				setupdata += length;
1353 				sprintf(GETLINE,
1354 						"DomainName = %s", tempstring);
1355 			}
1356 			length = 2*unicode2ascii(
1357 				tempstring, 256, setupdata, 256);
1358 			setupdata += (length+2);
1359 			sprintf(GETLINE,
1360 					"NativeOS = %s", tempstring);
1361 			length = 2*unicode2ascii(
1362 				tempstring, 256, setupdata, 256);
1363 			sprintf(GETLINE,
1364 					"NativeLanman = %s", tempstring);
1365 		} else {
1366 			length = sprintf(tempstring, (char *)setupdata);
1367 			setupdata += (length+1);
1368 			sprintf(GETLINE, "AccountName = %s", tempstring);
1369 			length = sprintf(tempstring, (char *)setupdata);
1370 			setupdata += (length+1);
1371 			sprintf(GETLINE, "DomainName = %s", tempstring);
1372 			length = sprintf(tempstring, (char *)setupdata);
1373 			setupdata += (length+1);
1374 			sprintf(GETLINE, "NativeOS = %s", tempstring);
1375 			sprintf(tempstring, (char *)setupdata);
1376 			sprintf(GETLINE, "NativeLanman = %s", tempstring);
1377 		}
1378 	}
1379 
1380 	if (flags & F_DTAIL && smbdata->flags & SERVER_RESPONSE) {
1381 		if (wordcount != 3)
1382 			return;
1383 		sprintf(GETLINE, "ChainedCommand = 0x%.2x",
1384 			setupdata[0]);
1385 		setupdata += 2;
1386 		sprintf(GETLINE, "NextOffset = 0x%.4x",
1387 			get2(setupdata));
1388 		setupdata += 2;
1389 		sprintf(GETLINE, "SetupAction = 0x%.4x",
1390 			get2(setupdata));
1391 		setupdata += 2;
1392 		bytecount = get2(setupdata);
1393 		sprintf(GETLINE, "ByteCount = %d", bytecount);
1394 		setupdata += 2;
1395 		length = sprintf(tempstring, (char *)setupdata);
1396 		setupdata += (length+1);
1397 		sprintf(GETLINE, "NativeOS = %s", tempstring);
1398 		length = sprintf(tempstring, (char *)setupdata);
1399 		setupdata += (length+1);
1400 		sprintf(GETLINE, "NativeLanman = %s", tempstring);
1401 		length = sprintf(tempstring, (char *)setupdata);
1402 		sprintf(GETLINE, "DomainName = %s", tempstring);
1403 	}
1404 }
1405 
1406 /*
1407  * Interpret "Trans2" SMB
1408  * [X/Open-SMB, Sec. 16]
1409  *
1410  * This is very much like "trans" above.
1411  */
1412 /* ARGSUSED */
1413 static void
1414 interpret_trans2(int flags, uchar_t *data, int len, char *xtra)
1415 {
1416 	struct smb *smb;
1417 	uchar_t *vwv; /* word parameters */
1418 	int wordcount;
1419 	uchar_t *byteparms;
1420 	int bytecount;
1421 	int parambytes;
1422 	int paramoffset;
1423 	int setupcount;
1424 	int subcode;
1425 	uchar_t *setupdata;
1426 	uchar_t *params;
1427 	char *name;
1428 
1429 	smb  = (struct smb *)data;
1430 	vwv = (uchar_t *)data + sizeof (struct smb);
1431 	wordcount = *vwv++;
1432 
1433 	byteparms = vwv + (2 * wordcount);
1434 	bytecount = get2(byteparms);
1435 	byteparms += 2;
1436 
1437 	/*
1438 	 * Print the lengths before we (potentially) bail out
1439 	 * due to lack of data (so the user knows why we did).
1440 	 */
1441 	if (flags & F_DTAIL) {
1442 		sprintf(GETLINE, "WordCount = %d", wordcount);
1443 		sprintf(GETLINE, "ByteCount = %d", bytecount);
1444 	}
1445 
1446 	/* Get length and location of params and setup data. */
1447 	if (!(smb->flags & SERVER_RESPONSE)) {
1448 		/* CALL */
1449 		if (wordcount < 14)
1450 			return;
1451 		parambytes  = get2(vwv + (2 *  9));
1452 		paramoffset = get2(vwv + (2 * 10));
1453 		setupcount = *(vwv + (2 * 13));
1454 		setupdata  =   vwv + (2 * 14);
1455 	} else {
1456 		/* REPLY */
1457 		if (wordcount < 10)
1458 			return;
1459 		parambytes  = get2(vwv + (2 * 3));
1460 		paramoffset = get2(vwv + (2 * 4));
1461 		setupcount = *(vwv + (2 *  9));
1462 		setupdata  =   vwv + (2 * 10);
1463 	}
1464 	if (setupcount > 0)
1465 		subcode = get2(setupdata);
1466 	else
1467 		subcode = -1; /* invalid */
1468 
1469 	/* The parameters are offset from the SMB header. */
1470 	params = data + paramoffset;
1471 
1472 	if (flags & F_DTAIL && !(smb->flags & SERVER_RESPONSE)) {
1473 		/* This is a CALL. */
1474 		/* print the word parameters */
1475 		sprintf(GETLINE, "TotalParamBytes = %d", get2(vwv));
1476 		sprintf(GETLINE, "TotalDataBytes = %d", get2(vwv+2));
1477 		sprintf(GETLINE, "MaxParamBytes = %d", get2(vwv+4));
1478 		sprintf(GETLINE, "MaxDataBytes = %d", get2(vwv+6));
1479 		sprintf(GETLINE, "MaxSetupWords = %d", vwv[8]);
1480 		sprintf(GETLINE, "TransFlags = 0x%.4x", get2(vwv+10));
1481 		sprintf(GETLINE, "Timeout = 0x%.8x", get4(vwv+12));
1482 		/* skip Reserved2 */
1483 		sprintf(GETLINE, "ParamBytes = 0x%.4x", parambytes);
1484 		sprintf(GETLINE, "ParamOffset = 0x%.4x", paramoffset);
1485 		sprintf(GETLINE, "DataBytes = 0x%.4x", get2(vwv+22));
1486 		sprintf(GETLINE, "DataOffset = 0x%.4x", get2(vwv+24));
1487 		sprintf(GETLINE, "SetupWords = %d", setupcount);
1488 
1489 		/* That finishes the VWV, now the misc. stuff. */
1490 		sprintf(GETLINE, "FunctionCode = %d", subcode);
1491 	}
1492 
1493 	if (!(smb->flags & SERVER_RESPONSE)) {
1494 		/* This is a CALL.  Do sub-function. */
1495 		switch (subcode) {
1496 		case TRANS2_OPEN:
1497 			name = "Open";
1498 			goto name_only;
1499 		case TRANS2_FIND_FIRST:
1500 			output_trans2_findfirst(flags, params, xtra);
1501 			break;
1502 		case TRANS2_FIND_NEXT2:
1503 			output_trans2_findnext(flags, params, xtra);
1504 			break;
1505 		case TRANS2_QUERY_FS_INFORMATION:
1506 			name = "QueryFSInfo";
1507 			goto name_only;
1508 		case TRANS2_QUERY_PATH_INFORMATION:
1509 			output_trans2_querypath(flags, params, xtra);
1510 			break;
1511 		case TRANS2_SET_PATH_INFORMATION:
1512 			name = "SetPathInfo";
1513 			goto name_only;
1514 		case TRANS2_QUERY_FILE_INFORMATION:
1515 			output_trans2_queryfile(flags, params, xtra);
1516 			break;
1517 		case TRANS2_SET_FILE_INFORMATION:
1518 			output_trans2_setfile(flags, params, xtra);
1519 			break;
1520 		case TRANS2_CREATE_DIRECTORY:
1521 			name = "CreateDir";
1522 			goto name_only;
1523 
1524 		default:
1525 			name = "Unknown";
1526 			/* fall through */
1527 		name_only:
1528 			if (flags & F_SUM)
1529 				sprintf(xtra, "%s ", name);
1530 			if (flags & F_DTAIL)
1531 				sprintf(GETLINE, "FunctionName = %s", name);
1532 			break;
1533 		}
1534 	}
1535 
1536 	if (flags & F_DTAIL && smb->flags & SERVER_RESPONSE) {
1537 		/* This is a REPLY. */
1538 		/* print the word parameters */
1539 		sprintf(GETLINE, "TotalParamBytes = %d", get2(vwv));
1540 		sprintf(GETLINE, "TotalDataBytes = %d",  get2(vwv+2));
1541 		/* skip Reserved */
1542 		sprintf(GETLINE, "ParamBytes = 0x%.4x", parambytes);
1543 		sprintf(GETLINE, "ParamOffset = 0x%.4x", paramoffset);
1544 		sprintf(GETLINE, "ParamDispl. = 0x%.4x", get2(vwv+10));
1545 		sprintf(GETLINE, "DataBytes = 0x%.4x", get2(vwv+12));
1546 		sprintf(GETLINE, "DataOffset = 0x%.4x", get2(vwv+14));
1547 		sprintf(GETLINE, "DataDispl. = 0x%.4x", get2(vwv+16));
1548 		sprintf(GETLINE, "SetupWords = %d", setupcount);
1549 
1550 		output_bytes(byteparms, bytecount);
1551 	}
1552 }
1553 
1554 
1555 static void
1556 interpret_default(int flags, uchar_t *data, int len, char *xtra)
1557 {
1558 	int slength;
1559 	int i;
1560 	int printit;
1561 	int wordcount;
1562 	char *outstr;
1563 	char *prfmt;
1564 	char *format;
1565 	char valuetype;
1566 	char word[10];
1567 	char *label;
1568 	char tempstring[256];
1569 	uchar_t *comdata, *limit;
1570 	char buff[80];
1571 	struct smb *smbdata;
1572 	struct decode *decoder;
1573 
1574 	smbdata  = (struct smb *)data;
1575 	comdata = (uchar_t *)data + sizeof (struct smb);
1576 	wordcount = *comdata++;
1577 	limit = data + len;
1578 
1579 	decoder = &SMBtable[smbdata->com & 255];
1580 
1581 	if (smbdata->flags & SERVER_RESPONSE)
1582 		format = decoder->replyfmt;
1583 	else
1584 		format = decoder->callfmt;
1585 
1586 	if (!format || strlen(format) == 0) {
1587 		if (wordcount == 0 || flags & F_SUM)
1588 			return;
1589 		sprintf(GETLINE, "WordCount = %d", wordcount);
1590 		sprintf(GETLINE, "Word values (in hex):");
1591 		for (i = 0; i < wordcount; i++) {
1592 			sprintf(word, "%.4x ", get2(comdata));
1593 			comdata += 2;
1594 			if (comdata >= limit)
1595 				wordcount = i+1; /* terminate */
1596 			strcat(buff, word);
1597 			if (((i+1) & 7) == 0 || i == (wordcount-1)) {
1598 				sprintf(GETLINE, "%s", buff);
1599 				strcpy(buff, "");
1600 			}
1601 		}
1602 		return;
1603 	}
1604 
1605 
1606 	valuetype = format[0];
1607 	while (valuetype != '\0') {
1608 		if (comdata >= limit)
1609 			break;
1610 		if ((flags & F_DTAIL) && valuetype != 'r' && valuetype != 'R')
1611 			outstr = GETLINE;
1612 		else
1613 			outstr = xtra + strlen(xtra);
1614 		label = format+1;
1615 		printit = (flags & F_DTAIL) || (valuetype <= 'Z');
1616 
1617 		switch (valuetype) {
1618 		case 'W':
1619 		case 'w':
1620 			prfmt = (flags & F_DTAIL) ? "%s = 0x%.4x" : "%s=0x%x ";
1621 			if (printit)
1622 				sprintf(outstr, prfmt, label, get2(comdata));
1623 			comdata += 2;
1624 			break;
1625 		case 'D':
1626 		case 'd':
1627 			prfmt = (flags & F_DTAIL) ? "%s = %d" : "%s=%d ";
1628 			if (printit)
1629 				sprintf(outstr, prfmt, label, get2(comdata));
1630 			comdata += 2;
1631 			break;
1632 		case 'L':
1633 		case 'l':
1634 			prfmt = (flags & F_DTAIL) ? "%s = 0x%.8x" : "%s=0x%x ";
1635 			if (printit)
1636 				sprintf(outstr, prfmt, label, get4(comdata));
1637 			comdata += 4;
1638 			break;
1639 		case 'B':
1640 		case 'b':
1641 			prfmt = (flags & F_DTAIL) ? "%s = 0x%.2x" : "%s=0x%x ";
1642 			if (printit)
1643 				sprintf(outstr, prfmt, label, comdata[0]);
1644 			comdata += 1;
1645 			break;
1646 		case 'r':
1647 			comdata++;
1648 			break;
1649 		case 'R':
1650 			comdata += 2;
1651 			break;
1652 		case 'U':
1653 		case 'u':
1654 			prfmt = (flags & F_DTAIL) ? "%s = %s" : "%s=%s ";
1655 			slength = unicode2ascii(tempstring, 256, comdata, 256);
1656 			if (printit)
1657 				sprintf(outstr, prfmt, label, tempstring);
1658 			comdata +=  (slength*2 + 1);
1659 			break;
1660 		case 'S':
1661 		case 's':
1662 			prfmt = (flags & F_DTAIL) ? "%s = %s" : "%s=%s ";
1663 			slength = sprintf(tempstring, (char *)comdata);
1664 			if (printit)
1665 				sprintf(outstr, prfmt, label, tempstring);
1666 			comdata += (slength+1);
1667 			break;
1668 		}
1669 		format += (strlen(format) + 1);
1670 		valuetype = format[0];
1671 	}
1672 }
1673