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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
29 * References used throughout this code:
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
35 * [X/Open-SMB] : X/Open CAE Specification;
36 * Protocols for X/Open PC Interworking: SMB, Version 2
37 * X/Open Document Number: C209
50 * [X/Open-SMB, Sec. 5.1]
53 uchar_t idf
[4]; /* identifier, contains 0xff, 'SMB' */
54 uchar_t com
; /* command code */
55 uchar_t err
[4]; /* NT Status, or error class+code */
64 * immediately after the above 32 byte header:
65 * unsigned char WordCount;
66 * unsigned short ParameterWords[ WordCount ];
67 * unsigned short ByteCount;
68 * unsigned char ParameterBytes[ ByteCount ];
73 #define SERVER_RESPONSE 0x80
76 #define FLAGS2_EXT_SEC 0x0800 /* Extended security */
77 #define FLAGS2_NT_STATUS 0x4000 /* NT status codes */
78 #define FLAGS2_UNICODE 0x8000 /* String are Unicode */
80 static void interpret_sesssetupX(int, uchar_t
*, int, char *, int);
81 static void interpret_tconX(int, uchar_t
*, int, char *, int);
82 static void interpret_trans(int, uchar_t
*, int, char *, int);
83 static void interpret_trans2(int, uchar_t
*, int, char *, int);
84 static void interpret_negprot(int, uchar_t
*, int, char *, int);
85 static void interpret_default(int, uchar_t
*, int, char *, int);
88 * Trans2 subcommand codes
89 * [X/Open-SMB, Sec. 16.1.7]
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
104 void (*func
)(int, uchar_t
*, int, char *, int);
110 * SMB command codes (function names)
111 * [X/Open-SMB, Sec. 5.2]
113 static struct decode SMBtable
[256] = {
115 { "mkdir", 0, 0, 0 },
116 { "rmdir", 0, 0, 0 },
118 { "create", 0, 0, 0 },
122 /* [X/Open-SMB, Sec. 7.10] */
129 { "flush", 0, 0, 0 },
130 { "unlink", 0, 0, 0 },
134 /* [X/Open-SMB, Sec. 7.11] */
144 /* [X/Open-SMB, Sec. 8.4] */
154 { "setatr", 0, 0, 0 },
158 /* [X/Open-SMB, Sec. 7.4] */
171 /* [X/Open-SMB, Sec. 7.5] */
182 { "unlock", 0, 0, 0 },
183 { "ctemp", 0, 0, 0 },
184 { "mknew", 0, 0, 0 },
189 /* [X/Open-SMB, Sec. 8.7] */
196 { "lseek", 0, 0, 0 },
197 { "lockread", 0, 0, 0 },
198 { "writeunlock", 0, 0, 0 },
207 /* [X/Open-SMB, Sec. 10.1] */
216 { "readbmpx", 0, 0, 0 },
217 { "readbs", 0, 0, 0 },
218 { "writebraw", 0, 0, 0 },
219 { "writebmpx", 0, 0, 0 },
220 { "writebs", 0, 0, 0 },
223 { "writec", 0, 0, 0 },
224 { "qrysrv", 0, 0, 0 },
225 { "setattrE", 0, 0, 0 },
226 { "getattrE", 0, 0, 0 },
230 /* [X/Open-SMB, Sec. 12.2] */
241 { "trans", interpret_trans
, 0, 0 },
242 { "transs", 0, 0, 0 },
243 { "ioctl", 0, 0, 0 },
244 { "ioctls", 0, 0, 0 },
248 { "writeclose", 0, 0, 0 },
251 /* [X/Open-SMB, Sec. 12.1] */
258 "wSearchAttributes\0"
263 "lOpenTimeout\0R\0R\0"
331 { "closeTD", 0, 0, 0 },
332 { "trans2", interpret_trans2
, 0, 0 },
333 { "trans2s", 0, 0, 0 },
336 /* [X/Open-SMB, Sec. 15.4 ] */
411 /* [X/Open-SMB, Sec. 6.3] */
415 { "negprot", interpret_negprot
, 0, 0 },
416 { "sesssetupX", interpret_sesssetupX
, 0, 0 },
419 /* [X/Open-SMB, Sec. 15.5] */
424 { "tconX", interpret_tconX
, 0, 0 },
437 { "dskattr", 0, 0, 0 },
438 { "search", 0, 0, 0 },
439 { "ffirst", 0, 0, 0 },
440 { "funique", 0, 0, 0 },
441 { "fclose", 0, 0, 0 },
474 * Command codes 0xa0 to 0xa7 are from
475 * [CIFS/1.0, Sec. 5.1]
477 { "_NT_Trans", 0, 0, 0 },
478 { "_NT_Trans2", 0, 0, 0 },
480 /* [CIFS/1.0, Sec. 4.2.1] */
491 "lNTFileAttributes\0"
495 "lImpersonationLevel\0"
509 /* [CIFS/1.0, Sec. 4.1.8] */
543 { "splopen", 0, 0, 0 },
544 { "splwr", 0, 0, 0 },
545 { "splclose", 0, 0, 0 },
546 { "splretq", 0, 0, 0 },
561 { "sends", 0, 0, 0 },
562 { "sendb", 0, 0, 0 },
563 { "fwdname", 0, 0, 0 },
564 { "cancelf", 0, 0, 0 },
565 { "getmac", 0, 0, 0 },
566 { "sendstrt", 0, 0, 0 },
567 { "sendend", 0, 0, 0 },
568 { "sendtxt", 0, 0, 0 },
615 /* Helpers to get values in Intel order (often mis-aligned). */
618 return (p
[0] + (p
[1]<<8));
622 return (p
[0] + (p
[1]<<8) + (p
[2]<<16) + (p
[3]<<24));
626 return (get4(p
) | ((uint64_t)get4(p
+4) << 32));
630 * Support displaying NT times.
631 * Number of seconds between 1970 and 1601 year
634 static const uint64_t DIFF1970TO1601
= 11644473600ULL;
635 static const uint32_t TEN_MIL
= 10000000UL;
637 format_nttime(uint64_t nt_time
)
639 uint64_t nt_sec
; /* seconds */
640 uint64_t nt_tus
; /* tenths of uSec. */
644 /* Optimize time zero. */
651 nt_sec
= nt_time
/ TEN_MIL
;
652 nt_tus
= nt_time
% TEN_MIL
;
654 if (nt_sec
<= DIFF1970TO1601
) {
659 ux_sec
= nt_sec
- DIFF1970TO1601
;
660 ux_nsec
= nt_tus
* 100;
663 return (format_time(ux_sec
, ux_nsec
));
667 * This is called by snoop_netbios.c.
668 * This is the external entry point.
671 interpret_smb(int flags
, uchar_t
*data
, int len
)
674 struct decode
*decoder
;
677 void (*func
)(int, uchar_t
*, int, char *, int);
679 if (len
< sizeof (struct smb
))
682 smb
= (struct smb
*)data
;
683 decoder
= &SMBtable
[smb
->com
& 255];
684 smb_flags2
= get2(smb
->flags2
);
688 * SMB Header description
689 * [X/Open-SMB, Sec. 5.1]
691 if (flags
& F_DTAIL
) {
692 show_header("SMB: ", "SMB Header", len
);
695 if (smb
->flags
& SERVER_RESPONSE
)
696 show_line("SERVER RESPONSE");
698 show_line("CLIENT REQUEST");
701 show_printf("Command code = 0x%x (SMB%s)",
702 smb
->com
, decoder
->name
);
704 show_printf("Command code = 0x%x", smb
->com
);
707 * NT status or error class/code
708 * [X/Open-SMB, Sec. 5.6]
710 if (smb_flags2
& FLAGS2_NT_STATUS
) {
711 show_printf("NT Status = %x", get4(smb
->err
));
713 /* Error classes [X/Open-SMB, Sec. 5.6] */
714 show_printf("Error class/code = %d/%d",
715 smb
->err
[0], get2(&smb
->err
[2]));
718 show_printf("Flags summary = 0x%.2x", smb
->flags
);
719 show_printf("Flags2 summary = 0x%.4x", smb_flags2
);
720 show_printf("Tree ID (TID) = 0x%.4x", get2(smb
->tid
));
721 show_printf("Proc. ID (PID) = 0x%.4x", get2(smb
->pid
));
722 show_printf("User ID (UID) = 0x%.4x", get2(smb
->uid
));
723 show_printf("Mux. ID (MID) = 0x%.4x", get2(smb
->mid
));
727 if ((func
= decoder
->func
) == NULL
)
728 func
= interpret_default
;
729 (*func
)(flags
, (uchar_t
*)data
, len
, xtra
, sizeof (xtra
));
735 /* Will advance p and decr. sz */
740 if (smb
->flags
& SERVER_RESPONSE
)
741 tl
= snprintf(p
, sz
, "SMB R");
743 tl
= snprintf(p
, sz
, "SMB C");
747 /* The name, if known, else the cmd code */
749 tl
= snprintf(p
, sz
, " Cmd=SMB%s", decoder
->name
);
751 tl
= snprintf(p
, sz
, " Cmd=0x%02X", smb
->com
);
757 * The "extra" (cmd-specific summary).
758 * If non-null, has leading blank.
760 if (xtra
[0] != '\0') {
761 tl
= snprintf(p
, sz
, "%s", xtra
);
767 * NT status or error class/code
768 * [X/Open-SMB, Sec. 5.6]
770 * Only show for response, not call.
772 if (smb
->flags
& SERVER_RESPONSE
) {
773 if (smb_flags2
& FLAGS2_NT_STATUS
) {
774 uint_t status
= get4(smb
->err
);
775 snprintf(p
, sz
, " Status=0x%x", status
);
777 uchar_t errcl
= smb
->err
[0];
778 ushort_t code
= get2(&smb
->err
[2]);
779 snprintf(p
, sz
, " Error=%d/%d", errcl
, code
);
789 output_bytes(uchar_t
*data
, int bytecount
)
795 (void) strlcpy(buff
, " ", sizeof (buff
));
796 for (i
= 0; i
< bytecount
; i
++) {
797 snprintf(word
, sizeof (word
), "%.2x ", data
[i
]);
798 (void) strlcat(buff
, word
, sizeof (buff
));
799 if ((i
+1)%16 == 0 || i
== (bytecount
-1)) {
801 (void) strlcpy(buff
, " ", sizeof (buff
));
807 * Based on the Unicode Standard, http://www.unicode.org/
808 * "The Unicode Standard: A Technical Introduction", June 1998
811 unicode2ascii(char *outstr
, int outlen
, uchar_t
*instr
, int inlen
)
816 while (i
< inlen
&& j
< (outlen
-1)) {
817 /* Show unicode chars >= 256 as '?' */
833 * Convenience macro to copy a string from the data,
834 * either in UCS-2 or ASCII as indicated by UCS.
835 * OBUF must be an array type (see sizeof) and
836 * DP must be an L-value (this increments it).
838 #define GET_STRING(OBUF, DP, UCS) \
840 int _len, _sz = sizeof (OBUF); \
842 if (((uintptr_t)DP) & 1) \
844 _len = unicode2ascii(OBUF, _sz, DP, 2 * _sz); \
845 DP += 2 * (_len + 1); \
847 _len = strlcpy(OBUF, (char *)DP, _sz); \
853 * TRANS2 information levels
854 * [X/Open-SMB, Sec. 16.1.6]
857 get_info_level(char *outstr
, int outsz
, int value
)
862 snprintf(outstr
, outsz
, "Standard");
865 snprintf(outstr
, outsz
, "Query EA Size");
868 snprintf(outstr
, outsz
, "Query EAS from List");
871 snprintf(outstr
, outsz
, "Directory Info");
874 snprintf(outstr
, outsz
, "Full Directory Info");
877 snprintf(outstr
, outsz
, "Names Info");
880 snprintf(outstr
, outsz
, "Both Directory Info");
883 snprintf(outstr
, outsz
, "Unknown");
889 * Interpret TRANS2_QUERY_PATH subcommand
890 * [X/Open-SMB, Sec. 16.7]
894 output_trans2_querypath(int flags
, uchar_t
*data
, char *xtra
, int xsz
)
900 length
= snprintf(xtra
, xsz
, " QueryPathInfo");
904 (void) unicode2ascii(filename
, 256, data
, 512);
905 snprintf(xtra
, xsz
, " File=%s", filename
);
908 if (flags
& F_DTAIL
) {
909 show_line("FunctionName = QueryPathInfo");
910 show_printf("InfoLevel = 0x%.4x", get2(data
));
912 (void) unicode2ascii(filename
, 256, data
, 512);
913 show_printf("FileName = %s", filename
);
918 * Interpret TRANS2_QUERY_FILE subcommand
919 * [X/Open-SMB, Sec. 16.9]
923 output_trans2_queryfile(int flags
, uchar_t
*data
, char *xtra
, int xsz
)
928 length
= snprintf(xtra
, xsz
, " QueryFileInfo");
931 snprintf(xtra
, xsz
, " FileID=0x%x", get2(data
));
934 if (flags
& F_DTAIL
) {
935 show_line("FunctionName = QueryFileInfo");
936 show_printf("FileID = 0x%.4x", get2(data
));
938 show_printf("InfoLevel = 0x%.4x", get2(data
));
943 * Interpret TRANS2_SET_FILE subcommand
944 * [X/Open-SMB, Sec. 16.10]
948 output_trans2_setfile(int flags
, uchar_t
*data
, char *xtra
, int xsz
)
953 length
= snprintf(xtra
, xsz
, " SetFileInfo");
956 snprintf(xtra
, xsz
, " FileID=0x%x", get2(data
));
959 if (flags
& F_DTAIL
) {
960 show_line("FunctionName = SetFileInfo");
961 show_printf("FileID = 0x%.4x", get2(data
));
963 show_printf("InfoLevel = 0x%.4x", get2(data
));
968 * Interpret TRANS2_FIND_FIRST subcommand
969 * [X/Open-SMB, Sec. 16.3]
973 output_trans2_findfirst(int flags
, uchar_t
*data
, char *xtra
, int xsz
)
980 length
= snprintf(xtra
, xsz
, " Findfirst");
984 (void) unicode2ascii(filename
, 256, data
, 512);
985 snprintf(xtra
, xsz
, " File=%s", filename
);
988 if (flags
& F_DTAIL
) {
989 show_line("FunctionName = Findfirst");
990 show_printf("SearchAttributes = 0x%.4x", get2(data
));
992 show_printf("FindCount = 0x%.4x", get2(data
));
994 show_printf("FindFlags = 0x%.4x", get2(data
));
996 get_info_level(infolevel
, sizeof (infolevel
), get2(data
));
997 show_printf("InfoLevel = %s", infolevel
);
999 (void) unicode2ascii(filename
, 256, data
, 512);
1000 show_printf("FileName = %s", filename
);
1006 * Interpret TRANS2_FIND_NEXT subcommand
1007 * [X/Open-SMB, Sec. 16.4]
1011 output_trans2_findnext(int flags
, uchar_t
*data
, char *xtra
, int xsz
)
1015 char infolevel
[100];
1017 if (flags
& F_SUM
) {
1018 length
= snprintf(xtra
, xsz
, " Findnext");
1022 (void) unicode2ascii(filename
, 256, data
, 512);
1023 snprintf(xtra
, xsz
, " File=%s", filename
);
1026 if (flags
& F_DTAIL
) {
1027 show_line("FunctionName = Findnext");
1028 show_printf("FileID = 0x%.4x", get2(data
));
1030 show_printf("FindCount = 0x%.4x", get2(data
));
1032 get_info_level(infolevel
, sizeof (infolevel
), get2(data
));
1033 show_printf("InfoLevel = %s", infolevel
);
1035 show_printf("FindKey = 0x%.8x", get4(data
));
1037 show_printf("FindFlags = 0x%.4x", get2(data
));
1039 (void) unicode2ascii(filename
, 256, data
, 512);
1040 show_printf("FileName = %s", filename
);
1045 * Interpret a "Negprot" SMB
1046 * [X/Open-SMB, Sec. 6.1]
1050 interpret_negprot(int flags
, uchar_t
*data
, int len
, char *xtra
, int xsz
)
1052 int i
, last
, length
;
1057 struct smb
*smbdata
;
1062 ushort_t smb_flags2
;
1064 smbdata
= (struct smb
*)data
;
1065 smb_flags2
= get2(smbdata
->flags2
);
1066 protodata
= (uchar_t
*)data
+ sizeof (struct smb
);
1067 wordcount
= *protodata
++;
1069 if ((smbdata
->flags
& SERVER_RESPONSE
) == 0) {
1073 * struct { char fmt; char name[]; } dialects
1075 bytecount
= get2(protodata
);
1079 if (flags
& F_DTAIL
)
1080 show_printf("ByteCount = %d", bytecount
);
1081 if (bytecount
> len
)
1084 /* Walk the list of dialects. */
1087 while (protodata
< (byte0
+ bytecount
- 2)) {
1088 if (*protodata
++ != 2) /* format code */
1090 length
= strlcpy(tbuf
, (char *)protodata
,
1092 protodata
+= (length
+ 1);
1093 if (flags
& F_DTAIL
) {
1094 show_printf("Dialect[%d] = %s",
1099 if (flags
& F_SUM
) {
1101 * Just print the last dialect, which is
1102 * normally the interesting one.
1104 snprintf(xtra
, xsz
, " Dialect[%d]=%s", last
, tbuf
);
1108 if (flags
& F_SUM
) {
1109 snprintf(xtra
, xsz
, " Dialect#=%d", protodata
[0]);
1111 if ((flags
& F_DTAIL
) == 0)
1115 show_printf("WordCount = %d", wordcount
);
1116 show_printf("Dialect Index = %d", protodata
[0]);
1118 show_printf("Security Mode = 0x%x", protodata
[0]);
1120 show_printf("MaxMPXRequests = %d", get2(protodata
));
1122 show_printf("MaxVCs = %d", get2(protodata
));
1124 show_printf("MaxBufferSize = %d", get4(protodata
));
1126 show_printf("MaxRawBuffer = %d", get4(protodata
));
1128 show_printf("SessionKey = 0x%.8x", get4(protodata
));
1131 caps
= get4(protodata
);
1133 show_printf("Capabilities = 0x%.8x", caps
);
1136 nttime
= get8(protodata
);
1138 show_printf("Server Time = %s", format_nttime(nttime
));
1140 show_printf("Server TZ = %d", get2(protodata
));
1143 key_len
= *protodata
++;
1144 show_printf("KeyLength = %d", key_len
);
1145 bytecount
= get2(protodata
);
1147 show_printf("ByteCount = %d", bytecount
);
1149 if (smb_flags2
& FLAGS2_EXT_SEC
) {
1150 show_printf("Server GUID (16)");
1151 output_bytes(protodata
, 16);
1153 show_printf("Security Blob (SPNEGO)");
1154 output_bytes(protodata
, bytecount
- 16);
1156 show_printf("NTLM Challenge: (%d)", key_len
);
1157 output_bytes(protodata
, key_len
);
1158 protodata
+= key_len
;
1160 * Get Unicode from capabilities here,
1161 * as flags2 typically doesn't have it.
1162 * Also, this one is NOT aligned!
1166 (void) unicode2ascii(tbuf
, sizeof (tbuf
),
1167 protodata
, 2 * sizeof (tbuf
));
1169 (void) strlcpy(tbuf
, (char *)protodata
,
1172 show_printf("Server Domain = %s", tbuf
);
1178 * LAN Manager remote admin function names.
1179 * [X/Open-SMB, Appendix B.8]
1181 static const char *apiname_table
[] = {
1189 "NetSessionGetInfo",
1191 "NetConnectionEnum",
1195 "RNetServerGetInfo",
1197 "NetServerDiskEnum",
1198 "NetServerAdminCommand",
1204 "NetCharDevGetInfo",
1205 "NetCharDevControl",
1207 "NetCharDevQGetInfo",
1208 "NetCharDevQSetInfo",
1210 "RNetCharDevQPurgeSelf",
1211 "NetMessageNameEnum",
1212 "NetMessageNameGetInfo",
1213 "NetMessageNameAdd",
1214 "NetMessageNameDel",
1215 "NetMessageNameFwd",
1216 "NetMessageNameUnFwd",
1217 "NetMessageBufferSend",
1218 "NetMessageFileSend",
1219 "NetMessageLogFileSet",
1220 "NetMessageLogFileGet",
1222 "RNetServiceInstall",
1223 "RNetServiceControl",
1225 "RNetAccessGetInfo",
1226 "RNetAccessSetInfo",
1240 "RNetUserPasswordSet",
1257 "DosPrintQContinue",
1259 "DosPrintJobGetInfo",
1260 "RDosPrintJobSetInfo",
1262 "DosPrintJobSchedule",
1264 "RDosPrintJobPause",
1265 "RDosPrintJobContinue",
1267 "DosPrintDestGetInfo",
1268 "DosPrintDestControl",
1272 "NetStatisticsClear",
1278 "NetServiceGetInfo",
1288 static const int apinum_max
= (
1289 sizeof (apiname_table
) /
1290 sizeof (apiname_table
[0]));
1293 pipeapi_name(int code
)
1299 name
= "SetNmPipeState";
1302 name
= "RawReadNmPipe";
1305 name
= "QueryNmPipeState";
1308 name
= "QueryNmPipeInfo";
1311 name
= "PeekNmPipe";
1314 name
= "XactNmPipe";
1317 name
= "RawWriteNmPipe";
1320 name
= "ReadNmPipe";
1323 name
= "WriteNmPipe";
1326 name
= "WaitNmPipe";
1329 name
= "CallNmPipe";
1339 * Interpret a "trans" SMB
1340 * [X/Open-SMB, Appendix B]
1342 * This is very much like "trans2" below.
1346 interpret_trans(int flags
, uchar_t
*data
, int len
, char *xtra
, int xsz
)
1349 uchar_t
*vwv
; /* word parameters */
1362 const char *apiname
;
1363 const char *subcname
;
1364 ushort_t smb_flags2
;
1366 smb
= (struct smb
*)data
;
1367 smb_flags2
= get2(smb
->flags2
);
1368 vwv
= (uchar_t
*)data
+ sizeof (struct smb
);
1371 /* Is the pathname in unicode? */
1372 isunicode
= smb_flags2
& FLAGS2_UNICODE
;
1374 byteparms
= vwv
+ (2 * wordcount
);
1375 bytecount
= get2(byteparms
);
1379 * Print the lengths before we (potentially) bail out
1380 * due to lack of data (so the user knows why we did).
1382 if (flags
& F_DTAIL
)
1383 show_printf("WordCount = %d", wordcount
);
1385 /* Get length and location of params and setup data. */
1386 if (!(smb
->flags
& SERVER_RESPONSE
)) {
1390 parambytes
= get2(vwv
+ (2 * 9));
1391 paramoffset
= get2(vwv
+ (2 * 10));
1392 setupcount
= *(vwv
+ (2 * 13));
1393 setupdata
= vwv
+ (2 * 14);
1398 parambytes
= get2(vwv
+ (2 * 3));
1399 paramoffset
= get2(vwv
+ (2 * 4));
1400 setupcount
= *(vwv
+ (2 * 9));
1401 setupdata
= vwv
+ (2 * 10);
1404 /* The parameters are offset from the SMB header. */
1405 params
= data
+ paramoffset
;
1407 if ((smb
->flags
& SERVER_RESPONSE
) == 0) {
1408 /* This is a CALL. */
1411 subcode
= get2(setupdata
);
1413 subcode
= -1; /* invalid */
1414 subcname
= pipeapi_name(subcode
);
1419 apinum
= -1; /* invalid */
1420 if (0 <= apinum
&& apinum
< apinum_max
)
1421 apiname
= apiname_table
[apinum
];
1425 if (flags
& F_SUM
) {
1427 /* Only get one or the other */
1428 if (*subcname
!= '?') {
1429 tl
= snprintf(xtra
, xsz
,
1430 " Func=%s", subcname
);
1434 if (*apiname
!= '?')
1436 " Func=%s", apiname
);
1439 if ((flags
& F_DTAIL
) == 0)
1442 /* print the word parameters */
1443 show_printf("TotalParamBytes = %d", get2(vwv
));
1444 show_printf("TotalDataBytes = %d", get2(vwv
+2));
1445 show_printf("MaxParamBytes = %d", get2(vwv
+4));
1446 show_printf("MaxDataBytes = %d", get2(vwv
+6));
1447 show_printf("MaxSetupWords = %d", vwv
[8]);
1448 show_printf("TransFlags = 0x%.4x", get2(vwv
+10));
1449 show_printf("Timeout = 0x%.8x", get4(vwv
+12));
1450 /* skip Reserved2 */
1451 show_printf("ParamBytes = %d", parambytes
);
1452 show_printf("ParamOffset = %d", paramoffset
);
1453 show_printf("DataBytes = %d", get2(vwv
+22));
1454 show_printf("DataOffset = %d", get2(vwv
+24));
1455 show_printf("SetupWords = %d", setupcount
);
1456 show_printf("ByteCount = %d", bytecount
);
1458 /* That finishes the VWV, now the misc. stuff. */
1460 show_printf("NmPipeFunc = 0x%x (%s)",
1463 show_printf("RAP_Func = %d (%s)",
1466 /* Finally, print the byte parameters. */
1467 GET_STRING(filename
, byteparms
, isunicode
);
1468 show_printf("FileName = %s", filename
);
1470 /* This is a REPLY. */
1473 if ((flags
& F_DTAIL
) == 0)
1475 /* print the word parameters */
1476 show_printf("TotalParamBytes = %d", get2(vwv
));
1477 show_printf("TotalDataBytes = %d", get2(vwv
+2));
1479 show_printf("ParamBytes = 0x%.4x", parambytes
);
1480 show_printf("ParamOffset = 0x%.4x", paramoffset
);
1481 show_printf("ParamDispl. = 0x%.4x", get2(vwv
+10));
1482 show_printf("DataBytes = 0x%.4x", get2(vwv
+12));
1483 show_printf("DataOffset = 0x%.4x", get2(vwv
+14));
1484 show_printf("DataDispl. = 0x%.4x", get2(vwv
+16));
1485 show_printf("SetupWords = %d", setupcount
);
1486 show_printf("ByteCount = %d", bytecount
);
1488 show_printf("ParamVec (%d)", parambytes
);
1489 output_bytes(params
, parambytes
);
1494 * Interpret a "TconX" SMB
1495 * [X/Open-SMB, Sec. 11.4]
1499 interpret_tconX(int flags
, uchar_t
*data
, int len
, char *xtra
, int xsz
)
1512 struct smb
*smbdata
;
1514 ushort_t smb_flags2
;
1516 smbdata
= (struct smb
*)data
;
1517 smb_flags2
= get2(smbdata
->flags2
);
1518 tcondata
= (uchar_t
*)data
+ sizeof (struct smb
);
1519 wordcount
= *tcondata
++;
1521 isunicode
= smb_flags2
& FLAGS2_UNICODE
;
1523 if ((smbdata
->flags
& SERVER_RESPONSE
) == 0) {
1527 andxcmd
= get2(tcondata
);
1529 andxoffset
= get2(tcondata
);
1531 tconflags
= get2(tcondata
);
1533 pw_len
= get2(tcondata
);
1535 bytecount
= get2(tcondata
);
1543 GET_STRING(path
, tcondata
, isunicode
);
1544 (void) strlcpy(svc
, (char *)tcondata
, sizeof (svc
));
1546 if (flags
& F_SUM
) {
1547 snprintf(xtra
, xsz
, " Share=%s", path
);
1551 if ((flags
& F_DTAIL
) == 0)
1554 show_printf("WordCount = %d", wordcount
);
1555 show_printf("ChainedCommand = 0x%.2x", andxcmd
);
1556 show_printf("NextOffset = 0x%.4x", andxoffset
);
1557 show_printf("TconFlags = 0x%.4x", tconflags
);
1558 show_printf("PasswordLength = 0x%.4x", pw_len
);
1559 show_printf("ByteCount = %d", bytecount
);
1560 show_printf("SharePath = %s", path
);
1561 show_printf("ServiceType = %s", svc
);
1566 andxcmd
= get2(tcondata
);
1568 andxoffset
= get2(tcondata
);
1570 tconflags
= get2(tcondata
);
1572 bytecount
= get2(tcondata
);
1575 length
= strlcpy(svc
, (char *)tcondata
, sizeof (svc
));
1576 tcondata
+= (length
+ 1);
1578 if (flags
& F_SUM
) {
1579 snprintf(xtra
, xsz
, " Type=%s", svc
);
1582 if ((flags
& F_DTAIL
) == 0)
1585 show_printf("WordCount = %d", wordcount
);
1586 show_printf("ChainedCommand = 0x%.2x", andxcmd
);
1587 show_printf("NextOffset = 0x%.4x", andxoffset
);
1588 show_printf("OptionalSupport = 0x%.4x", tconflags
);
1589 show_printf("ByteCount = %d", bytecount
);
1590 show_printf("ServiceType = %s", svc
);
1591 GET_STRING(tbuf
, tcondata
, isunicode
);
1592 show_printf("NativeFS = %s", tbuf
);
1597 * Interpret a "SesssetupX" SMB
1598 * [X/Open-SMB, Sec. 11.3]
1602 interpret_sesssetupX(int flags
, uchar_t
*data
, int len
, char *xtra
, int xsz
)
1613 struct smb
*smbdata
;
1615 ushort_t smb_flags2
;
1617 smbdata
= (struct smb
*)data
;
1618 smb_flags2
= get2(smbdata
->flags2
);
1619 setupdata
= (uchar_t
*)data
+ sizeof (struct smb
);
1620 wordcount
= *setupdata
++;
1622 isunicode
= smb_flags2
& FLAGS2_UNICODE
;
1623 ext_security
= smb_flags2
& FLAGS2_EXT_SEC
;
1625 if ((smbdata
->flags
& SERVER_RESPONSE
) == 0) {
1626 /* request summary */
1627 if (flags
& F_SUM
) {
1629 /* No decoder for SPNEGO */
1630 snprintf(xtra
, xsz
, " (SPNEGO)");
1633 if (wordcount
!= 13)
1636 lm_pw_len
= get2(setupdata
);
1638 nt_pw_len
= get2(setupdata
);
1640 cap
= get4(setupdata
);
1641 setupdata
+= 6 + lm_pw_len
+ nt_pw_len
;
1643 GET_STRING(tbuf
, setupdata
, isunicode
);
1644 snprintf(xtra
, xsz
, " Username=%s", tbuf
);
1647 if ((flags
& F_DTAIL
) == 0)
1650 /* request detail */
1651 show_printf("WordCount = %d", wordcount
);
1655 show_printf("ChainedCommand = 0x%.2x", setupdata
[0]);
1657 show_printf("NextOffset = 0x%.4x", get2(setupdata
));
1659 show_printf("MaxBufferSize = %d", get2(setupdata
));
1661 show_printf("MaxMPXRequests = %d", get2(setupdata
));
1663 show_printf("VCNumber = %d", get2(setupdata
));
1665 show_printf("SessionKey = 0x%.8x", get4(setupdata
));
1669 if (wordcount
!= 12)
1672 sec_blob_len
= get2(setupdata
);
1674 show_printf("Sec. blob len = %d", sec_blob_len
);
1675 /* words 8, 9 (reserved) */
1678 if (wordcount
!= 13)
1681 lm_pw_len
= get2(setupdata
);
1683 show_printf("LM_Hash_Len = %d", lm_pw_len
);
1685 nt_pw_len
= get2(setupdata
);
1687 show_printf("NT_Hash_Len = %d", nt_pw_len
);
1688 /* words 9, 10 (reserved) */
1692 cap
= get4(setupdata
);
1693 show_printf("Capabilities = 0x%.8x", cap
);
1696 bytecount
= get2(setupdata
);
1698 show_printf("ByteCount = %d", bytecount
);
1701 /* No decoder for SPNEGO. Just dump hex. */
1702 show_printf("Security blob: (SPNEGO)");
1703 output_bytes(setupdata
, sec_blob_len
);
1704 setupdata
+= sec_blob_len
;
1706 /* Dump password hashes */
1707 if (lm_pw_len
> 0) {
1708 show_printf("LM Hash (%d bytes)", lm_pw_len
);
1709 output_bytes(setupdata
, lm_pw_len
);
1710 setupdata
+= lm_pw_len
;
1712 if (nt_pw_len
> 0) {
1713 show_printf("NT Hash (%d bytes)", nt_pw_len
);
1714 output_bytes(setupdata
, nt_pw_len
);
1715 setupdata
+= nt_pw_len
;
1719 GET_STRING(tbuf
, setupdata
, isunicode
);
1720 show_printf("AccountName = %s", tbuf
);
1723 GET_STRING(tbuf
, setupdata
, isunicode
);
1724 show_printf("DomainName = %s", tbuf
);
1728 * Remainder is the same for etc. sec. or not
1729 * Native OS, Native LanMan
1731 GET_STRING(tbuf
, setupdata
, isunicode
);
1732 show_printf("NativeOS = %s", tbuf
);
1734 GET_STRING(tbuf
, setupdata
, isunicode
);
1735 show_printf("NativeLanman = %s", tbuf
);
1737 /* response summary */
1738 if (flags
& F_SUM
) {
1740 /* No decoder for SPNEGO */
1741 snprintf(xtra
, xsz
, " (SPNEGO)");
1746 if ((flags
& F_DTAIL
) == 0)
1749 /* response detail */
1750 show_printf("WordCount = %d", wordcount
);
1754 show_printf("ChainedCommand = 0x%.2x", setupdata
[0]);
1756 show_printf("NextOffset = 0x%.4x", get2(setupdata
));
1758 show_printf("SetupAction = 0x%.4x", get2(setupdata
));
1764 sec_blob_len
= get2(setupdata
);
1766 show_printf("Sec. blob len = %d", sec_blob_len
);
1772 bytecount
= get2(setupdata
);
1774 show_printf("ByteCount = %d", bytecount
);
1777 /* No decoder for SPNEGO. Just dump hex. */
1778 show_line("Security blob: (SPNEGO)");
1779 output_bytes(setupdata
, sec_blob_len
);
1780 setupdata
+= sec_blob_len
;
1784 * Native OS, Native LanMan
1786 GET_STRING(tbuf
, setupdata
, isunicode
);
1787 show_printf("NativeOS = %s", tbuf
);
1789 GET_STRING(tbuf
, setupdata
, isunicode
);
1790 show_printf("NativeLanman = %s", tbuf
);
1792 if (ext_security
== 0) {
1793 GET_STRING(tbuf
, setupdata
, isunicode
);
1794 show_printf("DomainName = %s", tbuf
);
1800 * Interpret "Trans2" SMB
1801 * [X/Open-SMB, Sec. 16]
1803 * This is very much like "trans" above.
1807 interpret_trans2(int flags
, uchar_t
*data
, int len
, char *xtra
, int xsz
)
1810 uchar_t
*vwv
; /* word parameters */
1822 smb
= (struct smb
*)data
;
1823 vwv
= (uchar_t
*)data
+ sizeof (struct smb
);
1826 byteparms
= vwv
+ (2 * wordcount
);
1827 bytecount
= get2(byteparms
);
1831 * Print the lengths before we (potentially) bail out
1832 * due to lack of data (so the user knows why we did).
1834 if (flags
& F_DTAIL
) {
1835 show_printf("WordCount = %d", wordcount
);
1836 show_printf("ByteCount = %d", bytecount
);
1839 /* Get length and location of params and setup data. */
1840 if (!(smb
->flags
& SERVER_RESPONSE
)) {
1844 parambytes
= get2(vwv
+ (2 * 9));
1845 paramoffset
= get2(vwv
+ (2 * 10));
1846 setupcount
= *(vwv
+ (2 * 13));
1847 setupdata
= vwv
+ (2 * 14);
1852 parambytes
= get2(vwv
+ (2 * 3));
1853 paramoffset
= get2(vwv
+ (2 * 4));
1854 setupcount
= *(vwv
+ (2 * 9));
1855 setupdata
= vwv
+ (2 * 10);
1858 subcode
= get2(setupdata
);
1860 subcode
= -1; /* invalid */
1862 /* The parameters are offset from the SMB header. */
1863 params
= data
+ paramoffset
;
1865 if (flags
& F_DTAIL
&& !(smb
->flags
& SERVER_RESPONSE
)) {
1866 /* This is a CALL. */
1867 /* print the word parameters */
1868 show_printf("TotalParamBytes = %d", get2(vwv
));
1869 show_printf("TotalDataBytes = %d", get2(vwv
+2));
1870 show_printf("MaxParamBytes = %d", get2(vwv
+4));
1871 show_printf("MaxDataBytes = %d", get2(vwv
+6));
1872 show_printf("MaxSetupWords = %d", vwv
[8]);
1873 show_printf("TransFlags = 0x%.4x", get2(vwv
+10));
1874 show_printf("Timeout = 0x%.8x", get4(vwv
+12));
1875 /* skip Reserved2 */
1876 show_printf("ParamBytes = 0x%.4x", parambytes
);
1877 show_printf("ParamOffset = 0x%.4x", paramoffset
);
1878 show_printf("DataBytes = 0x%.4x", get2(vwv
+22));
1879 show_printf("DataOffset = 0x%.4x", get2(vwv
+24));
1880 show_printf("SetupWords = %d", setupcount
);
1882 /* That finishes the VWV, now the misc. stuff. */
1883 show_printf("FunctionCode = %d", subcode
);
1886 if (!(smb
->flags
& SERVER_RESPONSE
)) {
1887 /* This is a CALL. Do sub-function. */
1892 case TRANS2_FIND_FIRST
:
1893 output_trans2_findfirst(flags
, params
, xtra
, xsz
);
1895 case TRANS2_FIND_NEXT2
:
1896 output_trans2_findnext(flags
, params
, xtra
, xsz
);
1898 case TRANS2_QUERY_FS_INFORMATION
:
1899 name
= "QueryFSInfo";
1901 case TRANS2_QUERY_PATH_INFORMATION
:
1902 output_trans2_querypath(flags
, params
, xtra
, xsz
);
1904 case TRANS2_SET_PATH_INFORMATION
:
1905 name
= "SetPathInfo";
1907 case TRANS2_QUERY_FILE_INFORMATION
:
1908 output_trans2_queryfile(flags
, params
, xtra
, xsz
);
1910 case TRANS2_SET_FILE_INFORMATION
:
1911 output_trans2_setfile(flags
, params
, xtra
, xsz
);
1913 case TRANS2_CREATE_DIRECTORY
:
1922 snprintf(xtra
, xsz
, " %s", name
);
1923 if (flags
& F_DTAIL
)
1924 show_printf("FunctionName = %s", name
);
1929 if (flags
& F_DTAIL
&& smb
->flags
& SERVER_RESPONSE
) {
1930 /* This is a REPLY. */
1931 /* print the word parameters */
1932 show_printf("TotalParamBytes = %d", get2(vwv
));
1933 show_printf("TotalDataBytes = %d", get2(vwv
+2));
1935 show_printf("ParamBytes = 0x%.4x", parambytes
);
1936 show_printf("ParamOffset = 0x%.4x", paramoffset
);
1937 show_printf("ParamDispl. = 0x%.4x", get2(vwv
+10));
1938 show_printf("DataBytes = 0x%.4x", get2(vwv
+12));
1939 show_printf("DataOffset = 0x%.4x", get2(vwv
+14));
1940 show_printf("DataDispl. = 0x%.4x", get2(vwv
+16));
1941 show_printf("SetupWords = %d", setupcount
);
1943 output_bytes(byteparms
, bytecount
);
1949 interpret_default(int flags
, uchar_t
*data
, int len
, char *xtra
, int xsz
)
1963 uchar_t
*comdata
, *limit
;
1965 struct smb
*smbdata
;
1966 struct decode
*decoder
;
1969 ushort_t smb_flags2
;
1972 smbdata
= (struct smb
*)data
;
1973 smb_flags2
= get2(smbdata
->flags2
);
1974 comdata
= (uchar_t
*)data
+ sizeof (struct smb
);
1975 wordcount
= *comdata
++;
1978 isunicode
= smb_flags2
& FLAGS2_UNICODE
;
1979 decoder
= &SMBtable
[smbdata
->com
& 255];
1981 if (smbdata
->flags
& SERVER_RESPONSE
)
1982 format
= decoder
->replyfmt
;
1984 format
= decoder
->callfmt
;
1986 if (!format
|| strlen(format
) == 0) {
1989 show_printf("WordCount = %d", wordcount
);
1992 show_line("Word values (in hex):");
1994 for (i
= 0; i
< wordcount
; i
++) {
1995 snprintf(word
, sizeof (word
), "%.4x ", get2(comdata
));
1997 if (comdata
>= limit
)
1998 wordcount
= i
+1; /* terminate */
1999 (void) strlcat(buff
, word
, sizeof (buff
));
2000 if (((i
+1) & 7) == 0 || i
== (wordcount
-1)) {
2008 if (flags
& F_DTAIL
)
2009 show_printf("WordCount = %d", wordcount
);
2014 valuetype
= format
[0];
2015 while (valuetype
!= '\0') {
2016 if (comdata
>= limit
)
2019 printit
= (flags
& F_DTAIL
) || (valuetype
<= 'Z');
2021 switch (valuetype
) {
2024 wval
= get2(comdata
);
2028 if (flags
& F_DTAIL
)
2030 "%s = 0x%.4x", label
, wval
);
2032 tl
= snprintf(outstr
, outsz
,
2033 " %s=0x%x", label
, wval
);
2041 wval
= get2(comdata
);
2045 if (flags
& F_DTAIL
)
2047 "%s = %d", label
, wval
);
2049 tl
= snprintf(outstr
, outsz
,
2050 " %s=%d", label
, wval
);
2058 lval
= get4(comdata
);
2062 if (flags
& F_DTAIL
)
2064 "%s = 0x%.8x", label
, lval
);
2066 tl
= snprintf(outstr
, outsz
,
2067 " %s=0x%x", label
, lval
);
2079 if (flags
& F_DTAIL
)
2081 "%s = 0x%.2x", label
, bval
);
2083 tl
= snprintf(outstr
, outsz
,
2084 " %s=0x%x", label
, bval
);
2100 /* Unicode or ASCII string. */
2101 GET_STRING(tempstr
, comdata
, isunicode
);
2104 if (flags
& F_DTAIL
)
2106 "%s = %s", label
, tempstr
);
2108 tl
= snprintf(outstr
, outsz
,
2109 " %s=%s", label
, tempstr
);
2117 slength
= strlcpy(tempstr
, (char *)comdata
,
2119 comdata
+= (slength
+1);
2122 if (flags
& F_DTAIL
)
2124 "%s = %s", label
, tempstr
);
2126 tl
= snprintf(outstr
, outsz
,
2127 " %s=%s", label
, tempstr
);
2133 format
+= (strlen(format
) + 1);
2134 valuetype
= format
[0];