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