Home | History | Annotate | Download | only in snoop
      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