/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */ /* * References used throughout this code: * * [CIFS/1.0] : A Common Internet File System (CIFS/1.0) Protocol * Internet Engineering Task Force (IETF) draft * Paul J. Leach, Microsoft, Dec. 1997 * * [X/Open-SMB] : X/Open CAE Specification; * Protocols for X/Open PC Interworking: SMB, Version 2 * X/Open Document Number: C209 */ #include #include #include #include #include #include "snoop.h" /* * SMB Format (header) * [X/Open-SMB, Sec. 5.1] */ struct smb { uchar_t idf[4]; /* identifier, contains 0xff, 'SMB' */ uchar_t com; /* command code */ uchar_t err[4]; /* NT Status, or error class+code */ uchar_t flags; uchar_t flags2[2]; uchar_t re[12]; uchar_t tid[2]; uchar_t pid[2]; uchar_t uid[2]; uchar_t mid[2]; /* * immediately after the above 32 byte header: * unsigned char WordCount; * unsigned short ParameterWords[ WordCount ]; * unsigned short ByteCount; * unsigned char ParameterBytes[ ByteCount ]; */ }; /* smb flags */ #define SERVER_RESPONSE 0x80 /* smb flags2 */ #define FLAGS2_EXT_SEC 0x0800 /* Extended security */ #define FLAGS2_NT_STATUS 0x4000 /* NT status codes */ #define FLAGS2_UNICODE 0x8000 /* String are Unicode */ static void interpret_sesssetupX(int, uchar_t *, int, char *, int); static void interpret_tconX(int, uchar_t *, int, char *, int); static void interpret_trans(int, uchar_t *, int, char *, int); static void interpret_trans2(int, uchar_t *, int, char *, int); static void interpret_negprot(int, uchar_t *, int, char *, int); static void interpret_default(int, uchar_t *, int, char *, int); /* * Trans2 subcommand codes * [X/Open-SMB, Sec. 16.1.7] */ #define TRANS2_OPEN 0x00 #define TRANS2_FIND_FIRST 0x01 #define TRANS2_FIND_NEXT2 0x02 #define TRANS2_QUERY_FS_INFORMATION 0x03 #define TRANS2_QUERY_PATH_INFORMATION 0x05 #define TRANS2_SET_PATH_INFORMATION 0x06 #define TRANS2_QUERY_FILE_INFORMATION 0x07 #define TRANS2_SET_FILE_INFORMATION 0x08 #define TRANS2_CREATE_DIRECTORY 0x0D struct decode { char *name; void (*func)(int, uchar_t *, int, char *, int); char *callfmt; char *replyfmt; }; /* * SMB command codes (function names) * [X/Open-SMB, Sec. 5.2] */ static struct decode SMBtable[256] = { /* 0x00 */ { "mkdir", 0, 0, 0 }, { "rmdir", 0, 0, 0 }, { "open", 0, 0, 0 }, { "create", 0, 0, 0 }, { "close", 0, /* [X/Open-SMB, Sec. 7.10] */ "WFileID\0" "lLastModTime\0" "dByteCount\0\0", "dByteCount\0\0" }, { "flush", 0, 0, 0 }, { "unlink", 0, 0, 0 }, { "move", 0, /* [X/Open-SMB, Sec. 7.11] */ "wFileAttributes\0" "dByteCount\0r\0" "UFileName\0r\0" "UNewPath\0\0", "dByteCount\0\0" }, { "getatr", 0, /* [X/Open-SMB, Sec. 8.4] */ "dBytecount\0r\0" "UFileName\0\0", "wFileAttributes\0" "lTime\0" "lSize\0" "R\0R\0R\0R\0R\0" "dByteCount\0\0" }, { "setatr", 0, 0, 0 }, { "read", 0, /* [X/Open-SMB, Sec. 7.4] */ "WFileID\0" "wI/0 Bytes\0" "LFileOffset\0" "WBytesLeft\0" "dByteCount\0\0", "WDataLength\0" "R\0R\0R\0R\0" "dByteCount\0\0" }, { "write", 0, /* [X/Open-SMB, Sec. 7.5] */ "WFileID\0" "wI/0 Bytes\0" "LFileOffset\0" "WBytesLeft\0" "dByteCount\0\0", "WDataLength\0" "dByteCount\0\0" }, { "lock", 0, 0, 0 }, { "unlock", 0, 0, 0 }, { "ctemp", 0, 0, 0 }, { "mknew", 0, 0, 0 }, /* 0x10 */ { "chkpth", 0, /* [X/Open-SMB, Sec. 8.7] */ "dByteCount\0r\0" "UFile\0\0", "dByteCount\0\0" }, { "exit", 0, 0, 0 }, { "lseek", 0, 0, 0 }, { "lockread", 0, 0, 0 }, { "writeunlock", 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { "readbraw", 0, /* [X/Open-SMB, Sec. 10.1] */ "WFileID\0" "LFileOffset\0" "wMaxCount\0" "wMinCount\0" "lTimeout\0R\0" "dByteCount\0\0", 0 }, { "readbmpx", 0, 0, 0 }, { "readbs", 0, 0, 0 }, { "writebraw", 0, 0, 0 }, { "writebmpx", 0, 0, 0 }, { "writebs", 0, 0, 0 }, /* 0x20 */ { "writec", 0, 0, 0 }, { "qrysrv", 0, 0, 0 }, { "setattrE", 0, 0, 0 }, { "getattrE", 0, 0, 0 }, { "lockingX", 0, /* [X/Open-SMB, Sec. 12.2] */ "wChainedCommand\0" "wNextOffset\0" "WFileID\0" "wLockType\0" "lOpenTimeout\0" "W#Unlocks\0" "W#Locks\0" "dByteCount\0\0", 0 }, { "trans", interpret_trans, 0, 0 }, { "transs", 0, 0, 0 }, { "ioctl", 0, 0, 0 }, { "ioctls", 0, 0, 0 }, { "copy", 0, 0, 0 }, { "move", 0, 0, 0 }, { "echo", 0, 0, 0 }, { "writeclose", 0, 0, 0 }, { /* [X/Open-SMB, Sec. 12.1] */ "openX", 0, /* call */ "wChainedCommand\0" "wNextOffset\0" "wFlags\0" "wMode\0" "wSearchAttributes\0" "wFileAttributes\0" "lTime\0" "wOpenFunction\0" "lFileSize\0" "lOpenTimeout\0R\0R\0" "dByteCount\0r\0" "UFileName\0\0", /* reply */ "wChainedCommand\0" "wNextOffset\0" "WFileID\0" "wAttributes\0" "lTime\0" "LSize\0" "wOpenMode\0" "wFileType\0" "wDeviceState\0" "wActionTaken\0" "lUniqueFileID\0R\0" "wBytecount\0\0" }, { /* [CIFS 4.2.4] */ "readX", 0, /* call */ "wChainedCommand\0" "wNextOffset\0" "WFileID\0" "LOffset\0" "DMaxCount\0" "dMinCount\0" "dMaxCountHigh\0" "R\0" "wRemaining\0" "lOffsetHigh\0" "dByteCount\0\0", /* reply */ "wChainedCommand\0" "wNextOffset\0" "dRemaining\0R\0R\0" "DCount\0" "dDataOffset\0" "dCountHigh\0" "R\0R\0R\0R\0" "dByteCount\0\0" }, { /* [CIFS 4.2.5] */ "writeX", 0, /* call */ "wChainedCommand\0" "wNextOffset\0" "WFileID\0" "LOffset\0R\0R\0" "wWriteMode\0" "wRemaining\0" "dDataLenHigh\0" "DDataLen\0" "dDataOffset\0" "lOffsetHigh\0\0", /* reply */ "wChainedCommand\0" "wNextOffset\0" "DCount\0" "wRemaining\0" "wCountHigh\0\0" }, /* 0x30 */ { 0, 0, 0, 0 }, { "closeTD", 0, 0, 0 }, { "trans2", interpret_trans2, 0, 0 }, { "trans2s", 0, 0, 0 }, { "findclose", 0, /* [X/Open-SMB, Sec. 15.4 ] */ "WFileID\0" "dByteCount\0\0", "dByteCount\0\0" }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0x40 */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0x50 */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0x60 */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0x70 */ { "tcon", 0, 0, 0 }, { "tdis", 0, /* [X/Open-SMB, Sec. 6.3] */ "dByteCount\0\0", "dByteCount\0\0" }, { "negprot", interpret_negprot, 0, 0 }, { "sesssetupX", interpret_sesssetupX, 0, 0 }, { "uloggoffX", 0, /* [X/Open-SMB, Sec. 15.5] */ "wChainedCommand\0" "wNextOffset\0\0", "wChainedCommnad\0" "wNextOffset\0\0" }, { "tconX", interpret_tconX, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0x80 */ { "dskattr", 0, 0, 0 }, { "search", 0, 0, 0 }, { "ffirst", 0, 0, 0 }, { "funique", 0, 0, 0 }, { "fclose", 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0x90 */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0xa0 */ /* * Command codes 0xa0 to 0xa7 are from * [CIFS/1.0, Sec. 5.1] */ { "_NT_Trans", 0, 0, 0 }, { "_NT_Trans2", 0, 0, 0 }, { /* [CIFS/1.0, Sec. 4.2.1] */ "_NT_CreateX", 0, /* Call */ "wChainedCommand\0" "wNextOffset\0r\0" "dNameLength\0" "lCreateFlags\0" "lRootDirFID\0" "lDesiredAccess\0" "lAllocSizeLow\0" "lAllocSizeHigh\0" "lNTFileAttributes\0" "lShareAccess\0" "lOpenDisposition\0" "lCreateOption\0" "lImpersonationLevel\0" "bSecurityFlags\0" "dByteCount\0r\0" "UFileName\0\0", /* Reply */ "wChainedCommand\0" "wNextOffset\0" "bOplockLevel\0" "WFileID\0" "lCreateAction\0\0" }, { 0, 0, 0, 0 }, { "_NT_Cancel", 0, /* [CIFS/1.0, Sec. 4.1.8] */ "dByteCount\0", 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0xb0 */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0xc0 */ { "splopen", 0, 0, 0 }, { "splwr", 0, 0, 0 }, { "splclose", 0, 0, 0 }, { "splretq", 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0xd0 */ { "sends", 0, 0, 0 }, { "sendb", 0, 0, 0 }, { "fwdname", 0, 0, 0 }, { "cancelf", 0, 0, 0 }, { "getmac", 0, 0, 0 }, { "sendstrt", 0, 0, 0 }, { "sendend", 0, 0, 0 }, { "sendtxt", 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0xe0 */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, /* 0xf0 */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; /* Helpers to get values in Intel order (often mis-aligned). */ static uint16_t get2(uchar_t *p) { return (p[0] + (p[1]<<8)); } static uint32_t get4(uchar_t *p) { return (p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24)); } static uint64_t get8(uchar_t *p) { return (get4(p) | ((uint64_t)get4(p+4) << 32)); } /* * Support displaying NT times. * Number of seconds between 1970 and 1601 year * (134774 days) */ static const uint64_t DIFF1970TO1601 = 11644473600ULL; static const uint32_t TEN_MIL = 10000000UL; static char * format_nttime(uint64_t nt_time) { uint64_t nt_sec; /* seconds */ uint64_t nt_tus; /* tenths of uSec. */ uint32_t ux_nsec; int64_t ux_sec; /* Optimize time zero. */ if (nt_time == 0) { ux_sec = 0; ux_nsec = 0; goto out; } nt_sec = nt_time / TEN_MIL; nt_tus = nt_time % TEN_MIL; if (nt_sec <= DIFF1970TO1601) { ux_sec = 0; ux_nsec = 0; goto out; } ux_sec = nt_sec - DIFF1970TO1601; ux_nsec = nt_tus * 100; out: return (format_time(ux_sec, ux_nsec)); } /* * This is called by snoop_netbios.c. * This is the external entry point. */ void interpret_smb(int flags, uchar_t *data, int len) { struct smb *smb; struct decode *decoder; char xtra[MAXLINE]; ushort_t smb_flags2; void (*func)(int, uchar_t *, int, char *, int); if (len < sizeof (struct smb)) return; smb = (struct smb *)data; decoder = &SMBtable[smb->com & 255]; smb_flags2 = get2(smb->flags2); xtra[0] = '\0'; /* * SMB Header description * [X/Open-SMB, Sec. 5.1] */ if (flags & F_DTAIL) { show_header("SMB: ", "SMB Header", len); show_space(); if (smb->flags & SERVER_RESPONSE) show_line("SERVER RESPONSE"); else show_line("CLIENT REQUEST"); if (decoder->name) show_printf("Command code = 0x%x (SMB%s)", smb->com, decoder->name); else show_printf("Command code = 0x%x", smb->com); /* * NT status or error class/code * [X/Open-SMB, Sec. 5.6] */ if (smb_flags2 & FLAGS2_NT_STATUS) { show_printf("NT Status = %x", get4(smb->err)); } else { /* Error classes [X/Open-SMB, Sec. 5.6] */ show_printf("Error class/code = %d/%d", smb->err[0], get2(&smb->err[2])); } show_printf("Flags summary = 0x%.2x", smb->flags); show_printf("Flags2 summary = 0x%.4x", smb_flags2); show_printf("Tree ID (TID) = 0x%.4x", get2(smb->tid)); show_printf("Proc. ID (PID) = 0x%.4x", get2(smb->pid)); show_printf("User ID (UID) = 0x%.4x", get2(smb->uid)); show_printf("Mux. ID (MID) = 0x%.4x", get2(smb->mid)); show_space(); } if ((func = decoder->func) == NULL) func = interpret_default; (*func)(flags, (uchar_t *)data, len, xtra, sizeof (xtra)); if (flags & F_SUM) { char *p; int sz, tl; /* Will advance p and decr. sz */ p = get_sum_line(); sz = MAXLINE; /* Call or Reply */ if (smb->flags & SERVER_RESPONSE) tl = snprintf(p, sz, "SMB R"); else tl = snprintf(p, sz, "SMB C"); p += tl; sz -= tl; /* The name, if known, else the cmd code */ if (decoder->name) { tl = snprintf(p, sz, " Cmd=SMB%s", decoder->name); } else { tl = snprintf(p, sz, " Cmd=0x%02X", smb->com); } p += tl; sz -= tl; /* * The "extra" (cmd-specific summary). * If non-null, has leading blank. */ if (xtra[0] != '\0') { tl = snprintf(p, sz, "%s", xtra); p += tl; sz -= tl; } /* * NT status or error class/code * [X/Open-SMB, Sec. 5.6] * * Only show for response, not call. */ if (smb->flags & SERVER_RESPONSE) { if (smb_flags2 & FLAGS2_NT_STATUS) { uint_t status = get4(smb->err); snprintf(p, sz, " Status=0x%x", status); } else { uchar_t errcl = smb->err[0]; ushort_t code = get2(&smb->err[2]); snprintf(p, sz, " Error=%d/%d", errcl, code); } } } if (flags & F_DTAIL) show_trailer(); } static void output_bytes(uchar_t *data, int bytecount) { int i; char buff[80]; char word[10]; (void) strlcpy(buff, " ", sizeof (buff)); for (i = 0; i < bytecount; i++) { snprintf(word, sizeof (word), "%.2x ", data[i]); (void) strlcat(buff, word, sizeof (buff)); if ((i+1)%16 == 0 || i == (bytecount-1)) { show_line(buff); (void) strlcpy(buff, " ", sizeof (buff)); } } } /* * Based on the Unicode Standard, http://www.unicode.org/ * "The Unicode Standard: A Technical Introduction", June 1998 */ static int unicode2ascii(char *outstr, int outlen, uchar_t *instr, int inlen) { int i = 0, j = 0; char c; while (i < inlen && j < (outlen-1)) { /* Show unicode chars >= 256 as '?' */ if (instr[i+1]) c = '?'; else c = instr[i]; if (c == '\0') break; outstr[j] = c; i += 2; j++; } outstr[j] = '\0'; return (j); } /* * Convenience macro to copy a string from the data, * either in UCS-2 or ASCII as indicated by UCS. * OBUF must be an array type (see sizeof) and * DP must be an L-value (this increments it). */ #define GET_STRING(OBUF, DP, UCS) \ { \ int _len, _sz = sizeof (OBUF); \ if (UCS) { \ if (((uintptr_t)DP) & 1) \ DP++; \ _len = unicode2ascii(OBUF, _sz, DP, 2 * _sz); \ DP += 2 * (_len + 1); \ } else { \ _len = strlcpy(OBUF, (char *)DP, _sz); \ DP += (_len + 1); \ } \ } /* * TRANS2 information levels * [X/Open-SMB, Sec. 16.1.6] */ static void get_info_level(char *outstr, int outsz, int value) { switch (value) { case 1: snprintf(outstr, outsz, "Standard"); break; case 2: snprintf(outstr, outsz, "Query EA Size"); break; case 3: snprintf(outstr, outsz, "Query EAS from List"); break; case 0x101: snprintf(outstr, outsz, "Directory Info"); break; case 0x102: snprintf(outstr, outsz, "Full Directory Info"); break; case 0x103: snprintf(outstr, outsz, "Names Info"); break; case 0x104: snprintf(outstr, outsz, "Both Directory Info"); break; default: snprintf(outstr, outsz, "Unknown"); break; } } /* * Interpret TRANS2_QUERY_PATH subcommand * [X/Open-SMB, Sec. 16.7] */ /* ARGSUSED */ static void output_trans2_querypath(int flags, uchar_t *data, char *xtra, int xsz) { int length; char filename[256]; if (flags & F_SUM) { length = snprintf(xtra, xsz, " QueryPathInfo"); xtra += length; xsz -= length; data += 6; (void) unicode2ascii(filename, 256, data, 512); snprintf(xtra, xsz, " File=%s", filename); } if (flags & F_DTAIL) { show_line("FunctionName = QueryPathInfo"); show_printf("InfoLevel = 0x%.4x", get2(data)); data += 6; (void) unicode2ascii(filename, 256, data, 512); show_printf("FileName = %s", filename); } } /* * Interpret TRANS2_QUERY_FILE subcommand * [X/Open-SMB, Sec. 16.9] */ /* ARGSUSED */ static void output_trans2_queryfile(int flags, uchar_t *data, char *xtra, int xsz) { int length; if (flags & F_SUM) { length = snprintf(xtra, xsz, " QueryFileInfo"); xtra += length; xsz -= length; snprintf(xtra, xsz, " FileID=0x%x", get2(data)); } if (flags & F_DTAIL) { show_line("FunctionName = QueryFileInfo"); show_printf("FileID = 0x%.4x", get2(data)); data += 2; show_printf("InfoLevel = 0x%.4x", get2(data)); } } /* * Interpret TRANS2_SET_FILE subcommand * [X/Open-SMB, Sec. 16.10] */ /* ARGSUSED */ static void output_trans2_setfile(int flags, uchar_t *data, char *xtra, int xsz) { int length; if (flags & F_SUM) { length = snprintf(xtra, xsz, " SetFileInfo"); xtra += length; xsz -= length; snprintf(xtra, xsz, " FileID=0x%x", get2(data)); } if (flags & F_DTAIL) { show_line("FunctionName = SetFileInfo"); show_printf("FileID = 0x%.4x", get2(data)); data += 2; show_printf("InfoLevel = 0x%.4x", get2(data)); } } /* * Interpret TRANS2_FIND_FIRST subcommand * [X/Open-SMB, Sec. 16.3] */ /* ARGSUSED */ static void output_trans2_findfirst(int flags, uchar_t *data, char *xtra, int xsz) { int length; char filename[256]; char infolevel[100]; if (flags & F_SUM) { length = snprintf(xtra, xsz, " Findfirst"); xtra += length; xsz -= length; data += 12; (void) unicode2ascii(filename, 256, data, 512); snprintf(xtra, xsz, " File=%s", filename); } if (flags & F_DTAIL) { show_line("FunctionName = Findfirst"); show_printf("SearchAttributes = 0x%.4x", get2(data)); data += 2; show_printf("FindCount = 0x%.4x", get2(data)); data += 2; show_printf("FindFlags = 0x%.4x", get2(data)); data += 2; get_info_level(infolevel, sizeof (infolevel), get2(data)); show_printf("InfoLevel = %s", infolevel); data += 6; (void) unicode2ascii(filename, 256, data, 512); show_printf("FileName = %s", filename); } } /* * Interpret TRANS2_FIND_NEXT subcommand * [X/Open-SMB, Sec. 16.4] */ /* ARGSUSED */ static void output_trans2_findnext(int flags, uchar_t *data, char *xtra, int xsz) { int length; char filename[256]; char infolevel[100]; if (flags & F_SUM) { length = snprintf(xtra, xsz, " Findnext"); xtra += length; xsz -= length; data += 12; (void) unicode2ascii(filename, 256, data, 512); snprintf(xtra, xsz, " File=%s", filename); } if (flags & F_DTAIL) { show_line("FunctionName = Findnext"); show_printf("FileID = 0x%.4x", get2(data)); data += 2; show_printf("FindCount = 0x%.4x", get2(data)); data += 2; get_info_level(infolevel, sizeof (infolevel), get2(data)); show_printf("InfoLevel = %s", infolevel); data += 2; show_printf("FindKey = 0x%.8x", get4(data)); data += 4; show_printf("FindFlags = 0x%.4x", get2(data)); data += 2; (void) unicode2ascii(filename, 256, data, 512); show_printf("FileName = %s", filename); } } /* * Interpret a "Negprot" SMB * [X/Open-SMB, Sec. 6.1] */ /* ARGSUSED */ static void interpret_negprot(int flags, uchar_t *data, int len, char *xtra, int xsz) { int i, last, length; int bytecount; int key_len; int wordcount; char tbuf[256]; struct smb *smbdata; uchar_t *protodata; uchar_t *byte0; uint64_t nttime; uint32_t caps; ushort_t smb_flags2; smbdata = (struct smb *)data; smb_flags2 = get2(smbdata->flags2); protodata = (uchar_t *)data + sizeof (struct smb); wordcount = *protodata++; if ((smbdata->flags & SERVER_RESPONSE) == 0) { /* * request packet: * short bytecount; * struct { char fmt; char name[]; } dialects */ bytecount = get2(protodata); protodata += 2; byte0 = protodata; if (flags & F_DTAIL) show_printf("ByteCount = %d", bytecount); if (bytecount > len) bytecount = len; /* Walk the list of dialects. */ i = last = 0; tbuf[0] = '\0'; while (protodata < (byte0 + bytecount - 2)) { if (*protodata++ != 2) /* format code */ break; length = strlcpy(tbuf, (char *)protodata, sizeof (tbuf)); protodata += (length + 1); if (flags & F_DTAIL) { show_printf("Dialect[%d] = %s", i, tbuf); } last = i++; } if (flags & F_SUM) { /* * Just print the last dialect, which is * normally the interesting one. */ snprintf(xtra, xsz, " Dialect[%d]=%s", last, tbuf); } } else { /* Parse reply */ if (flags & F_SUM) { snprintf(xtra, xsz, " Dialect#=%d", protodata[0]); } if ((flags & F_DTAIL) == 0) return; if (wordcount < 13) return; show_printf("WordCount = %d", wordcount); show_printf("Dialect Index = %d", protodata[0]); protodata += 2; show_printf("Security Mode = 0x%x", protodata[0]); protodata++; show_printf("MaxMPXRequests = %d", get2(protodata)); protodata += 2; show_printf("MaxVCs = %d", get2(protodata)); protodata += 2; show_printf("MaxBufferSize = %d", get4(protodata)); protodata += 4; show_printf("MaxRawBuffer = %d", get4(protodata)); protodata += 4; show_printf("SessionKey = 0x%.8x", get4(protodata)); protodata += 4; caps = get4(protodata); protodata += 4; show_printf("Capabilities = 0x%.8x", caps); /* Server Time */ nttime = get8(protodata); protodata += 8; show_printf("Server Time = %s", format_nttime(nttime)); show_printf("Server TZ = %d", get2(protodata)); protodata += 2; key_len = *protodata++; show_printf("KeyLength = %d", key_len); bytecount = get2(protodata); protodata += 2; show_printf("ByteCount = %d", bytecount); if (smb_flags2 & FLAGS2_EXT_SEC) { show_printf("Server GUID (16)"); output_bytes(protodata, 16); protodata += 16; show_printf("Security Blob (SPNEGO)"); output_bytes(protodata, bytecount - 16); } else { show_printf("NTLM Challenge: (%d)", key_len); output_bytes(protodata, key_len); protodata += key_len; /* * Get Unicode from capabilities here, * as flags2 typically doesn't have it. * Also, this one is NOT aligned! */ tbuf[0] = '\0'; if (caps & 4) { (void) unicode2ascii(tbuf, sizeof (tbuf), protodata, 2 * sizeof (tbuf)); } else { (void) strlcpy(tbuf, (char *)protodata, sizeof (tbuf)); } show_printf("Server Domain = %s", tbuf); } } } /* * LAN Manager remote admin function names. * [X/Open-SMB, Appendix B.8] */ static const char *apiname_table[] = { "RNetShareEnum", "RNetShareGetInfo", "NetShareSetInfo", "NetShareAdd", "NetShareDel", "NetShareCheck", "NetSessionEnum", "NetSessionGetInfo", "NetSessionDel", "NetConnectionEnum", "NetFileEnum", "NetFileGetInfo", "NetFileClose", "RNetServerGetInfo", "NetServerSetInfo", "NetServerDiskEnum", "NetServerAdminCommand", "NetAuditOpen", "NetAuditClear", "NetErrorLogOpen", "NetErrorLogClear", "NetCharDevEnum", "NetCharDevGetInfo", "NetCharDevControl", "NetCharDevQEnum", "NetCharDevQGetInfo", "NetCharDevQSetInfo", "NetCharDevQPurge", "RNetCharDevQPurgeSelf", "NetMessageNameEnum", "NetMessageNameGetInfo", "NetMessageNameAdd", "NetMessageNameDel", "NetMessageNameFwd", "NetMessageNameUnFwd", "NetMessageBufferSend", "NetMessageFileSend", "NetMessageLogFileSet", "NetMessageLogFileGet", "NetServiceEnum", "RNetServiceInstall", "RNetServiceControl", "RNetAccessEnum", "RNetAccessGetInfo", "RNetAccessSetInfo", "RNetAccessAdd", "RNetAccessDel", "NetGroupEnum", "NetGroupAdd", "NetGroupDel", "NetGroupAddUser", "NetGroupDelUser", "NetGroupGetUsers", "NetUserEnum", "RNetUserAdd", "NetUserDel", "NetUserGetInfo", "RNetUserSetInfo", "RNetUserPasswordSet", "NetUserGetGroups", "NetWkstaLogon", "NetWkstaLogoff", "NetWkstaSetUID", "NetWkstaGetInfo", "NetWkstaSetInfo", "NetUseEnum", "NetUseAdd", "NetUseDel", "NetUseGetInfo", "DosPrintQEnum", "DosPrintQGetInfo", "DosPrintQSetInfo", "DosPrintQAdd", "DosPrintQDel", "DosPrintQPause", "DosPrintQContinue", "DosPrintJobEnum", "DosPrintJobGetInfo", "RDosPrintJobSetInfo", "DosPrintJobAdd", "DosPrintJobSchedule", "RDosPrintJobDel", "RDosPrintJobPause", "RDosPrintJobContinue", "DosPrintDestEnum", "DosPrintDestGetInfo", "DosPrintDestControl", "NetProfileSave", "NetProfileLoad", "NetStatisticsGet", "NetStatisticsClear", "NetRemoteTOD", "NetBiosEnum", "NetBiosGetInfo", "NetServerEnum", "I_NetServerEnum", "NetServiceGetInfo", "NetSplQmAbort", "NetSplQmClose", "NetSplQmEndDoc", "NetSplQmOpen", "NetSplQmStartDoc", "NetSplQmWrite", "DosPrintQPurge", "NetServerEnum2" }; static const int apinum_max = ( sizeof (apiname_table) / sizeof (apiname_table[0])); static const char * pipeapi_name(int code) { char *name; switch (code) { case 0x01: name = "SetNmPipeState"; break; case 0x11: name = "RawReadNmPipe"; break; case 0x21: name = "QueryNmPipeState"; break; case 0x22: name = "QueryNmPipeInfo"; break; case 0x23: name = "PeekNmPipe"; break; case 0x26: name = "XactNmPipe"; break; case 0x31: name = "RawWriteNmPipe"; break; case 0x36: name = "ReadNmPipe"; break; case 0x37: name = "WriteNmPipe"; break; case 0x53: name = "WaitNmPipe"; break; case 0x54: name = "CallNmPipe"; break; default: name = "?"; break; } return (name); } /* * Interpret a "trans" SMB * [X/Open-SMB, Appendix B] * * This is very much like "trans2" below. */ /* ARGSUSED */ static void interpret_trans(int flags, uchar_t *data, int len, char *xtra, int xsz) { struct smb *smb; uchar_t *vwv; /* word parameters */ int wordcount; uchar_t *byteparms; int bytecount; int parambytes; int paramoffset; int setupcount; int subcode; uchar_t *setupdata; uchar_t *params; int apinum; int isunicode; char filename[256]; const char *apiname; const char *subcname; ushort_t smb_flags2; smb = (struct smb *)data; smb_flags2 = get2(smb->flags2); vwv = (uchar_t *)data + sizeof (struct smb); wordcount = *vwv++; /* Is the pathname in unicode? */ isunicode = smb_flags2 & FLAGS2_UNICODE; byteparms = vwv + (2 * wordcount); bytecount = get2(byteparms); byteparms += 2; /* * Print the lengths before we (potentially) bail out * due to lack of data (so the user knows why we did). */ if (flags & F_DTAIL) show_printf("WordCount = %d", wordcount); /* Get length and location of params and setup data. */ if (!(smb->flags & SERVER_RESPONSE)) { /* CALL */ if (wordcount < 14) return; parambytes = get2(vwv + (2 * 9)); paramoffset = get2(vwv + (2 * 10)); setupcount = *(vwv + (2 * 13)); setupdata = vwv + (2 * 14); } else { /* REPLY */ if (wordcount < 10) return; parambytes = get2(vwv + (2 * 3)); paramoffset = get2(vwv + (2 * 4)); setupcount = *(vwv + (2 * 9)); setupdata = vwv + (2 * 10); } /* The parameters are offset from the SMB header. */ params = data + paramoffset; if ((smb->flags & SERVER_RESPONSE) == 0) { /* This is a CALL. */ if (setupcount > 0) subcode = get2(setupdata); else subcode = -1; /* invalid */ subcname = pipeapi_name(subcode); if (parambytes > 0) apinum = params[0]; else apinum = -1; /* invalid */ if (0 <= apinum && apinum < apinum_max) apiname = apiname_table[apinum]; else apiname = "?"; if (flags & F_SUM) { int tl; /* Only get one or the other */ if (*subcname != '?') { tl = snprintf(xtra, xsz, " Func=%s", subcname); xtra += tl; xsz -= tl; } if (*apiname != '?') snprintf(xtra, xsz, " Func=%s", apiname); return; } if ((flags & F_DTAIL) == 0) return; /* print the word parameters */ show_printf("TotalParamBytes = %d", get2(vwv)); show_printf("TotalDataBytes = %d", get2(vwv+2)); show_printf("MaxParamBytes = %d", get2(vwv+4)); show_printf("MaxDataBytes = %d", get2(vwv+6)); show_printf("MaxSetupWords = %d", vwv[8]); show_printf("TransFlags = 0x%.4x", get2(vwv+10)); show_printf("Timeout = 0x%.8x", get4(vwv+12)); /* skip Reserved2 */ show_printf("ParamBytes = %d", parambytes); show_printf("ParamOffset = %d", paramoffset); show_printf("DataBytes = %d", get2(vwv+22)); show_printf("DataOffset = %d", get2(vwv+24)); show_printf("SetupWords = %d", setupcount); show_printf("ByteCount = %d", bytecount); /* That finishes the VWV, now the misc. stuff. */ if (setupcount > 0) show_printf("NmPipeFunc = 0x%x (%s)", subcode, subcname); if (parambytes > 0) show_printf("RAP_Func = %d (%s)", apinum, apiname); /* Finally, print the byte parameters. */ GET_STRING(filename, byteparms, isunicode); show_printf("FileName = %s", filename); } else { /* This is a REPLY. */ if (flags & F_SUM) return; if ((flags & F_DTAIL) == 0) return; /* print the word parameters */ show_printf("TotalParamBytes = %d", get2(vwv)); show_printf("TotalDataBytes = %d", get2(vwv+2)); /* skip Reserved */ show_printf("ParamBytes = 0x%.4x", parambytes); show_printf("ParamOffset = 0x%.4x", paramoffset); show_printf("ParamDispl. = 0x%.4x", get2(vwv+10)); show_printf("DataBytes = 0x%.4x", get2(vwv+12)); show_printf("DataOffset = 0x%.4x", get2(vwv+14)); show_printf("DataDispl. = 0x%.4x", get2(vwv+16)); show_printf("SetupWords = %d", setupcount); show_printf("ByteCount = %d", bytecount); show_printf("ParamVec (%d)", parambytes); output_bytes(params, parambytes); } } /* * Interpret a "TconX" SMB * [X/Open-SMB, Sec. 11.4] */ /* ARGSUSED */ static void interpret_tconX(int flags, uchar_t *data, int len, char *xtra, int xsz) { int length; int isunicode; int bytecount; int wordcount; int andxcmd; int andxoffset; int tconflags; int pw_len; char path[256]; char tbuf[256]; char svc[8]; struct smb *smbdata; uchar_t *tcondata; ushort_t smb_flags2; smbdata = (struct smb *)data; smb_flags2 = get2(smbdata->flags2); tcondata = (uchar_t *)data + sizeof (struct smb); wordcount = *tcondata++; isunicode = smb_flags2 & FLAGS2_UNICODE; if ((smbdata->flags & SERVER_RESPONSE) == 0) { /* Request */ if (wordcount < 4) return; andxcmd = get2(tcondata); tcondata += 2; andxoffset = get2(tcondata); tcondata += 2; tconflags = get2(tcondata); tcondata += 2; pw_len = get2(tcondata); tcondata += 2; bytecount = get2(tcondata); tcondata += 2; /* skip password */ if (pw_len > len) pw_len = len; tcondata += pw_len; GET_STRING(path, tcondata, isunicode); (void) strlcpy(svc, (char *)tcondata, sizeof (svc)); if (flags & F_SUM) { snprintf(xtra, xsz, " Share=%s", path); return; } if ((flags & F_DTAIL) == 0) return; show_printf("WordCount = %d", wordcount); show_printf("ChainedCommand = 0x%.2x", andxcmd); show_printf("NextOffset = 0x%.4x", andxoffset); show_printf("TconFlags = 0x%.4x", tconflags); show_printf("PasswordLength = 0x%.4x", pw_len); show_printf("ByteCount = %d", bytecount); show_printf("SharePath = %s", path); show_printf("ServiceType = %s", svc); } else { /* response */ if (wordcount < 3) return; andxcmd = get2(tcondata); tcondata += 2; andxoffset = get2(tcondata); tcondata += 2; tconflags = get2(tcondata); tcondata += 2; bytecount = get2(tcondata); tcondata += 2; length = strlcpy(svc, (char *)tcondata, sizeof (svc)); tcondata += (length + 1); if (flags & F_SUM) { snprintf(xtra, xsz, " Type=%s", svc); return; } if ((flags & F_DTAIL) == 0) return; show_printf("WordCount = %d", wordcount); show_printf("ChainedCommand = 0x%.2x", andxcmd); show_printf("NextOffset = 0x%.4x", andxoffset); show_printf("OptionalSupport = 0x%.4x", tconflags); show_printf("ByteCount = %d", bytecount); show_printf("ServiceType = %s", svc); GET_STRING(tbuf, tcondata, isunicode); show_printf("NativeFS = %s", tbuf); } } /* * Interpret a "SesssetupX" SMB * [X/Open-SMB, Sec. 11.3] */ /* ARGSUSED */ static void interpret_sesssetupX(int flags, uchar_t *data, int len, char *xtra, int xsz) { int bytecount; int lm_pw_len; int ext_security; int sec_blob_len; int isunicode; int nt_pw_len; int wordcount; int cap; char tbuf[256]; struct smb *smbdata; uchar_t *setupdata; ushort_t smb_flags2; smbdata = (struct smb *)data; smb_flags2 = get2(smbdata->flags2); setupdata = (uchar_t *)data + sizeof (struct smb); wordcount = *setupdata++; isunicode = smb_flags2 & FLAGS2_UNICODE; ext_security = smb_flags2 & FLAGS2_EXT_SEC; if ((smbdata->flags & SERVER_RESPONSE) == 0) { /* request summary */ if (flags & F_SUM) { if (ext_security) { /* No decoder for SPNEGO */ snprintf(xtra, xsz, " (SPNEGO)"); return; } if (wordcount != 13) return; setupdata += 14; lm_pw_len = get2(setupdata); setupdata += 2; nt_pw_len = get2(setupdata); setupdata += 6; cap = get4(setupdata); setupdata += 6 + lm_pw_len + nt_pw_len; GET_STRING(tbuf, setupdata, isunicode); snprintf(xtra, xsz, " Username=%s", tbuf); } if ((flags & F_DTAIL) == 0) return; /* request detail */ show_printf("WordCount = %d", wordcount); if (wordcount < 7) return; /* words 0 - 6 */ show_printf("ChainedCommand = 0x%.2x", setupdata[0]); setupdata += 2; show_printf("NextOffset = 0x%.4x", get2(setupdata)); setupdata += 2; show_printf("MaxBufferSize = %d", get2(setupdata)); setupdata += 2; show_printf("MaxMPXRequests = %d", get2(setupdata)); setupdata += 2; show_printf("VCNumber = %d", get2(setupdata)); setupdata += 2; show_printf("SessionKey = 0x%.8x", get4(setupdata)); setupdata += 4; if (ext_security) { if (wordcount != 12) return; /* word 7 */ sec_blob_len = get2(setupdata); setupdata += 2; show_printf("Sec. blob len = %d", sec_blob_len); /* words 8, 9 (reserved) */ setupdata += 4; } else { if (wordcount != 13) return; /* word 7 */ lm_pw_len = get2(setupdata); setupdata += 2; show_printf("LM_Hash_Len = %d", lm_pw_len); /* word 8 */ nt_pw_len = get2(setupdata); setupdata += 2; show_printf("NT_Hash_Len = %d", nt_pw_len); /* words 9, 10 (reserved) */ setupdata += 4; } cap = get4(setupdata); show_printf("Capabilities = 0x%.8x", cap); setupdata += 4; bytecount = get2(setupdata); setupdata += 2; show_printf("ByteCount = %d", bytecount); if (ext_security) { /* No decoder for SPNEGO. Just dump hex. */ show_printf("Security blob: (SPNEGO)"); output_bytes(setupdata, sec_blob_len); setupdata += sec_blob_len; } else { /* Dump password hashes */ if (lm_pw_len > 0) { show_printf("LM Hash (%d bytes)", lm_pw_len); output_bytes(setupdata, lm_pw_len); setupdata += lm_pw_len; } if (nt_pw_len > 0) { show_printf("NT Hash (%d bytes)", nt_pw_len); output_bytes(setupdata, nt_pw_len); setupdata += nt_pw_len; } /* User */ GET_STRING(tbuf, setupdata, isunicode); show_printf("AccountName = %s", tbuf); /* Domain */ GET_STRING(tbuf, setupdata, isunicode); show_printf("DomainName = %s", tbuf); } /* * Remainder is the same for etc. sec. or not * Native OS, Native LanMan */ GET_STRING(tbuf, setupdata, isunicode); show_printf("NativeOS = %s", tbuf); GET_STRING(tbuf, setupdata, isunicode); show_printf("NativeLanman = %s", tbuf); } else { /* response summary */ if (flags & F_SUM) { if (ext_security) { /* No decoder for SPNEGO */ snprintf(xtra, xsz, " (SPNEGO)"); } return; } if ((flags & F_DTAIL) == 0) return; /* response detail */ show_printf("WordCount = %d", wordcount); if (wordcount < 3) return; show_printf("ChainedCommand = 0x%.2x", setupdata[0]); setupdata += 2; show_printf("NextOffset = 0x%.4x", get2(setupdata)); setupdata += 2; show_printf("SetupAction = 0x%.4x", get2(setupdata)); setupdata += 2; if (ext_security) { if (wordcount != 4) return; sec_blob_len = get2(setupdata); setupdata += 2; show_printf("Sec. blob len = %d", sec_blob_len); } else { if (wordcount != 3) return; } bytecount = get2(setupdata); setupdata += 2; show_printf("ByteCount = %d", bytecount); if (ext_security) { /* No decoder for SPNEGO. Just dump hex. */ show_line("Security blob: (SPNEGO)"); output_bytes(setupdata, sec_blob_len); setupdata += sec_blob_len; } /* * Native OS, Native LanMan */ GET_STRING(tbuf, setupdata, isunicode); show_printf("NativeOS = %s", tbuf); GET_STRING(tbuf, setupdata, isunicode); show_printf("NativeLanman = %s", tbuf); if (ext_security == 0) { GET_STRING(tbuf, setupdata, isunicode); show_printf("DomainName = %s", tbuf); } } } /* * Interpret "Trans2" SMB * [X/Open-SMB, Sec. 16] * * This is very much like "trans" above. */ /* ARGSUSED */ static void interpret_trans2(int flags, uchar_t *data, int len, char *xtra, int xsz) { struct smb *smb; uchar_t *vwv; /* word parameters */ int wordcount; uchar_t *byteparms; int bytecount; int parambytes; int paramoffset; int setupcount; int subcode; uchar_t *setupdata; uchar_t *params; char *name; smb = (struct smb *)data; vwv = (uchar_t *)data + sizeof (struct smb); wordcount = *vwv++; byteparms = vwv + (2 * wordcount); bytecount = get2(byteparms); byteparms += 2; /* * Print the lengths before we (potentially) bail out * due to lack of data (so the user knows why we did). */ if (flags & F_DTAIL) { show_printf("WordCount = %d", wordcount); show_printf("ByteCount = %d", bytecount); } /* Get length and location of params and setup data. */ if (!(smb->flags & SERVER_RESPONSE)) { /* CALL */ if (wordcount < 14) return; parambytes = get2(vwv + (2 * 9)); paramoffset = get2(vwv + (2 * 10)); setupcount = *(vwv + (2 * 13)); setupdata = vwv + (2 * 14); } else { /* REPLY */ if (wordcount < 10) return; parambytes = get2(vwv + (2 * 3)); paramoffset = get2(vwv + (2 * 4)); setupcount = *(vwv + (2 * 9)); setupdata = vwv + (2 * 10); } if (setupcount > 0) subcode = get2(setupdata); else subcode = -1; /* invalid */ /* The parameters are offset from the SMB header. */ params = data + paramoffset; if (flags & F_DTAIL && !(smb->flags & SERVER_RESPONSE)) { /* This is a CALL. */ /* print the word parameters */ show_printf("TotalParamBytes = %d", get2(vwv)); show_printf("TotalDataBytes = %d", get2(vwv+2)); show_printf("MaxParamBytes = %d", get2(vwv+4)); show_printf("MaxDataBytes = %d", get2(vwv+6)); show_printf("MaxSetupWords = %d", vwv[8]); show_printf("TransFlags = 0x%.4x", get2(vwv+10)); show_printf("Timeout = 0x%.8x", get4(vwv+12)); /* skip Reserved2 */ show_printf("ParamBytes = 0x%.4x", parambytes); show_printf("ParamOffset = 0x%.4x", paramoffset); show_printf("DataBytes = 0x%.4x", get2(vwv+22)); show_printf("DataOffset = 0x%.4x", get2(vwv+24)); show_printf("SetupWords = %d", setupcount); /* That finishes the VWV, now the misc. stuff. */ show_printf("FunctionCode = %d", subcode); } if (!(smb->flags & SERVER_RESPONSE)) { /* This is a CALL. Do sub-function. */ switch (subcode) { case TRANS2_OPEN: name = "Open"; goto name_only; case TRANS2_FIND_FIRST: output_trans2_findfirst(flags, params, xtra, xsz); break; case TRANS2_FIND_NEXT2: output_trans2_findnext(flags, params, xtra, xsz); break; case TRANS2_QUERY_FS_INFORMATION: name = "QueryFSInfo"; goto name_only; case TRANS2_QUERY_PATH_INFORMATION: output_trans2_querypath(flags, params, xtra, xsz); break; case TRANS2_SET_PATH_INFORMATION: name = "SetPathInfo"; goto name_only; case TRANS2_QUERY_FILE_INFORMATION: output_trans2_queryfile(flags, params, xtra, xsz); break; case TRANS2_SET_FILE_INFORMATION: output_trans2_setfile(flags, params, xtra, xsz); break; case TRANS2_CREATE_DIRECTORY: name = "CreateDir"; goto name_only; default: name = "Unknown"; /* fall through */ name_only: if (flags & F_SUM) snprintf(xtra, xsz, " %s", name); if (flags & F_DTAIL) show_printf("FunctionName = %s", name); break; } } if (flags & F_DTAIL && smb->flags & SERVER_RESPONSE) { /* This is a REPLY. */ /* print the word parameters */ show_printf("TotalParamBytes = %d", get2(vwv)); show_printf("TotalDataBytes = %d", get2(vwv+2)); /* skip Reserved */ show_printf("ParamBytes = 0x%.4x", parambytes); show_printf("ParamOffset = 0x%.4x", paramoffset); show_printf("ParamDispl. = 0x%.4x", get2(vwv+10)); show_printf("DataBytes = 0x%.4x", get2(vwv+12)); show_printf("DataOffset = 0x%.4x", get2(vwv+14)); show_printf("DataDispl. = 0x%.4x", get2(vwv+16)); show_printf("SetupWords = %d", setupcount); output_bytes(byteparms, bytecount); } } static void interpret_default(int flags, uchar_t *data, int len, char *xtra, int xsz) { int slength; int i, tl; int isunicode; int printit; int wordcount; int outsz; char *outstr; char *format; char valuetype; char word[10]; char *label; char tempstr[256]; uchar_t *comdata, *limit; char buff[80]; struct smb *smbdata; struct decode *decoder; uchar_t bval; ushort_t wval; ushort_t smb_flags2; uint_t lval; smbdata = (struct smb *)data; smb_flags2 = get2(smbdata->flags2); comdata = (uchar_t *)data + sizeof (struct smb); wordcount = *comdata++; limit = data + len; isunicode = smb_flags2 & FLAGS2_UNICODE; decoder = &SMBtable[smbdata->com & 255]; if (smbdata->flags & SERVER_RESPONSE) format = decoder->replyfmt; else format = decoder->callfmt; if (!format || strlen(format) == 0) { if (flags & F_SUM) return; show_printf("WordCount = %d", wordcount); if (wordcount == 0) return; show_line("Word values (in hex):"); buff[0] = '\0'; for (i = 0; i < wordcount; i++) { snprintf(word, sizeof (word), "%.4x ", get2(comdata)); comdata += 2; if (comdata >= limit) wordcount = i+1; /* terminate */ (void) strlcat(buff, word, sizeof (buff)); if (((i+1) & 7) == 0 || i == (wordcount-1)) { show_line(buff); strcpy(buff, ""); } } return; } if (flags & F_DTAIL) show_printf("WordCount = %d", wordcount); outstr = xtra; outsz = xsz; valuetype = format[0]; while (valuetype != '\0') { if (comdata >= limit) break; label = format+1; printit = (flags & F_DTAIL) || (valuetype <= 'Z'); switch (valuetype) { case 'W': case 'w': wval = get2(comdata); comdata += 2; if (!printit) break; if (flags & F_DTAIL) show_printf( "%s = 0x%.4x", label, wval); else { tl = snprintf(outstr, outsz, " %s=0x%x", label, wval); outstr += tl; outsz -= tl; } break; case 'D': case 'd': wval = get2(comdata); comdata += 2; if (!printit) break; if (flags & F_DTAIL) show_printf( "%s = %d", label, wval); else { tl = snprintf(outstr, outsz, " %s=%d", label, wval); outstr += tl; outsz -= tl; } break; case 'L': case 'l': lval = get4(comdata); comdata += 4; if (!printit) break; if (flags & F_DTAIL) show_printf( "%s = 0x%.8x", label, lval); else { tl = snprintf(outstr, outsz, " %s=0x%x", label, lval); outstr += tl; outsz -= tl; } break; case 'B': case 'b': bval = comdata[0]; comdata += 1; if (!printit) break; if (flags & F_DTAIL) show_printf( "%s = 0x%.2x", label, bval); else { tl = snprintf(outstr, outsz, " %s=0x%x", label, bval); outstr += tl; outsz -= tl; } break; case 'r': comdata++; break; case 'R': comdata += 2; break; case 'U': case 'u': /* Unicode or ASCII string. */ GET_STRING(tempstr, comdata, isunicode); if (!printit) break; if (flags & F_DTAIL) show_printf( "%s = %s", label, tempstr); else { tl = snprintf(outstr, outsz, " %s=%s", label, tempstr); outstr += tl; outsz -= tl; } break; case 'S': case 's': slength = strlcpy(tempstr, (char *)comdata, sizeof (tempstr)); comdata += (slength+1); if (!printit) break; if (flags & F_DTAIL) show_printf( "%s = %s", label, tempstr); else { tl = snprintf(outstr, outsz, " %s=%s", label, tempstr); outstr += tl; outsz -= tl; } break; } format += (strlen(format) + 1); valuetype = format[0]; } }