xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c (revision 3e739001e717c71549822a6b2a5c89b3456ff167)
1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * This file and its contents are supplied under the terms of the
3a90cf9f2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4a90cf9f2SGordon Ross  * You may only use this file in accordance with the terms of version
5a90cf9f2SGordon Ross  * 1.0 of the CDDL.
6a90cf9f2SGordon Ross  *
7a90cf9f2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8a90cf9f2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9a90cf9f2SGordon Ross  * http://www.illumos.org/license/CDDL.
10a90cf9f2SGordon Ross  */
11a90cf9f2SGordon Ross 
12a90cf9f2SGordon Ross /*
13*3e739001SGordon Ross  * Copyright 2013-2021 Tintri by DDN, Inc. All rights reserved.
14b716e3d0SGordon Ross  * Copyright 2022 RackTop Systems, Inc.
15a90cf9f2SGordon Ross  */
16a90cf9f2SGordon Ross 
17a90cf9f2SGordon Ross /*
18a90cf9f2SGordon Ross  * Dispatch function for SMB2_NEGOTIATE
19a90cf9f2SGordon Ross  */
20a90cf9f2SGordon Ross 
21a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
22a90cf9f2SGordon Ross #include <smbsrv/smb2.h>
234e065a9fSAlexander Stetsenko #include <sys/random.h>
24ebc5aadbSAndrew Stormont 
25b716e3d0SGordon Ross /*
26b716e3d0SGordon Ross  * Note from [MS-SMB2] Sec. 2.2.3:  Windows servers return
27b716e3d0SGordon Ross  * invalid parameter if the dialect count is greater than 64
28b716e3d0SGordon Ross  * This is here (and not in smb2.h) because this is technically
29b716e3d0SGordon Ross  * an implementation detail, not protocol specification.
30b716e3d0SGordon Ross  */
31b716e3d0SGordon Ross #define	SMB2_NEGOTIATE_MAX_DIALECTS	64
32b716e3d0SGordon Ross 
33a90cf9f2SGordon Ross static int smb2_negotiate_common(smb_request_t *, uint16_t);
34a90cf9f2SGordon Ross 
35700daa96SAndrew Stormont /* List of supported capabilities.  Can be patched for testing. */
36a90cf9f2SGordon Ross uint32_t smb2srv_capabilities =
37a90cf9f2SGordon Ross 	SMB2_CAP_DFS |
3894047d49SGordon Ross 	SMB2_CAP_LEASING |
391160dcf7SMatt Barden 	SMB2_CAP_LARGE_MTU |
408d94f651SGordon Ross 	SMB2_CAP_PERSISTENT_HANDLES |
414f0ce1daSGordon Ross 	SMB2_CAP_ENCRYPTION;
42a90cf9f2SGordon Ross 
438d94f651SGordon Ross /* These are the only capabilities defined for SMB2.X */
448d94f651SGordon Ross #define	SMB_2X_CAPS (SMB2_CAP_DFS | SMB2_CAP_LEASING | SMB2_CAP_LARGE_MTU)
458d94f651SGordon Ross 
46a90cf9f2SGordon Ross /*
47a90cf9f2SGordon Ross  * These are not intended as customer tunables, but dev. & test folks
48a90cf9f2SGordon Ross  * might want to adjust them (with caution).
49a90cf9f2SGordon Ross  *
50a90cf9f2SGordon Ross  * smb2_tcp_bufsize is the TCP buffer size, applied to the network socket
51a90cf9f2SGordon Ross  * with setsockopt SO_SNDBUF, SO_RCVBUF.  These set the TCP window size.
52a90cf9f2SGordon Ross  * This is also used as a "sanity limit" for internal send/reply message
53a90cf9f2SGordon Ross  * allocations.  Note that with compounding SMB2 messages may contain
54a90cf9f2SGordon Ross  * multiple requests/responses.  This size should be large enough for
55a90cf9f2SGordon Ross  * at least a few SMB2 requests, and at least 2X smb2_max_rwsize.
56a90cf9f2SGordon Ross  *
57a90cf9f2SGordon Ross  * smb2_max_rwsize is what we put in the SMB2 negotiate response to tell
58a90cf9f2SGordon Ross  * the client the largest read and write request size we'll support.
59*3e739001SGordon Ross  * One megabyte is a compromise between efficiency on fast networks
60*3e739001SGordon Ross  * and memory consumption (for the buffers) on the server side.
61a90cf9f2SGordon Ross  *
62a90cf9f2SGordon Ross  * smb2_max_trans is the largest "transact" send or receive, which is
63a90cf9f2SGordon Ross  * used for directory listings and info set/get operations.
64a90cf9f2SGordon Ross  */
65a90cf9f2SGordon Ross uint32_t smb2_tcp_bufsize = (1<<22);	/* 4MB */
66*3e739001SGordon Ross uint32_t smb2_max_rwsize = (1<<20);	/* 1MB */
67a90cf9f2SGordon Ross uint32_t smb2_max_trans  = (1<<16);	/* 64KB */
68a90cf9f2SGordon Ross 
69a90cf9f2SGordon Ross /*
70aa321b3cSDan McDonald  * With clients (e.g. HP scanners) that don't advertise SMB2_CAP_LARGE_MTU
71aa321b3cSDan McDonald  * (including all clients using dialect < SMB 2.1), use a "conservative" value
72aa321b3cSDan McDonald  * for max r/w size because some older clients misbehave with larger values.
73aa321b3cSDan McDonald  * 64KB is recommended in the [MS-SMB2] spec.  (3.3.5.3.1 SMB 2.1 or SMB 3.x
74aa321b3cSDan McDonald  * Support) as the minimum so we'll use that.
75aa321b3cSDan McDonald  */
76aa321b3cSDan McDonald uint32_t smb2_old_rwsize = (1<<16);	/* 64KB */
77aa321b3cSDan McDonald 
78aa321b3cSDan McDonald /*
79a90cf9f2SGordon Ross  * List of all SMB2 versions we implement.  Note that the
803e2c0c09SMatt Barden  * versions we support may be limited by the
813e2c0c09SMatt Barden  * _cfg.skc_max_protocol and min_protocol settings.
82a90cf9f2SGordon Ross  */
83a90cf9f2SGordon Ross static uint16_t smb2_versions[] = {
84a90cf9f2SGordon Ross 	0x202,	/* SMB 2.002 */
85a90cf9f2SGordon Ross 	0x210,	/* SMB 2.1 */
86c51c88bdSMatt Barden 	0x300,	/* SMB 3.0 */
87dfa42fabSMatt Barden 	0x302,	/* SMB 3.02 */
884e065a9fSAlexander Stetsenko 	0x311,	/* SMB 3.11 */
89a90cf9f2SGordon Ross };
90a90cf9f2SGordon Ross static uint16_t smb2_nversions =
91a90cf9f2SGordon Ross     sizeof (smb2_versions) / sizeof (smb2_versions[0]);
92a90cf9f2SGordon Ross 
934e065a9fSAlexander Stetsenko enum smb2_neg_ctx_type {
944e065a9fSAlexander Stetsenko 	SMB2_PREAUTH_INTEGRITY_CAPS		= 1,
954e065a9fSAlexander Stetsenko 	SMB2_ENCRYPTION_CAPS			= 2,
964e065a9fSAlexander Stetsenko 	SMB2_COMPRESSION_CAPS			= 3,	/* not imlemented */
974e065a9fSAlexander Stetsenko 	SMB2_NETNAME_NEGOTIATE_CONTEXT_ID	= 5	/* not imlemented */
984e065a9fSAlexander Stetsenko };
994e065a9fSAlexander Stetsenko 
1004e065a9fSAlexander Stetsenko typedef struct smb2_negotiate_ctx {
1014e065a9fSAlexander Stetsenko 	uint16_t	type;
1024e065a9fSAlexander Stetsenko 	uint16_t	datalen;
1034e065a9fSAlexander Stetsenko } smb2_neg_ctx_t;
1044e065a9fSAlexander Stetsenko 
1054e065a9fSAlexander Stetsenko #define	SMB31_PREAUTH_CTX_SALT_LEN	32
1064e065a9fSAlexander Stetsenko 
1074e065a9fSAlexander Stetsenko /*
10874e3b2c7SAndy Fiddaman  * SMB 3.1.1 originally specified a single hashing algorithm - SHA-512 - and
1094e065a9fSAlexander Stetsenko  * two encryption ones - AES-128-CCM and AES-128-GCM.
11074e3b2c7SAndy Fiddaman  * Windows Server 2022 and Windows 11 introduced two further encryption
11174e3b2c7SAndy Fiddaman  * algorithms - AES-256-CCM and AES-256-GCM.
1124e065a9fSAlexander Stetsenko  */
1134e065a9fSAlexander Stetsenko #define	MAX_HASHID_NUM	(1)
114a4568e19SAlexander Stetsenko #define	MAX_CIPHER_NUM	(8)
1154e065a9fSAlexander Stetsenko 
1164e065a9fSAlexander Stetsenko typedef struct smb2_preauth_integrity_caps {
1174e065a9fSAlexander Stetsenko 	uint16_t	picap_hash_count;
1184e065a9fSAlexander Stetsenko 	uint16_t	picap_salt_len;
1194e065a9fSAlexander Stetsenko 	uint16_t	picap_hash_id;
1204e065a9fSAlexander Stetsenko 	uint8_t		picap_salt[SMB31_PREAUTH_CTX_SALT_LEN];
1214e065a9fSAlexander Stetsenko } smb2_preauth_caps_t;
1224e065a9fSAlexander Stetsenko 
1234e065a9fSAlexander Stetsenko typedef struct smb2_encryption_caps {
1244e065a9fSAlexander Stetsenko 	uint16_t	encap_cipher_count;
1254e065a9fSAlexander Stetsenko 	uint16_t	encap_cipher_ids[MAX_CIPHER_NUM];
1264e065a9fSAlexander Stetsenko } smb2_encrypt_caps_t;
1274e065a9fSAlexander Stetsenko 
1284e065a9fSAlexander Stetsenko /*
1294e065a9fSAlexander Stetsenko  * The contexts we support
1304e065a9fSAlexander Stetsenko  */
1314e065a9fSAlexander Stetsenko typedef struct smb2_preauth_neg_ctx {
1324e065a9fSAlexander Stetsenko 	smb2_neg_ctx_t		neg_ctx;
1334e065a9fSAlexander Stetsenko 	smb2_preauth_caps_t	preauth_caps;
1344e065a9fSAlexander Stetsenko } smb2_preauth_neg_ctx_t;
1354e065a9fSAlexander Stetsenko 
1364e065a9fSAlexander Stetsenko typedef struct smb2_encrypt_neg_ctx {
1374e065a9fSAlexander Stetsenko 	smb2_neg_ctx_t		neg_ctx;
1384e065a9fSAlexander Stetsenko 	smb2_encrypt_caps_t	encrypt_caps;
1394e065a9fSAlexander Stetsenko } smb2_encrypt_neg_ctx_t;
1404e065a9fSAlexander Stetsenko 
1414e065a9fSAlexander Stetsenko typedef struct smb2_neg_ctxs {
1424e065a9fSAlexander Stetsenko 	uint32_t		offset;
1434e065a9fSAlexander Stetsenko 	uint16_t		count;
1444e065a9fSAlexander Stetsenko 	smb2_preauth_neg_ctx_t	preauth_ctx;
1454e065a9fSAlexander Stetsenko 	smb2_encrypt_neg_ctx_t	encrypt_ctx;
1464e065a9fSAlexander Stetsenko } smb2_neg_ctxs_t;
1474e065a9fSAlexander Stetsenko 
1484e065a9fSAlexander Stetsenko #define	NEG_CTX_INFO_OFFSET	(SMB2_HDR_SIZE + 28)
1494e065a9fSAlexander Stetsenko #define	NEG_CTX_OFFSET_OFFSET	(SMB2_HDR_SIZE + 64)
1504e065a9fSAlexander Stetsenko #define	NEG_CTX_MAX_COUNT	(16)
1514e065a9fSAlexander Stetsenko #define	NEG_CTX_MAX_DATALEN	(256)
1524e065a9fSAlexander Stetsenko 
1534e065a9fSAlexander Stetsenko #define	STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP	(0xC05D0000)
1544e065a9fSAlexander Stetsenko 
1554e065a9fSAlexander Stetsenko #define	STATUS_PREAUTH_HASH_OVERLAP \
1564e065a9fSAlexander Stetsenko     STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP
1574e065a9fSAlexander Stetsenko 
158b716e3d0SGordon Ross typedef struct smb2_arg_negotiate {
159b716e3d0SGordon Ross 	struct smb2_neg_ctxs	neg_in_ctxs;
160b716e3d0SGordon Ross 	struct smb2_neg_ctxs	neg_out_ctxs;
161b716e3d0SGordon Ross 	uint16_t		neg_dialect_cnt;
162b716e3d0SGordon Ross 	uint16_t		neg_dialects[SMB2_NEGOTIATE_MAX_DIALECTS];
163b716e3d0SGordon Ross 	uint16_t		neg_highest_dialect;
164b716e3d0SGordon Ross } smb2_arg_negotiate_t;
165b716e3d0SGordon Ross 
166b716e3d0SGordon Ross 
167b716e3d0SGordon Ross static boolean_t
smb2_supported_version(smb_session_t * s,uint16_t version)168b716e3d0SGordon Ross smb2_supported_version(smb_session_t *s, uint16_t version)
169b716e3d0SGordon Ross {
170b716e3d0SGordon Ross 	int i;
171b716e3d0SGordon Ross 
172b716e3d0SGordon Ross 	if (version > s->s_cfg.skc_max_protocol ||
173b716e3d0SGordon Ross 	    version < s->s_cfg.skc_min_protocol)
174b716e3d0SGordon Ross 		return (B_FALSE);
175b716e3d0SGordon Ross 	for (i = 0; i < smb2_nversions; i++)
176b716e3d0SGordon Ross 		if (version == smb2_versions[i])
177b716e3d0SGordon Ross 			return (B_TRUE);
178b716e3d0SGordon Ross 	return (B_FALSE);
179b716e3d0SGordon Ross }
180b716e3d0SGordon Ross 
181b716e3d0SGordon Ross static uint16_t
smb2_find_best_dialect(smb_session_t * s,uint16_t cl_versions[],uint16_t version_cnt)182b716e3d0SGordon Ross smb2_find_best_dialect(smb_session_t *s, uint16_t cl_versions[],
183b716e3d0SGordon Ross     uint16_t version_cnt)
184b716e3d0SGordon Ross {
185b716e3d0SGordon Ross 	uint16_t best_version = 0;
186b716e3d0SGordon Ross 	int i;
187b716e3d0SGordon Ross 
188b716e3d0SGordon Ross 	for (i = 0; i < version_cnt; i++)
189b716e3d0SGordon Ross 		if (smb2_supported_version(s, cl_versions[i]) &&
190b716e3d0SGordon Ross 		    best_version < cl_versions[i])
191b716e3d0SGordon Ross 			best_version = cl_versions[i];
192b716e3d0SGordon Ross 
193b716e3d0SGordon Ross 	return (best_version);
194b716e3d0SGordon Ross }
195b716e3d0SGordon Ross 
1964e065a9fSAlexander Stetsenko /*
1974e065a9fSAlexander Stetsenko  * This function should be called only for dialect >= 0x311
1984e065a9fSAlexander Stetsenko  * Negotiate context list should contain exactly one
1994e065a9fSAlexander Stetsenko  * SMB2_PREAUTH_INTEGRITY_CAPS context.
2004e065a9fSAlexander Stetsenko  * Otherwise STATUS_INVALID_PARAMETER.
2014e065a9fSAlexander Stetsenko  * It should contain at least 1 hash algorith what server does support.
2024e065a9fSAlexander Stetsenko  * Otehrwise STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP.
2034e065a9fSAlexander Stetsenko  */
2044e065a9fSAlexander Stetsenko static uint32_t
smb31_decode_neg_ctxs(smb_request_t * sr)205b716e3d0SGordon Ross smb31_decode_neg_ctxs(smb_request_t *sr)
2064e065a9fSAlexander Stetsenko {
2074e065a9fSAlexander Stetsenko 	smb_session_t *s = sr->session;
208b716e3d0SGordon Ross 	smb2_arg_negotiate_t *nego = sr->arg.other;
209b716e3d0SGordon Ross 	smb2_neg_ctxs_t *neg_ctxs = &nego->neg_in_ctxs;
2104e065a9fSAlexander Stetsenko 	smb2_preauth_caps_t *picap = &neg_ctxs->preauth_ctx.preauth_caps;
2114e065a9fSAlexander Stetsenko 	smb2_encrypt_caps_t *encap = &neg_ctxs->encrypt_ctx.encrypt_caps;
212dee7ba86SAlexander Stetsenko 	boolean_t found_sha512 = B_FALSE;
213dee7ba86SAlexander Stetsenko 	boolean_t found_cipher = B_FALSE;
214b0bb0d63SGordon Ross 	uint32_t ciphers = sr->sr_server->sv_cfg.skc_encrypt_ciphers;
2154e065a9fSAlexander Stetsenko 	uint32_t status = 0;
2164e065a9fSAlexander Stetsenko 	int32_t skip;
2174e065a9fSAlexander Stetsenko 	int found_preauth_ctx = 0;
2184e065a9fSAlexander Stetsenko 	int found_encrypt_ctx = 0;
2194e065a9fSAlexander Stetsenko 	int cnt, i;
2204e065a9fSAlexander Stetsenko 	int rc;
2214e065a9fSAlexander Stetsenko 
2224e065a9fSAlexander Stetsenko 	/*
2234e065a9fSAlexander Stetsenko 	 * There should be exactly 1 SMB2_PREAUTH_INTEGRITY_CAPS negotiate ctx.
2244e065a9fSAlexander Stetsenko 	 * SMB2_ENCRYPTION_CAPS is optional one.
2254e065a9fSAlexander Stetsenko 	 * If there is no contexts or there are to many then stop parsing.
2264e065a9fSAlexander Stetsenko 	 */
2274e065a9fSAlexander Stetsenko 	cnt = neg_ctxs->count;
2284e065a9fSAlexander Stetsenko 	if (cnt < 1 || cnt > NEG_CTX_MAX_COUNT) {
2294e065a9fSAlexander Stetsenko 		status = NT_STATUS_INVALID_PARAMETER;
2304e065a9fSAlexander Stetsenko 		goto errout;
2314e065a9fSAlexander Stetsenko 	}
2324e065a9fSAlexander Stetsenko 
2334e065a9fSAlexander Stetsenko 	/*
2344e065a9fSAlexander Stetsenko 	 * Cannot proceed parsing if the first context isn't aligned by 8.
2354e065a9fSAlexander Stetsenko 	 */
2364e065a9fSAlexander Stetsenko 	if (neg_ctxs->offset % 8 != 0) {
2374e065a9fSAlexander Stetsenko 		status = NT_STATUS_INVALID_PARAMETER;
2384e065a9fSAlexander Stetsenko 		goto errout;
2394e065a9fSAlexander Stetsenko 	}
2404e065a9fSAlexander Stetsenko 
2414e065a9fSAlexander Stetsenko 	if ((skip = neg_ctxs->offset - sr->command.chain_offset) != 0 &&
2424e065a9fSAlexander Stetsenko 	    smb_mbc_decodef(&sr->command, "#.", skip) != 0) {
2434e065a9fSAlexander Stetsenko 		status = NT_STATUS_INVALID_PARAMETER;
2444e065a9fSAlexander Stetsenko 		goto errout;
2454e065a9fSAlexander Stetsenko 	}
2464e065a9fSAlexander Stetsenko 
2474e065a9fSAlexander Stetsenko 	/*
2484e065a9fSAlexander Stetsenko 	 * Parse negotiate contexts. Ignore non-decoding errors to fill
2494e065a9fSAlexander Stetsenko 	 * as much as possible data for dtrace probe.
2504e065a9fSAlexander Stetsenko 	 */
2514e065a9fSAlexander Stetsenko 	for (i = 0; i < cnt; i++) {
2524e065a9fSAlexander Stetsenko 		smb2_neg_ctx_t neg_ctx;
2534e065a9fSAlexander Stetsenko 		int32_t ctx_end_off;
2544e065a9fSAlexander Stetsenko 		int32_t ctx_next_off;
2554e065a9fSAlexander Stetsenko 
2564e065a9fSAlexander Stetsenko 		if (i > 0) {
2574e065a9fSAlexander Stetsenko 			if ((skip = ctx_next_off - ctx_end_off) != 0 &&
2584e065a9fSAlexander Stetsenko 			    smb_mbc_decodef(&sr->command, "#.", skip) != 0) {
2594e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
2604e065a9fSAlexander Stetsenko 				goto errout;
2614e065a9fSAlexander Stetsenko 			}
2624e065a9fSAlexander Stetsenko 		}
2634e065a9fSAlexander Stetsenko 
2644e065a9fSAlexander Stetsenko 		rc = smb_mbc_decodef(
2654e065a9fSAlexander Stetsenko 		    &sr->command, "ww4.",
2664e065a9fSAlexander Stetsenko 		    &neg_ctx.type,	/* w */
2674e065a9fSAlexander Stetsenko 		    &neg_ctx.datalen);	/* w */
2684e065a9fSAlexander Stetsenko 		if (rc != 0) {
2694e065a9fSAlexander Stetsenko 			status = NT_STATUS_INVALID_PARAMETER;
2704e065a9fSAlexander Stetsenko 			goto errout;
2714e065a9fSAlexander Stetsenko 		}
2724e065a9fSAlexander Stetsenko 
2734e065a9fSAlexander Stetsenko 		/*
2744e065a9fSAlexander Stetsenko 		 * We got something crazy
2754e065a9fSAlexander Stetsenko 		 */
2764e065a9fSAlexander Stetsenko 		if (neg_ctx.datalen > NEG_CTX_MAX_DATALEN) {
2774e065a9fSAlexander Stetsenko 			status = NT_STATUS_INVALID_PARAMETER;
2784e065a9fSAlexander Stetsenko 			goto errout;
2794e065a9fSAlexander Stetsenko 		}
2804e065a9fSAlexander Stetsenko 
2814e065a9fSAlexander Stetsenko 		ctx_end_off = sr->command.chain_offset + neg_ctx.datalen;
2824e065a9fSAlexander Stetsenko 		ctx_next_off = P2ROUNDUP(ctx_end_off, 8);
2834e065a9fSAlexander Stetsenko 
2844e065a9fSAlexander Stetsenko 		switch (neg_ctx.type) {
2854e065a9fSAlexander Stetsenko 		case SMB2_PREAUTH_INTEGRITY_CAPS:
2864e065a9fSAlexander Stetsenko 			memcpy(&neg_ctxs->preauth_ctx.neg_ctx, &neg_ctx,
2874e065a9fSAlexander Stetsenko 			    sizeof (neg_ctx));
2884e065a9fSAlexander Stetsenko 
2894e065a9fSAlexander Stetsenko 			if (found_preauth_ctx++ != 0) {
2904e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
2914e065a9fSAlexander Stetsenko 				continue;
2924e065a9fSAlexander Stetsenko 			}
2934e065a9fSAlexander Stetsenko 
2944e065a9fSAlexander Stetsenko 			rc = smb_mbc_decodef(
2954e065a9fSAlexander Stetsenko 			    &sr->command, "ww",
2964e065a9fSAlexander Stetsenko 			    &picap->picap_hash_count,	/* w */
2974e065a9fSAlexander Stetsenko 			    &picap->picap_salt_len);	/* w */
2984e065a9fSAlexander Stetsenko 			if (rc != 0 || picap->picap_hash_count >
2994e065a9fSAlexander Stetsenko 			    MAX_HASHID_NUM) {
3004e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
3014e065a9fSAlexander Stetsenko 				goto errout;
3024e065a9fSAlexander Stetsenko 			}
3034e065a9fSAlexander Stetsenko 
3044e065a9fSAlexander Stetsenko 			/*
3054e065a9fSAlexander Stetsenko 			 * Get hash id
3064e065a9fSAlexander Stetsenko 			 */
3074e065a9fSAlexander Stetsenko 			rc = smb_mbc_decodef(
3084e065a9fSAlexander Stetsenko 			    &sr->command, "#w",
3094e065a9fSAlexander Stetsenko 			    picap->picap_hash_count,
3104e065a9fSAlexander Stetsenko 			    &picap->picap_hash_id);	/* w */
3114e065a9fSAlexander Stetsenko 			if (rc != 0) {
3124e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
3134e065a9fSAlexander Stetsenko 				goto errout;
3144e065a9fSAlexander Stetsenko 			}
3154e065a9fSAlexander Stetsenko 
3164e065a9fSAlexander Stetsenko 			/*
3174e065a9fSAlexander Stetsenko 			 * Get salt
3184e065a9fSAlexander Stetsenko 			 */
3194e065a9fSAlexander Stetsenko 			rc = smb_mbc_decodef(
3204e065a9fSAlexander Stetsenko 			    &sr->command, "#c",
3214e065a9fSAlexander Stetsenko 			    sizeof (picap->picap_salt),
3224e065a9fSAlexander Stetsenko 			    &picap->picap_salt[0]);	/* w */
3234e065a9fSAlexander Stetsenko 			if (rc != 0) {
3244e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
3254e065a9fSAlexander Stetsenko 				goto errout;
3264e065a9fSAlexander Stetsenko 			}
3274e065a9fSAlexander Stetsenko 
3284e065a9fSAlexander Stetsenko 			/*
3294e065a9fSAlexander Stetsenko 			 * In SMB 0x311 there should be exactly 1 preauth
3304e065a9fSAlexander Stetsenko 			 * negotiate context, and there should be exactly 1
3314e065a9fSAlexander Stetsenko 			 * hash value in the list - SHA512.
3324e065a9fSAlexander Stetsenko 			 */
3334e065a9fSAlexander Stetsenko 			if (picap->picap_hash_count != 1) {
3344e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
3354e065a9fSAlexander Stetsenko 				continue;
3364e065a9fSAlexander Stetsenko 			}
3374e065a9fSAlexander Stetsenko 
3384e065a9fSAlexander Stetsenko 			if (picap->picap_hash_id == SMB3_HASH_SHA512)
339dee7ba86SAlexander Stetsenko 				found_sha512 = B_TRUE;
3404e065a9fSAlexander Stetsenko 			break;
3414e065a9fSAlexander Stetsenko 		case SMB2_ENCRYPTION_CAPS:
3424e065a9fSAlexander Stetsenko 			memcpy(&neg_ctxs->preauth_ctx.neg_ctx, &neg_ctx,
3434e065a9fSAlexander Stetsenko 			    sizeof (neg_ctx));
3444e065a9fSAlexander Stetsenko 
3454e065a9fSAlexander Stetsenko 			if (found_encrypt_ctx++ != 0) {
3464e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
3474e065a9fSAlexander Stetsenko 				continue;
3484e065a9fSAlexander Stetsenko 			}
3494e065a9fSAlexander Stetsenko 
3504e065a9fSAlexander Stetsenko 			rc = smb_mbc_decodef(
3514e065a9fSAlexander Stetsenko 			    &sr->command, "w",
3524e065a9fSAlexander Stetsenko 			    &encap->encap_cipher_count);	/* w */
3534e065a9fSAlexander Stetsenko 			if (rc != 0 || encap->encap_cipher_count >
3544e065a9fSAlexander Stetsenko 			    MAX_CIPHER_NUM) {
3554e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
3564e065a9fSAlexander Stetsenko 				goto errout;
3574e065a9fSAlexander Stetsenko 			}
3584e065a9fSAlexander Stetsenko 
3594e065a9fSAlexander Stetsenko 			/*
3604e065a9fSAlexander Stetsenko 			 * Get cipher list
3614e065a9fSAlexander Stetsenko 			 */
3624e065a9fSAlexander Stetsenko 			rc = smb_mbc_decodef(
3634e065a9fSAlexander Stetsenko 			    &sr->command, "#w",
3644e065a9fSAlexander Stetsenko 			    encap->encap_cipher_count,
3654e065a9fSAlexander Stetsenko 			    &encap->encap_cipher_ids[0]);	/* w */
3664e065a9fSAlexander Stetsenko 			if (rc != 0) {
3674e065a9fSAlexander Stetsenko 				status = NT_STATUS_INVALID_PARAMETER;
3684e065a9fSAlexander Stetsenko 				goto errout;
3694e065a9fSAlexander Stetsenko 			}
3704e065a9fSAlexander Stetsenko 
371dee7ba86SAlexander Stetsenko 			/*
372dee7ba86SAlexander Stetsenko 			 * Select the first enabled cipher.
373dee7ba86SAlexander Stetsenko 			 * Client should list more prioritized ciphers first.
374dee7ba86SAlexander Stetsenko 			 */
3754e065a9fSAlexander Stetsenko 			for (int k = 0; k < encap->encap_cipher_count; k++) {
376dee7ba86SAlexander Stetsenko 				uint16_t c = encap->encap_cipher_ids[k];
377dee7ba86SAlexander Stetsenko 
378a4568e19SAlexander Stetsenko 				if (c <= SMB3_CIPHER_MAX &&
379a4568e19SAlexander Stetsenko 				    (SMB3_CIPHER_BIT(c) & ciphers) != 0) {
380dee7ba86SAlexander Stetsenko 					s->smb31_enc_cipherid = c;
381dee7ba86SAlexander Stetsenko 					found_cipher = B_TRUE;
3824e065a9fSAlexander Stetsenko 					break;
3834e065a9fSAlexander Stetsenko 				}
3844e065a9fSAlexander Stetsenko 			}
3854e065a9fSAlexander Stetsenko 			break;
3864e065a9fSAlexander Stetsenko 		default:
3874e065a9fSAlexander Stetsenko 			;
3884e065a9fSAlexander Stetsenko 		}
3894e065a9fSAlexander Stetsenko 	}
3904e065a9fSAlexander Stetsenko 
3914e065a9fSAlexander Stetsenko 	if (status)
3924e065a9fSAlexander Stetsenko 		goto errout;
3934e065a9fSAlexander Stetsenko 
3944e065a9fSAlexander Stetsenko 	/* Not found mandatory SMB2_PREAUTH_INTEGRITY_CAPS ctx */
3954e065a9fSAlexander Stetsenko 	if (found_preauth_ctx != 1 || found_encrypt_ctx > 1) {
3964e065a9fSAlexander Stetsenko 		status = NT_STATUS_INVALID_PARAMETER;
3974e065a9fSAlexander Stetsenko 		goto errout;
3984e065a9fSAlexander Stetsenko 	}
3994e065a9fSAlexander Stetsenko 
400dee7ba86SAlexander Stetsenko 	if (!found_sha512) {
4014e065a9fSAlexander Stetsenko 		status = STATUS_PREAUTH_HASH_OVERLAP;
4024e065a9fSAlexander Stetsenko 		goto errout;
4034e065a9fSAlexander Stetsenko 	}
4044e065a9fSAlexander Stetsenko 
4054e065a9fSAlexander Stetsenko 	s->smb31_preauth_hashid = SMB3_HASH_SHA512;
4064e065a9fSAlexander Stetsenko 
407dee7ba86SAlexander Stetsenko 	if (!found_cipher)
4084e065a9fSAlexander Stetsenko 		s->smb31_enc_cipherid = 0;
4094e065a9fSAlexander Stetsenko 
410ab017dbaSGordon Ross 	/* Initialize out = in */
411ab017dbaSGordon Ross 	nego->neg_out_ctxs = nego->neg_in_ctxs;
412ab017dbaSGordon Ross 
4134e065a9fSAlexander Stetsenko errout:
4144e065a9fSAlexander Stetsenko 	return (status);
4154e065a9fSAlexander Stetsenko }
4164e065a9fSAlexander Stetsenko 
4174e065a9fSAlexander Stetsenko static int
smb31_encode_neg_ctxs(smb_request_t * sr)418b716e3d0SGordon Ross smb31_encode_neg_ctxs(smb_request_t *sr)
4194e065a9fSAlexander Stetsenko {
4204e065a9fSAlexander Stetsenko 	smb_session_t *s = sr->session;
421b716e3d0SGordon Ross 	smb2_arg_negotiate_t *nego = sr->arg.other;
422b716e3d0SGordon Ross 	smb2_neg_ctxs_t *neg_ctxs = &nego->neg_out_ctxs;
4234e065a9fSAlexander Stetsenko 	smb2_preauth_caps_t *picap = &neg_ctxs->preauth_ctx.preauth_caps;
4244e065a9fSAlexander Stetsenko 	smb2_encrypt_caps_t *encap = &neg_ctxs->encrypt_ctx.encrypt_caps;
4254e065a9fSAlexander Stetsenko 	uint16_t salt_len = sizeof (picap->picap_salt);
4264e065a9fSAlexander Stetsenko 	uint32_t preauth_ctx_len = 6 + salt_len;
4274e065a9fSAlexander Stetsenko 	uint32_t enc_ctx_len = 4;
4284e065a9fSAlexander Stetsenko 	uint32_t neg_ctx_off = NEG_CTX_OFFSET_OFFSET +
4294e065a9fSAlexander Stetsenko 	    P2ROUNDUP(sr->sr_cfg->skc_negtok_len, 8);
4304e065a9fSAlexander Stetsenko 	uint32_t rc;
4314e065a9fSAlexander Stetsenko 
4324e065a9fSAlexander Stetsenko 	if ((rc = smb_mbc_put_align(&sr->reply, 8)) != 0)
4334e065a9fSAlexander Stetsenko 		return (rc);
4344e065a9fSAlexander Stetsenko 
4354e065a9fSAlexander Stetsenko 	ASSERT3S(neg_ctx_off, ==, sr->reply.chain_offset);
4364e065a9fSAlexander Stetsenko 
4374e065a9fSAlexander Stetsenko 	picap->picap_hash_id = s->smb31_preauth_hashid;
4384e065a9fSAlexander Stetsenko 	picap->picap_salt_len = salt_len;
4394e065a9fSAlexander Stetsenko 
4404e065a9fSAlexander Stetsenko 	(void) random_get_pseudo_bytes(picap->picap_salt, salt_len);
4414e065a9fSAlexander Stetsenko 
4424e065a9fSAlexander Stetsenko 	rc = smb_mbc_encodef(
4434e065a9fSAlexander Stetsenko 	    &sr->reply, "ww4.",
4444e065a9fSAlexander Stetsenko 	    SMB2_PREAUTH_INTEGRITY_CAPS,
4454e065a9fSAlexander Stetsenko 	    preauth_ctx_len
4464e065a9fSAlexander Stetsenko 	    /* 4. */); /* reserved */
4474e065a9fSAlexander Stetsenko 	if (rc != 0)
4484e065a9fSAlexander Stetsenko 		return (rc);
4494e065a9fSAlexander Stetsenko 
4504e065a9fSAlexander Stetsenko 	rc = smb_mbc_encodef(
4514e065a9fSAlexander Stetsenko 	    &sr->reply, "www#c",
4524e065a9fSAlexander Stetsenko 	    1,				/* hash algo count */
4534e065a9fSAlexander Stetsenko 	    salt_len,			/* salt length */
4544e065a9fSAlexander Stetsenko 	    s->smb31_preauth_hashid,	/* hash id */
4554e065a9fSAlexander Stetsenko 	    salt_len,			/* salt length */
4564e065a9fSAlexander Stetsenko 	    picap->picap_salt);
457ab017dbaSGordon Ross 	if (rc != 0)
4584e065a9fSAlexander Stetsenko 		return (rc);
4594e065a9fSAlexander Stetsenko 
460ab017dbaSGordon Ross 	/*
461ab017dbaSGordon Ross 	 * If we did not get SMB2_ENCRYPTION_CAPS, don't send one.
462ab017dbaSGordon Ross 	 */
463ab017dbaSGordon Ross 	if (encap->encap_cipher_count == 0)
464ab017dbaSGordon Ross 		return (0);
465ab017dbaSGordon Ross 
466ab017dbaSGordon Ross 	/*
467ab017dbaSGordon Ross 	 * Encode SMB2_ENCRYPTION_CAPS response.
468ab017dbaSGordon Ross 	 */
4694e065a9fSAlexander Stetsenko 	if ((rc = smb_mbc_put_align(&sr->reply, 8)) != 0)
4704e065a9fSAlexander Stetsenko 		return (rc);
4714e065a9fSAlexander Stetsenko 
4724e065a9fSAlexander Stetsenko 	rc = smb_mbc_encodef(
4734e065a9fSAlexander Stetsenko 	    &sr->reply, "ww4.",
4744e065a9fSAlexander Stetsenko 	    SMB2_ENCRYPTION_CAPS,
4754e065a9fSAlexander Stetsenko 	    enc_ctx_len
4764e065a9fSAlexander Stetsenko 	    /* 4. */); /* reserved */
4774e065a9fSAlexander Stetsenko 
4784e065a9fSAlexander Stetsenko 	rc = smb_mbc_encodef(
4794e065a9fSAlexander Stetsenko 	    &sr->reply, "ww",
4804e065a9fSAlexander Stetsenko 	    1,				/* cipher count */
4814e065a9fSAlexander Stetsenko 	    s->smb31_enc_cipherid);	/* encrypt. cipher id */
4824e065a9fSAlexander Stetsenko 
4834e065a9fSAlexander Stetsenko 	return (rc);
4844e065a9fSAlexander Stetsenko }
4854e065a9fSAlexander Stetsenko 
486b716e3d0SGordon Ross /*
487b716e3d0SGordon Ross  * Helper for the (SMB1) smb_com_negotiate().  This is the
488b716e3d0SGordon Ross  * very unusual protocol interaction where an SMB1 negotiate
489b716e3d0SGordon Ross  * gets an SMB2 negotiate response.  This is the normal way
490b716e3d0SGordon Ross  * clients first find out if the server supports SMB2.
491b716e3d0SGordon Ross  *
492b716e3d0SGordon Ross  * Note: This sends an SMB2 reply _itself_ and then returns
493b716e3d0SGordon Ross  * SDRC_NO_REPLY so the caller will not send an SMB1 reply.
494b716e3d0SGordon Ross  * Also, this is called directly from the reader thread, so
495b716e3d0SGordon Ross  * we know this is the only thread using this session.
496b716e3d0SGordon Ross  * Otherwise, this is similar to smb2_newrq_negotiate().
497b716e3d0SGordon Ross  *
498b716e3d0SGordon Ross  * The caller frees this request.
499b716e3d0SGordon Ross  */
500b716e3d0SGordon Ross smb_sdrc_t
smb1_negotiate_smb2(smb_request_t * sr)501b716e3d0SGordon Ross smb1_negotiate_smb2(smb_request_t *sr)
502b716e3d0SGordon Ross {
503b716e3d0SGordon Ross 	smb_session_t *s = sr->session;
504b716e3d0SGordon Ross 	smb_arg_negotiate_t *negprot = sr->sr_negprot;
505b716e3d0SGordon Ross 	uint16_t smb2_version;
506b716e3d0SGordon Ross 
507b716e3d0SGordon Ross 	/*
508b716e3d0SGordon Ross 	 * Note: In the SMB1 negotiate command handler, we
509b716e3d0SGordon Ross 	 * agreed with one of the SMB2 dialects.  If that
510b716e3d0SGordon Ross 	 * dialect was "SMB 2.002", we'll respond here with
511b716e3d0SGordon Ross 	 * version 0x202 and negotiation is done.  If that
512b716e3d0SGordon Ross 	 * dialect was "SMB 2.???", we'll respond here with
513b716e3d0SGordon Ross 	 * the "wildcard" version 0x2FF, and the client will
514b716e3d0SGordon Ross 	 * come back with an SMB2 negotiate.
515b716e3d0SGordon Ross 	 */
516b716e3d0SGordon Ross 	switch (negprot->ni_dialect) {
517b716e3d0SGordon Ross 	case DIALECT_SMB2002:	/* SMB 2.002 (a.k.a. SMB2.0) */
518b716e3d0SGordon Ross 		smb2_version = SMB_VERS_2_002;
519b716e3d0SGordon Ross 		s->dialect = smb2_version;
520b716e3d0SGordon Ross 		s->s_state = SMB_SESSION_STATE_NEGOTIATED;
521b716e3d0SGordon Ross 		/* Allow normal SMB2 requests now. */
522b716e3d0SGordon Ross 		s->newrq_func = smb2sr_newrq;
523b716e3d0SGordon Ross 		break;
524b716e3d0SGordon Ross 	case DIALECT_SMB2XXX:	/* SMB 2.??? (wildcard vers) */
525b716e3d0SGordon Ross 		/*
526b716e3d0SGordon Ross 		 * Expecting an SMB2 negotiate next, so keep the
527b716e3d0SGordon Ross 		 * initial s->newrq_func.
528b716e3d0SGordon Ross 		 */
529b716e3d0SGordon Ross 		smb2_version = 0x2FF;
530b716e3d0SGordon Ross 		break;
531b716e3d0SGordon Ross 	default:
532b716e3d0SGordon Ross 		return (SDRC_DROP_VC);
533b716e3d0SGordon Ross 	}
534b716e3d0SGordon Ross 
535b716e3d0SGordon Ross 	/*
536b716e3d0SGordon Ross 	 * We did not decode an SMB2 header, so make sure
537b716e3d0SGordon Ross 	 * the SMB2 header fields are initialized.
538b716e3d0SGordon Ross 	 * (Most are zero from smb_request_alloc.)
539b716e3d0SGordon Ross 	 * Also, the SMB1 common dispatch code reserved space
540b716e3d0SGordon Ross 	 * for an SMB1 header, which we need to undo here.
541b716e3d0SGordon Ross 	 */
542b716e3d0SGordon Ross 	sr->smb2_reply_hdr = sr->reply.chain_offset = 0;
543b716e3d0SGordon Ross 	sr->smb2_cmd_code = SMB2_NEGOTIATE;
544b716e3d0SGordon Ross 	sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
545b716e3d0SGordon Ross 
546b716e3d0SGordon Ross 	/*
547b716e3d0SGordon Ross 	 * Also setup SMB2 negotiate args (empty here).
548b716e3d0SGordon Ross 	 * SMB1 args free'd by smb_srm_fini(sr)
549b716e3d0SGordon Ross 	 */
550b716e3d0SGordon Ross 	sr->arg.other = smb_srm_zalloc(sr, sizeof (smb2_arg_negotiate_t));
551b716e3d0SGordon Ross 
552b716e3d0SGordon Ross 	(void) smb2_encode_header(sr, B_FALSE);
553b716e3d0SGordon Ross 	if (smb2_negotiate_common(sr, smb2_version) != 0)
554b716e3d0SGordon Ross 		sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
555b716e3d0SGordon Ross 	if (sr->smb2_status != 0)
556b716e3d0SGordon Ross 		smb2sr_put_error(sr, sr->smb2_status);
557b716e3d0SGordon Ross 	(void) smb2_encode_header(sr, B_TRUE);
558b716e3d0SGordon Ross 
559b716e3d0SGordon Ross 	smb2_send_reply(sr);
560b716e3d0SGordon Ross 
561b716e3d0SGordon Ross 	/*
562b716e3d0SGordon Ross 	 * We sent the reply, so tell the SMB1 dispatch
563b716e3d0SGordon Ross 	 * it should NOT (also) send a reply.
564b716e3d0SGordon Ross 	 */
565b716e3d0SGordon Ross 	return (SDRC_NO_REPLY);
566b716e3d0SGordon Ross }
567b716e3d0SGordon Ross 
568b716e3d0SGordon Ross /*
569b716e3d0SGordon Ross  * SMB2 Negotiate gets special handling.  This is called directly by
570b716e3d0SGordon Ross  * the reader thread (see smbsr_newrq_initial) with what _should_ be
571b716e3d0SGordon Ross  * an SMB2 Negotiate.  Only the "\feSMB" header has been checked
572b716e3d0SGordon Ross  * when this is called, so this needs to check the SMB command,
573b716e3d0SGordon Ross  * if it's Negotiate execute it, then send the reply, etc.
574b716e3d0SGordon Ross  *
575b716e3d0SGordon Ross  * Since this is called directly from the reader thread, we
576b716e3d0SGordon Ross  * know this is the only thread currently using this session.
577b716e3d0SGordon Ross  * This has to duplicate some of what smb2sr_work does as a
578b716e3d0SGordon Ross  * result of bypassing the normal dispatch mechanism.
579b716e3d0SGordon Ross  *
580b716e3d0SGordon Ross  * The caller always frees this request.
581b716e3d0SGordon Ross  *
582b716e3d0SGordon Ross  * Return value is 0 for success, and anything else will
583b716e3d0SGordon Ross  * terminate the reader thread (drop the connection).
584b716e3d0SGordon Ross  */
585a90cf9f2SGordon Ross int
smb2_newrq_negotiate(smb_request_t * sr)586a90cf9f2SGordon Ross smb2_newrq_negotiate(smb_request_t *sr)
587a90cf9f2SGordon Ross {
588a90cf9f2SGordon Ross 	smb_session_t *s = sr->session;
589b716e3d0SGordon Ross 	smb2_arg_negotiate_t *nego;
5901160dcf7SMatt Barden 	int rc;
591b716e3d0SGordon Ross 	uint32_t nctx_status = 0;
592ebc5aadbSAndrew Stormont 	uint32_t status = 0;
593b716e3d0SGordon Ross 	uint32_t neg_ctx_off;
594b716e3d0SGordon Ross 	uint16_t neg_ctx_cnt;
595a90cf9f2SGordon Ross 	uint16_t struct_size;
596b716e3d0SGordon Ross 	uint16_t dialect_cnt;
597a90cf9f2SGordon Ross 	uint16_t best_version;
5984e065a9fSAlexander Stetsenko 
599b716e3d0SGordon Ross 	nego = smb_srm_zalloc(sr, sizeof (smb2_arg_negotiate_t));
600b716e3d0SGordon Ross 	sr->arg.other = nego;	// for dtrace
601a90cf9f2SGordon Ross 
602a90cf9f2SGordon Ross 	sr->smb2_cmd_hdr = sr->command.chain_offset;
603a90cf9f2SGordon Ross 	rc = smb2_decode_header(sr);
604a90cf9f2SGordon Ross 	if (rc != 0)
605a90cf9f2SGordon Ross 		return (rc);
606a90cf9f2SGordon Ross 
607ebc5aadbSAndrew Stormont 	if (sr->smb2_hdr_flags & SMB2_FLAGS_SERVER_TO_REDIR)
608ebc5aadbSAndrew Stormont 		return (-1);
609ebc5aadbSAndrew Stormont 
610a90cf9f2SGordon Ross 	if ((sr->smb2_cmd_code != SMB2_NEGOTIATE) ||
611a90cf9f2SGordon Ross 	    (sr->smb2_next_command != 0))
61293bc28dbSGordon Ross 		return (-1);
613a90cf9f2SGordon Ross 
614a90cf9f2SGordon Ross 	/*
615a90cf9f2SGordon Ross 	 * Decode SMB2 Negotiate (fixed-size part)
616a90cf9f2SGordon Ross 	 */
617a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(
618b716e3d0SGordon Ross 	    &sr->command, "www..l16clw..",
619a90cf9f2SGordon Ross 	    &struct_size,	/* w */
620b716e3d0SGordon Ross 	    &dialect_cnt,	/* w */
6211160dcf7SMatt Barden 	    &s->cli_secmode,	/* w */
622a90cf9f2SGordon Ross 	    /* reserved		(..) */
6231160dcf7SMatt Barden 	    &s->capabilities,	/* l */
624b716e3d0SGordon Ross 	    s->clnt_uuid,	/* 16c */
625b716e3d0SGordon Ross 	    &neg_ctx_off,	/* l */
626b716e3d0SGordon Ross 	    &neg_ctx_cnt);	/* w */
627b716e3d0SGordon Ross 	    /* reserverd	(..) */
628a90cf9f2SGordon Ross 	if (rc != 0)
629a90cf9f2SGordon Ross 		return (rc);
630ebc5aadbSAndrew Stormont 	if (struct_size != 36)
63193bc28dbSGordon Ross 		return (-1);
632a90cf9f2SGordon Ross 
633a90cf9f2SGordon Ross 	/*
634a90cf9f2SGordon Ross 	 * Decode SMB2 Negotiate (variable part)
635ebc5aadbSAndrew Stormont 	 *
636ebc5aadbSAndrew Stormont 	 * Be somewhat tolerant while decoding the variable part
637ebc5aadbSAndrew Stormont 	 * so we can return errors instead of dropping the client.
6384e065a9fSAlexander Stetsenko 	 * Will limit decoding to the size of cli_dialects here,
639b716e3d0SGordon Ross 	 * and do error checks on the decoded dialect_cnt after the
640ebc5aadbSAndrew Stormont 	 * dtrace start probe.
641a90cf9f2SGordon Ross 	 */
642b716e3d0SGordon Ross 	if (dialect_cnt > SMB2_NEGOTIATE_MAX_DIALECTS)
643b716e3d0SGordon Ross 		nego->neg_dialect_cnt = SMB2_NEGOTIATE_MAX_DIALECTS;
644b716e3d0SGordon Ross 	else
645b716e3d0SGordon Ross 		nego->neg_dialect_cnt = dialect_cnt;
646b716e3d0SGordon Ross 	if (nego->neg_dialect_cnt > 0) {
647b716e3d0SGordon Ross 		rc = smb_mbc_decodef(&sr->command, "#w",
648b716e3d0SGordon Ross 		    nego->neg_dialect_cnt,
649b716e3d0SGordon Ross 		    nego->neg_dialects);
650b716e3d0SGordon Ross 		if (rc != 0)
651b716e3d0SGordon Ross 			return (rc);	// short msg
6524e065a9fSAlexander Stetsenko 	}
6534e065a9fSAlexander Stetsenko 
654b716e3d0SGordon Ross 	best_version = smb2_find_best_dialect(s, nego->neg_dialects,
655b716e3d0SGordon Ross 	    nego->neg_dialect_cnt);
6564e065a9fSAlexander Stetsenko 
6574e065a9fSAlexander Stetsenko 	if (best_version >= SMB_VERS_3_11) {
658b716e3d0SGordon Ross 		nego->neg_in_ctxs.offset = neg_ctx_off;
659b716e3d0SGordon Ross 		nego->neg_in_ctxs.count  = neg_ctx_cnt;
660b716e3d0SGordon Ross 		nctx_status = smb31_decode_neg_ctxs(sr);
661b716e3d0SGordon Ross 		/* check nctx_status below */
662ebc5aadbSAndrew Stormont 	}
66393bc28dbSGordon Ross 
66493bc28dbSGordon Ross 	DTRACE_SMB2_START(op__Negotiate, smb_request_t *, sr);
665a90cf9f2SGordon Ross 
666b716e3d0SGordon Ross 	sr->smb2_credit_response = 1;
667ebc5aadbSAndrew Stormont 	sr->smb2_hdr_flags |= SMB2_FLAGS_SERVER_TO_REDIR;
668ebc5aadbSAndrew Stormont 	(void) smb2_encode_header(sr, B_FALSE);
669ebc5aadbSAndrew Stormont 
670b716e3d0SGordon Ross 	/*
671b716e3d0SGordon Ross 	 * NOW start validating things (NOT before here)
672b716e3d0SGordon Ross 	 */
6734e065a9fSAlexander Stetsenko 
674ebc5aadbSAndrew Stormont 	/*
675ebc5aadbSAndrew Stormont 	 * [MS-SMB2] 3.3.5.2.4 Verifying the Signature
676ebc5aadbSAndrew Stormont 	 * "If the SMB2 header of the SMB2 NEGOTIATE request has the
677ebc5aadbSAndrew Stormont 	 * SMB2_FLAGS_SIGNED bit set in the Flags field, the server
678ebc5aadbSAndrew Stormont 	 * MUST fail the request with STATUS_INVALID_PARAMETER."
679ebc5aadbSAndrew Stormont 	 */
680ebc5aadbSAndrew Stormont 	if ((sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0) {
681ebc5aadbSAndrew Stormont 		sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED;
682ebc5aadbSAndrew Stormont 		status = NT_STATUS_INVALID_PARAMETER;
683ebc5aadbSAndrew Stormont 		goto errout;
684ebc5aadbSAndrew Stormont 	}
685ebc5aadbSAndrew Stormont 
686b716e3d0SGordon Ross 	/*
687b716e3d0SGordon Ross 	 * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
688b716e3d0SGordon Ross 	 * "If the DialectCount of the SMB2 NEGOTIATE Request is 0, the
689b716e3d0SGordon Ross 	 * server MUST fail the request with STATUS_INVALID_PARAMETER."
690b716e3d0SGordon Ross 	 * Checking the decoded value here, not the constrained one.
691b716e3d0SGordon Ross 	 */
692b716e3d0SGordon Ross 	if (dialect_cnt == 0 ||
693b716e3d0SGordon Ross 	    dialect_cnt > SMB2_NEGOTIATE_MAX_DIALECTS) {
694b716e3d0SGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
695b716e3d0SGordon Ross 		goto errout;
696b716e3d0SGordon Ross 	}
697b716e3d0SGordon Ross 
698b716e3d0SGordon Ross 	/*
699b716e3d0SGordon Ross 	 * We decoded the offered dialects above, and
700b716e3d0SGordon Ross 	 * determined which was the highest we support.
701b716e3d0SGordon Ross 	 *
702b716e3d0SGordon Ross 	 * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
703b716e3d0SGordon Ross 	 * "If a common dialect is not found, the server MUST fail
704b716e3d0SGordon Ross 	 * the request with STATUS_NOT_SUPPORTED."
705b716e3d0SGordon Ross 	 */
706b716e3d0SGordon Ross 	if (best_version == 0) {
707b716e3d0SGordon Ross 		status = NT_STATUS_NOT_SUPPORTED;
708b716e3d0SGordon Ross 		goto errout;
709b716e3d0SGordon Ross 	}
710b716e3d0SGordon Ross 
711b716e3d0SGordon Ross 	/*
712b716e3d0SGordon Ross 	 * Check for problems with the negotiate contexts.
713b716e3d0SGordon Ross 	 */
714b716e3d0SGordon Ross 	if (nctx_status != 0) {
715b716e3d0SGordon Ross 		status = nctx_status;
716b716e3d0SGordon Ross 		goto errout;
717b716e3d0SGordon Ross 	}
718a90cf9f2SGordon Ross 
719a90cf9f2SGordon Ross 	/* Allow normal SMB2 requests now. */
720b716e3d0SGordon Ross 	s->dialect = best_version;
721a90cf9f2SGordon Ross 	s->s_state = SMB_SESSION_STATE_NEGOTIATED;
722a90cf9f2SGordon Ross 	s->newrq_func = smb2sr_newrq;
723a90cf9f2SGordon Ross 
724ebc5aadbSAndrew Stormont 	if (smb2_negotiate_common(sr, best_version) != 0)
725ebc5aadbSAndrew Stormont 		status = NT_STATUS_INTERNAL_ERROR;
726a90cf9f2SGordon Ross 
7274e065a9fSAlexander Stetsenko 	if (s->dialect >= SMB_VERS_3_11 && status == 0) {
728b716e3d0SGordon Ross 		if (smb31_encode_neg_ctxs(sr) != 0)
7294e065a9fSAlexander Stetsenko 			status = NT_STATUS_INTERNAL_ERROR;
7304e065a9fSAlexander Stetsenko 	}
7314e065a9fSAlexander Stetsenko 
7323e2c0c09SMatt Barden errout:
733ebc5aadbSAndrew Stormont 	sr->smb2_status = status;
73493bc28dbSGordon Ross 	DTRACE_SMB2_DONE(op__Negotiate, smb_request_t *, sr);
73593bc28dbSGordon Ross 
736ebc5aadbSAndrew Stormont 	if (sr->smb2_status != 0)
737ebc5aadbSAndrew Stormont 		smb2sr_put_error(sr, sr->smb2_status);
738ebc5aadbSAndrew Stormont 	(void) smb2_encode_header(sr, B_TRUE);
739ebc5aadbSAndrew Stormont 
7404e065a9fSAlexander Stetsenko 	if (s->dialect >= SMB_VERS_3_11 && sr->smb2_status == 0) {
7414e065a9fSAlexander Stetsenko 		ASSERT3U(s->smb31_preauth_hashid, !=, 0);
7424e065a9fSAlexander Stetsenko 		if (smb31_preauth_sha512_calc(sr, &sr->reply,
7434e065a9fSAlexander Stetsenko 		    s->smb31_preauth_hashval,
7444e065a9fSAlexander Stetsenko 		    s->smb31_preauth_hashval) != 0)
7454e065a9fSAlexander Stetsenko 			cmn_err(CE_WARN, "(1) Preauth hash calculation "
7464e065a9fSAlexander Stetsenko 			    "failed");
7474e065a9fSAlexander Stetsenko 	}
7484e065a9fSAlexander Stetsenko 
74993bc28dbSGordon Ross 	smb2_send_reply(sr);
75093bc28dbSGordon Ross 
75193bc28dbSGordon Ross 	return (rc);
752a90cf9f2SGordon Ross }
753a90cf9f2SGordon Ross 
754a90cf9f2SGordon Ross /*
755a90cf9f2SGordon Ross  * Common parts of SMB2 Negotiate, used for both the
756a90cf9f2SGordon Ross  * SMB1-to-SMB2 style, and straight SMB2 style.
75793bc28dbSGordon Ross  * Do negotiation decisions and encode the reply.
75893bc28dbSGordon Ross  * The caller does the network send.
75993bc28dbSGordon Ross  *
760ebc5aadbSAndrew Stormont  * Return value is 0 for success, else error.
761a90cf9f2SGordon Ross  */
762a90cf9f2SGordon Ross static int
smb2_negotiate_common(smb_request_t * sr,uint16_t version)763a90cf9f2SGordon Ross smb2_negotiate_common(smb_request_t *sr, uint16_t version)
764a90cf9f2SGordon Ross {
765a90cf9f2SGordon Ross 	timestruc_t boot_tv, now_tv;
766a90cf9f2SGordon Ross 	smb_session_t *s = sr->session;
767ab017dbaSGordon Ross 	smb2_arg_negotiate_t *nego = sr->arg.other;
768a90cf9f2SGordon Ross 	int rc;
769aa321b3cSDan McDonald 	uint32_t max_rwsize;
770a90cf9f2SGordon Ross 	uint16_t secmode;
7714e065a9fSAlexander Stetsenko 	uint16_t neg_ctx_cnt = 0;
7724e065a9fSAlexander Stetsenko 	uint32_t neg_ctx_off = 0;
773a90cf9f2SGordon Ross 
774a90cf9f2SGordon Ross 	/*
775a90cf9f2SGordon Ross 	 * Negotiation itself.  First the Security Mode.
776a90cf9f2SGordon Ross 	 */
777a90cf9f2SGordon Ross 	secmode = SMB2_NEGOTIATE_SIGNING_ENABLED;
778ebc5aadbSAndrew Stormont 	if (sr->sr_cfg->skc_signing_required)
779a90cf9f2SGordon Ross 		secmode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
7801160dcf7SMatt Barden 	s->srv_secmode = secmode;
781a90cf9f2SGordon Ross 
782a90cf9f2SGordon Ross 	s->cmd_max_bytes = smb2_tcp_bufsize;
783a90cf9f2SGordon Ross 	s->reply_max_bytes = smb2_tcp_bufsize;
784a90cf9f2SGordon Ross 
785a90cf9f2SGordon Ross 	/*
786a90cf9f2SGordon Ross 	 * "The number of credits held by the client MUST be considered
787a90cf9f2SGordon Ross 	 * as 1 when the connection is established." [MS-SMB2]
788a90cf9f2SGordon Ross 	 * We leave credits at 1 until the first successful
789a90cf9f2SGordon Ross 	 * session setup is completed.
790a90cf9f2SGordon Ross 	 */
791a90cf9f2SGordon Ross 	s->s_cur_credits = s->s_max_credits = 1;
792a90cf9f2SGordon Ross 	sr->smb2_credit_response = 1;
793a90cf9f2SGordon Ross 
794a90cf9f2SGordon Ross 	boot_tv.tv_sec = smb_get_boottime();
795a90cf9f2SGordon Ross 	boot_tv.tv_nsec = 0;
796a90cf9f2SGordon Ross 	now_tv.tv_sec = gethrestime_sec();
797a90cf9f2SGordon Ross 	now_tv.tv_nsec = 0;
798a90cf9f2SGordon Ross 
799a90cf9f2SGordon Ross 	/*
800c51c88bdSMatt Barden 	 * If the version is 0x2FF, we haven't completed negotiate.
801c51c88bdSMatt Barden 	 * Don't initialize until we have our final request.
802c51c88bdSMatt Barden 	 */
803c51c88bdSMatt Barden 	if (version != 0x2FF)
804c51c88bdSMatt Barden 		smb2_sign_init_mech(s);
8054e065a9fSAlexander Stetsenko 	if (version >= 0x311)
8064e065a9fSAlexander Stetsenko 		smb31_preauth_init_mech(s);
807c51c88bdSMatt Barden 
808c51c88bdSMatt Barden 	/*
8091160dcf7SMatt Barden 	 * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
8101160dcf7SMatt Barden 	 *
8118d94f651SGordon Ross 	 * The SMB2.x capabilities are returned without regard for
8128d94f651SGordon Ross 	 * what capabilities the client provided in the request.
8138d94f651SGordon Ross 	 * The SMB3.x capabilities returned are the traditional
814ab017dbaSGordon Ross 	 * logical AND of server and client capabilities, except
815ab017dbaSGordon Ross 	 * for the SMB2.x capabilities which are what the server
816ab017dbaSGordon Ross 	 * supports (regardless of the client capabilities).
8178d94f651SGordon Ross 	 *
8188d94f651SGordon Ross 	 * One additional check: If KCF is missing something we
8198d94f651SGordon Ross 	 * require for encryption, turn off that capability.
8201160dcf7SMatt Barden 	 */
821700daa96SAndrew Stormont 	if (s->dialect < SMB_VERS_2_1) {
822700daa96SAndrew Stormont 		/* SMB 2.002 */
823700daa96SAndrew Stormont 		s->srv_cap = smb2srv_capabilities & SMB2_CAP_DFS;
824700daa96SAndrew Stormont 	} else if (s->dialect < SMB_VERS_3_0) {
8258d94f651SGordon Ross 		/* SMB 2.x */
8268d94f651SGordon Ross 		s->srv_cap = smb2srv_capabilities & SMB_2X_CAPS;
8278d94f651SGordon Ross 	} else {
8288d94f651SGordon Ross 		/* SMB 3.0 or later */
8298d94f651SGordon Ross 		s->srv_cap = smb2srv_capabilities &
8308d94f651SGordon Ross 		    (SMB_2X_CAPS | s->capabilities);
831ab017dbaSGordon Ross 
832ab017dbaSGordon Ross 		if (s->dialect < SMB_VERS_3_11)
833ab017dbaSGordon Ross 			s->smb31_enc_cipherid = SMB3_CIPHER_AES128_CCM;
834ab017dbaSGordon Ross 		/* else from negotiate context */
835ab017dbaSGordon Ross 
8368d94f651SGordon Ross 		if ((s->srv_cap & SMB2_CAP_ENCRYPTION) != 0 &&
8378d94f651SGordon Ross 		    smb3_encrypt_init_mech(s) != 0) {
8388d94f651SGordon Ross 			s->srv_cap &= ~SMB2_CAP_ENCRYPTION;
8394e065a9fSAlexander Stetsenko 		}
8404e065a9fSAlexander Stetsenko 
8414e065a9fSAlexander Stetsenko 		if (s->dialect >= SMB_VERS_3_11) {
842ab017dbaSGordon Ross 			smb2_encrypt_caps_t *encap =
843ab017dbaSGordon Ross 			    &nego->neg_in_ctxs.encrypt_ctx.encrypt_caps;
844ab017dbaSGordon Ross 
845ab017dbaSGordon Ross 			neg_ctx_cnt = 1; // always have preauth
846ab017dbaSGordon Ross 
847ab017dbaSGordon Ross 			if (encap->encap_cipher_count != 0)
848ab017dbaSGordon Ross 				neg_ctx_cnt++;
849ab017dbaSGordon Ross 
8504e065a9fSAlexander Stetsenko 			neg_ctx_off = NEG_CTX_OFFSET_OFFSET +
8514e065a9fSAlexander Stetsenko 			    P2ROUNDUP(sr->sr_cfg->skc_negtok_len, 8);
8524e065a9fSAlexander Stetsenko 
8534e065a9fSAlexander Stetsenko 			ASSERT3U(s->smb31_preauth_hashid, !=, 0);
8544e065a9fSAlexander Stetsenko 
8554e065a9fSAlexander Stetsenko 			if (smb31_preauth_sha512_calc(sr, &sr->command,
8564e065a9fSAlexander Stetsenko 			    s->smb31_preauth_hashval,
8574e065a9fSAlexander Stetsenko 			    s->smb31_preauth_hashval) != 0)
8584e065a9fSAlexander Stetsenko 				cmn_err(CE_WARN, "(0) Preauth hash calculation "
8594e065a9fSAlexander Stetsenko 				    "failed");
8608d94f651SGordon Ross 		}
8618d94f651SGordon Ross 	}
8621160dcf7SMatt Barden 
8631160dcf7SMatt Barden 	/*
864aa321b3cSDan McDonald 	 * See notes above smb2_max_rwsize, smb2_old_rwsize
865aa321b3cSDan McDonald 	 */
866aa321b3cSDan McDonald 	if (s->capabilities & SMB2_CAP_LARGE_MTU)
867aa321b3cSDan McDonald 		max_rwsize = smb2_max_rwsize;
868aa321b3cSDan McDonald 	else
869aa321b3cSDan McDonald 		max_rwsize = smb2_old_rwsize;
870aa321b3cSDan McDonald 
871a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
872a90cf9f2SGordon Ross 	    &sr->reply,
873a90cf9f2SGordon Ross 	    "wwww#cllllTTwwl#c",
874a90cf9f2SGordon Ross 	    65,	/* StructSize */	/* w */
8751160dcf7SMatt Barden 	    s->srv_secmode,		/* w */
876a90cf9f2SGordon Ross 	    version,			/* w */
8774e065a9fSAlexander Stetsenko 	    neg_ctx_cnt,		/* w */
878a90cf9f2SGordon Ross 	    UUID_LEN,			/* # */
879a90cf9f2SGordon Ross 	    &s->s_cfg.skc_machine_uuid, /* c */
8801160dcf7SMatt Barden 	    s->srv_cap,			/* l */
881a90cf9f2SGordon Ross 	    smb2_max_trans,		/* l */
882aa321b3cSDan McDonald 	    max_rwsize,			/* l */
883aa321b3cSDan McDonald 	    max_rwsize,			/* l */
884a90cf9f2SGordon Ross 	    &now_tv,			/* T */
885a90cf9f2SGordon Ross 	    &boot_tv,			/* T */
886a90cf9f2SGordon Ross 	    128, /* SecBufOff */	/* w */
887a90cf9f2SGordon Ross 	    sr->sr_cfg->skc_negtok_len,	/* w */
8884e065a9fSAlexander Stetsenko 	    neg_ctx_off,		/* l */
889a90cf9f2SGordon Ross 	    sr->sr_cfg->skc_negtok_len,	/* # */
890a90cf9f2SGordon Ross 	    sr->sr_cfg->skc_negtok);	/* c */
891a90cf9f2SGordon Ross 
892ab017dbaSGordon Ross 	/* Note: smb31_encode_neg_ctxs() follows in caller */
8934e065a9fSAlexander Stetsenko 
89493bc28dbSGordon Ross 	/* smb2_send_reply(sr); in caller */
895a90cf9f2SGordon Ross 
896a90cf9f2SGordon Ross 	(void) ksocket_setsockopt(s->sock, SOL_SOCKET,
897a90cf9f2SGordon Ross 	    SO_SNDBUF, (const void *)&smb2_tcp_bufsize,
898a90cf9f2SGordon Ross 	    sizeof (smb2_tcp_bufsize), CRED());
899a90cf9f2SGordon Ross 	(void) ksocket_setsockopt(s->sock, SOL_SOCKET,
900a90cf9f2SGordon Ross 	    SO_RCVBUF, (const void *)&smb2_tcp_bufsize,
901a90cf9f2SGordon Ross 	    sizeof (smb2_tcp_bufsize), CRED());
902a90cf9f2SGordon Ross 
903a90cf9f2SGordon Ross 	return (rc);
904a90cf9f2SGordon Ross }
905a90cf9f2SGordon Ross 
906a90cf9f2SGordon Ross /*
907a90cf9f2SGordon Ross  * SMB2 Dispatch table handler, which will run if we see an
908a90cf9f2SGordon Ross  * SMB2_NEGOTIATE after the initial negotiation is done.
909a90cf9f2SGordon Ross  * That would be a protocol error.
910a90cf9f2SGordon Ross  */
911a90cf9f2SGordon Ross smb_sdrc_t
smb2_negotiate(smb_request_t * sr)912a90cf9f2SGordon Ross smb2_negotiate(smb_request_t *sr)
913a90cf9f2SGordon Ross {
914a90cf9f2SGordon Ross 	sr->smb2_status = NT_STATUS_INVALID_PARAMETER;
915a90cf9f2SGordon Ross 	return (SDRC_ERROR);
916a90cf9f2SGordon Ross }
917a90cf9f2SGordon Ross 
918a90cf9f2SGordon Ross /*
919a90cf9f2SGordon Ross  * VALIDATE_NEGOTIATE_INFO [MS-SMB2] 2.2.32.6
920a90cf9f2SGordon Ross  */
921a90cf9f2SGordon Ross uint32_t
smb2_nego_validate(smb_request_t * sr,smb_fsctl_t * fsctl)92255f0a249SGordon Ross smb2_nego_validate(smb_request_t *sr, smb_fsctl_t *fsctl)
923a90cf9f2SGordon Ross {
924a90cf9f2SGordon Ross 	smb_session_t *s = sr->session;
925a90cf9f2SGordon Ross 	int rc;
926a90cf9f2SGordon Ross 
927a90cf9f2SGordon Ross 	/*
928a90cf9f2SGordon Ross 	 * The spec. says to parse the VALIDATE_NEGOTIATE_INFO here
929a90cf9f2SGordon Ross 	 * and verify that the original negotiate was not modified.
930a90cf9f2SGordon Ross 	 *
931a90cf9f2SGordon Ross 	 * One interesting requirement here is that we MUST reply
932a90cf9f2SGordon Ross 	 * with exactly the same information as we returned in our
933a90cf9f2SGordon Ross 	 * original reply to the SMB2 negotiate on this session.
934a90cf9f2SGordon Ross 	 * If we don't the client closes the connection.
935a90cf9f2SGordon Ross 	 */
936a90cf9f2SGordon Ross 
9371160dcf7SMatt Barden 	uint32_t capabilities;
9384e065a9fSAlexander Stetsenko 	uint16_t secmode;
9394e065a9fSAlexander Stetsenko 	uint16_t num_dialects;
9404e065a9fSAlexander Stetsenko 	uint16_t dialects[SMB2_NEGOTIATE_MAX_DIALECTS];
9411160dcf7SMatt Barden 	uint8_t clnt_guid[16];
9421160dcf7SMatt Barden 
9434e065a9fSAlexander Stetsenko 	if (s->dialect >= SMB_VERS_3_11)
9444e065a9fSAlexander Stetsenko 		goto drop;
9454e065a9fSAlexander Stetsenko 
946715c0bc6SAndrew Stormont 	/*
947715c0bc6SAndrew Stormont 	 * [MS-SMB2] 3.3.5.2.4 Verifying the Signature
948715c0bc6SAndrew Stormont 	 *
949715c0bc6SAndrew Stormont 	 * If the dialect is SMB3 and the message was successfully
950715c0bc6SAndrew Stormont 	 * decrypted we MUST skip processing of the signature.
951715c0bc6SAndrew Stormont 	 */
952715c0bc6SAndrew Stormont 	if (!sr->encrypted && (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) == 0)
9534ad35fa3SMatt Barden 		goto drop;
9544ad35fa3SMatt Barden 
9551160dcf7SMatt Barden 	if (fsctl->InputCount < 24)
9561160dcf7SMatt Barden 		goto drop;
9571160dcf7SMatt Barden 
9581160dcf7SMatt Barden 	(void) smb_mbc_decodef(fsctl->in_mbc, "l16cww",
9591160dcf7SMatt Barden 	    &capabilities, /* l */
9601160dcf7SMatt Barden 	    &clnt_guid, /* 16c */
9611160dcf7SMatt Barden 	    &secmode, /* w */
9621160dcf7SMatt Barden 	    &num_dialects); /* w */
9631160dcf7SMatt Barden 
9644e065a9fSAlexander Stetsenko 	if (num_dialects == 0 || num_dialects > SMB2_NEGOTIATE_MAX_DIALECTS)
9654e065a9fSAlexander Stetsenko 		goto drop;
9661160dcf7SMatt Barden 	if (secmode != s->cli_secmode)
9671160dcf7SMatt Barden 		goto drop;
9681160dcf7SMatt Barden 	if (capabilities != s->capabilities)
9691160dcf7SMatt Barden 		goto drop;
9701160dcf7SMatt Barden 	if (memcmp(clnt_guid, s->clnt_uuid, sizeof (clnt_guid)) != 0)
9711160dcf7SMatt Barden 		goto drop;
9721160dcf7SMatt Barden 
9731160dcf7SMatt Barden 	rc = smb_mbc_decodef(fsctl->in_mbc, "#w", num_dialects, dialects);
9741160dcf7SMatt Barden 	if (rc != 0)
9751160dcf7SMatt Barden 		goto drop;
9761160dcf7SMatt Barden 
977b716e3d0SGordon Ross 	/*
978b716e3d0SGordon Ross 	 * MS-SMB2 says we should compare the dialects array with the
979b716e3d0SGordon Ross 	 * one sent previously, but that appears to be unnecessary
980b716e3d0SGordon Ross 	 * as long as we end up with the same dialect.
981b716e3d0SGordon Ross 	 */
982b716e3d0SGordon Ross 	if (smb2_find_best_dialect(s, dialects, num_dialects) != s->dialect)
9831160dcf7SMatt Barden 		goto drop;
9841160dcf7SMatt Barden 
985a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
986a90cf9f2SGordon Ross 	    fsctl->out_mbc, "l#cww",
9871160dcf7SMatt Barden 	    s->srv_cap,			/* l */
988a90cf9f2SGordon Ross 	    UUID_LEN,			/* # */
989a90cf9f2SGordon Ross 	    &s->s_cfg.skc_machine_uuid, /* c */
9901160dcf7SMatt Barden 	    s->srv_secmode,		/* w */
991a90cf9f2SGordon Ross 	    s->dialect);		/* w */
9921160dcf7SMatt Barden 	if (rc == 0)
9931160dcf7SMatt Barden 		return (rc);
994a90cf9f2SGordon Ross 
9951160dcf7SMatt Barden drop:
9961160dcf7SMatt Barden 	smb_session_disconnect(s);
9971160dcf7SMatt Barden 	return (NT_STATUS_ACCESS_DENIED);
998a90cf9f2SGordon Ross }
999