--- old/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c	Mon Aug  5 17:26:23 2019
+++ new/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c	Mon Aug  5 17:26:23 2019
@@ -10,7 +10,7 @@
  */
 
 /*
- * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -24,8 +24,14 @@
 
 uint32_t smb2srv_capabilities =
 	SMB2_CAP_DFS |
-	SMB2_CAP_LARGE_MTU;
+	SMB2_CAP_LEASING |
+	SMB2_CAP_LARGE_MTU |
+	SMB2_CAP_PERSISTENT_HANDLES |
+	SMB2_CAP_ENCRYPTION;
 
+/* These are the only capabilities defined for SMB2.X */
+#define	SMB_2X_CAPS (SMB2_CAP_DFS | SMB2_CAP_LEASING | SMB2_CAP_LARGE_MTU)
+
 /*
  * These are not intended as customer tunables, but dev. & test folks
  * might want to adjust them (with caution).
@@ -39,24 +45,36 @@
  *
  * smb2_max_rwsize is what we put in the SMB2 negotiate response to tell
  * the client the largest read and write request size we'll support.
- * One megabyte is a compromise between efficiency on fast networks
- * and memory consumption (for the buffers) on the server side.
+ * For now, we're using contiguous allocations, so keep this at 64KB
+ * so that (even with message overhead) allocations stay below 128KB,
+ * avoiding kmem_alloc -> page_create_va thrashing.
  *
  * smb2_max_trans is the largest "transact" send or receive, which is
  * used for directory listings and info set/get operations.
  */
 uint32_t smb2_tcp_bufsize = (1<<22);	/* 4MB */
-uint32_t smb2_max_rwsize = (1<<20);	/* 1MB */
+uint32_t smb2_max_rwsize = (1<<16);	/* 64KB */
 uint32_t smb2_max_trans  = (1<<16);	/* 64KB */
 
 /*
+ * With clients (e.g. HP scanners) that don't advertise SMB2_CAP_LARGE_MTU
+ * (including all clients using dialect < SMB 2.1), use a "conservative" value
+ * for max r/w size because some older clients misbehave with larger values.
+ * 64KB is recommended in the [MS-SMB2] spec.  (3.3.5.3.1 SMB 2.1 or SMB 3.x
+ * Support) as the minimum so we'll use that.
+ */
+uint32_t smb2_old_rwsize = (1<<16);	/* 64KB */
+
+/*
  * List of all SMB2 versions we implement.  Note that the
- * highest version we support may be limited by the
- * _cfg.skc_max_protocol setting.
+ * versions we support may be limited by the
+ * _cfg.skc_max_protocol and min_protocol settings.
  */
 static uint16_t smb2_versions[] = {
 	0x202,	/* SMB 2.002 */
 	0x210,	/* SMB 2.1 */
+	0x300,	/* SMB 3.0 */
+	0x302,	/* SMB 3.02 */
 };
 static uint16_t smb2_nversions =
     sizeof (smb2_versions) / sizeof (smb2_versions[0]);
@@ -66,7 +84,8 @@
 {
 	int i;
 
-	if (version > s->s_cfg.skc_max_protocol)
+	if (version > s->s_cfg.skc_max_protocol ||
+	    version < s->s_cfg.skc_min_protocol)
 		return (B_FALSE);
 	for (i = 0; i < smb2_nversions; i++)
 		if (version == smb2_versions[i])
@@ -93,7 +112,6 @@
 	smb_session_t *s = sr->session;
 	smb_arg_negotiate_t *negprot = sr->sr_negprot;
 	uint16_t smb2_version;
-	uint16_t secmode2;
 	int rc;
 
 	/*
@@ -107,32 +125,18 @@
 	 */
 	switch (negprot->ni_dialect) {
 	case DIALECT_SMB2002:	/* SMB 2.002 (a.k.a. SMB2.0) */
-		smb2_version = 0x202;
+		smb2_version = SMB_VERS_2_002;
 		s->dialect = smb2_version;
 		s->s_state = SMB_SESSION_STATE_NEGOTIATED;
 		/* Allow normal SMB2 requests now. */
 		s->newrq_func = smb2sr_newrq;
-
-		/*
-		 * Translate SMB1 sec. mode to SMB2.
-		 */
-		secmode2 = 0;
-		if (s->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)
-			secmode2 |= SMB2_NEGOTIATE_SIGNING_ENABLED;
-		if (s->secmode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
-			secmode2 |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
-		s->secmode = secmode2;
 		break;
 	case DIALECT_SMB2XXX:	/* SMB 2.??? (wildcard vers) */
 		/*
 		 * Expecting an SMB2 negotiate next, so keep the
-		 * initial s->newrq_func.  Note that secmode is
-		 * fiction good enough to pass the signing check
-		 * in smb2_negotiate_common().  We'll check the
-		 * real secmode when the 2nd negotiate comes.
+		 * initial s->newrq_func.
 		 */
 		smb2_version = 0x2FF;
-		s->secmode = SMB2_NEGOTIATE_SIGNING_ENABLED;
 		break;
 	default:
 		return (SDRC_DROP_VC);
@@ -139,6 +143,18 @@
 	}
 
 	/*
+	 * Clients that negotiate SMB2 from SMB1 have not yet had the
+	 * opportunity to provide us with a secmode. However, any
+	 * client that negotiates SMB2 should support signing, so
+	 * this should be fiction good enough to pass the signing
+	 * check in smb2_negotiate_common(). Even if the client
+	 * doesn't support signing and we require it, we'll fail them
+	 * later when they fail to sign the packet. For 2.???,
+	 * we'll check the real secmode when the 2nd negotiate comes.
+	 */
+	s->cli_secmode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+
+	/*
 	 * We did not decode an SMB2 header, so make sure
 	 * the SMB2 header fields are initialized.
 	 * (Most are zero from smb_request_alloc.)
@@ -149,12 +165,32 @@
 	sr->smb2_cmd_code = SMB2_NEGOTIATE;
 
 	rc = smb2_negotiate_common(sr, smb2_version);
+	smb2_send_reply(sr);
 	if (rc != 0)
 		return (SDRC_DROP_VC);
 
+	/*
+	 * We sent the reply, so tell the SMB1 dispatch
+	 * it should NOT (also) send a reply.
+	 */
 	return (SDRC_NO_REPLY);
 }
 
+static uint16_t
+smb2_find_best_dialect(smb_session_t *s, uint16_t cl_versions[],
+    uint16_t version_cnt)
+{
+	uint16_t best_version = 0;
+	int i;
+
+	for (i = 0; i < version_cnt; i++)
+		if (smb2_supported_version(s, cl_versions[i]) &&
+		    best_version < cl_versions[i])
+			best_version = cl_versions[i];
+
+	return (best_version);
+}
+
 /*
  * SMB2 Negotiate gets special handling.  This is called directly by
  * the reader thread (see smbsr_newrq_initial) with what _should_ be
@@ -168,12 +204,15 @@
  * result of bypassing the normal dispatch mechanism.
  *
  * The caller always frees this request.
+ *
+ * Return value is 0 for success, and anything else will
+ * terminate the reader thread (drop the connection).
  */
 int
 smb2_newrq_negotiate(smb_request_t *sr)
 {
 	smb_session_t *s = sr->session;
-	int i, rc;
+	int rc;
 	uint16_t struct_size;
 	uint16_t best_version;
 	uint16_t version_cnt;
@@ -186,24 +225,24 @@
 
 	if ((sr->smb2_cmd_code != SMB2_NEGOTIATE) ||
 	    (sr->smb2_next_command != 0))
-		return (SDRC_DROP_VC);
+		return (-1);
 
 	/*
 	 * Decode SMB2 Negotiate (fixed-size part)
 	 */
 	rc = smb_mbc_decodef(
-	    &sr->command, "www..l16.8.",
+	    &sr->command, "www..l16c8.",
 	    &struct_size,	/* w */
 	    &version_cnt,	/* w */
-	    &s->secmode,	/* w */
-	    /* reserved 	(..) */
-	    &s->capabilities);	/* l */
-	    /* clnt_uuid	 16. */
+	    &s->cli_secmode,	/* w */
+	    /* reserved		(..) */
+	    &s->capabilities,	/* l */
+	    s->clnt_uuid);	/* 16c */
 	    /* start_time	  8. */
 	if (rc != 0)
 		return (rc);
 	if (struct_size != 36 || version_cnt > 8)
-		return (SDRC_DROP_VC);
+		return (-1);
 
 	/*
 	 * Decode SMB2 Negotiate (variable part)
@@ -211,20 +250,23 @@
 	rc = smb_mbc_decodef(&sr->command,
 	    "#w", version_cnt, cl_versions);
 	if (rc != 0)
-		return (SDRC_DROP_VC);
+		return (rc);
 
+	DTRACE_SMB2_START(op__Negotiate, smb_request_t *, sr);
+
 	/*
 	 * The client offers an array of protocol versions it
 	 * supports, which we have decoded into cl_versions[].
 	 * We walk the array and pick the highest supported.
 	 */
-	best_version = 0;
-	for (i = 0; i < version_cnt; i++)
-		if (smb2_supported_version(s, cl_versions[i]) &&
-		    best_version < cl_versions[i])
-			best_version = cl_versions[i];
-	if (best_version == 0)
-		return (SDRC_DROP_VC);
+	best_version = smb2_find_best_dialect(s, cl_versions, version_cnt);
+	if (best_version == 0) {
+		cmn_err(CE_NOTE, "clnt %s no supported dialect",
+		    sr->session->ip_addr_str);
+		sr->smb2_status = NT_STATUS_INVALID_PARAMETER;
+		rc = -1;
+		goto errout;
+	}
 	s->dialect = best_version;
 
 	/* Allow normal SMB2 requests now. */
@@ -232,16 +274,24 @@
 	s->newrq_func = smb2sr_newrq;
 
 	rc = smb2_negotiate_common(sr, best_version);
-	if (rc != 0)
-		return (SDRC_DROP_VC);
 
-	return (0);
+errout:
+	/* sr->smb2_status was set */
+	DTRACE_SMB2_DONE(op__Negotiate, smb_request_t *, sr);
+
+	smb2_send_reply(sr);
+
+	return (rc);
 }
 
 /*
  * Common parts of SMB2 Negotiate, used for both the
  * SMB1-to-SMB2 style, and straight SMB2 style.
- * Do negotiation decisions, encode, send the reply.
+ * Do negotiation decisions and encode the reply.
+ * The caller does the network send.
+ *
+ * Return value is 0 for success, and anything else will
+ * terminate the reader thread (drop the connection).
  */
 static int
 smb2_negotiate_common(smb_request_t *sr, uint16_t version)
@@ -249,6 +299,7 @@
 	timestruc_t boot_tv, now_tv;
 	smb_session_t *s = sr->session;
 	int rc;
+	uint32_t max_rwsize;
 	uint16_t secmode;
 
 	sr->smb2_status = 0;
@@ -255,19 +306,16 @@
 
 	/*
 	 * Negotiation itself.  First the Security Mode.
-	 * The caller stashed the client's secmode in s->secmode,
-	 * which we validate, and then replace with the server's
-	 * secmode, which is all we care about after this.
 	 */
 	secmode = SMB2_NEGOTIATE_SIGNING_ENABLED;
 	if (sr->sr_cfg->skc_signing_required) {
 		secmode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
 		/* Make sure client at least enables signing. */
-		if ((s->secmode & secmode) == 0) {
+		if ((s->cli_secmode & secmode) == 0) {
 			sr->smb2_status = NT_STATUS_INVALID_PARAMETER;
 		}
 	}
-	s->secmode = secmode;
+	s->srv_secmode = secmode;
 
 	s->cmd_max_bytes = smb2_tcp_bufsize;
 	s->reply_max_bytes = smb2_tcp_bufsize;
@@ -293,23 +341,62 @@
 	(void) smb2_encode_header(sr, B_FALSE);
 	if (sr->smb2_status != 0) {
 		smb2sr_put_error(sr, sr->smb2_status);
-		smb2_send_reply(sr);
+		/* smb2_send_reply(sr); in caller */
 		return (-1); /* will drop */
 	}
 
+	/*
+	 * If the version is 0x2FF, we haven't completed negotiate.
+	 * Don't initialize until we have our final request.
+	 */
+	if (version != 0x2FF)
+		smb2_sign_init_mech(s);
+
+	/*
+	 * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request
+	 *
+	 * The SMB2.x capabilities are returned without regard for
+	 * what capabilities the client provided in the request.
+	 * The SMB3.x capabilities returned are the traditional
+	 * logical AND of server and client capabilities.
+	 *
+	 * One additional check: If KCF is missing something we
+	 * require for encryption, turn off that capability.
+	 */
+	if (s->dialect < SMB_VERS_3_0) {
+		/* SMB 2.x */
+		s->srv_cap = smb2srv_capabilities & SMB_2X_CAPS;
+	} else {
+		/* SMB 3.0 or later */
+		s->srv_cap = smb2srv_capabilities &
+		    (SMB_2X_CAPS | s->capabilities);
+		if ((s->srv_cap & SMB2_CAP_ENCRYPTION) != 0 &&
+		    smb3_encrypt_init_mech(s) != 0) {
+			s->srv_cap &= ~SMB2_CAP_ENCRYPTION;
+		}
+	}
+
+	/*
+	 * See notes above smb2_max_rwsize, smb2_old_rwsize
+	 */
+	if (s->capabilities & SMB2_CAP_LARGE_MTU)
+		max_rwsize = smb2_max_rwsize;
+	else
+		max_rwsize = smb2_old_rwsize;
+
 	rc = smb_mbc_encodef(
 	    &sr->reply,
 	    "wwww#cllllTTwwl#c",
 	    65,	/* StructSize */	/* w */
-	    s->secmode,			/* w */
+	    s->srv_secmode,		/* w */
 	    version,			/* w */
 	    0, /* reserved */		/* w */
 	    UUID_LEN,			/* # */
 	    &s->s_cfg.skc_machine_uuid, /* c */
-	    smb2srv_capabilities,	/* l */
+	    s->srv_cap,			/* l */
 	    smb2_max_trans,		/* l */
-	    smb2_max_rwsize,		/* l */
-	    smb2_max_rwsize,		/* l */
+	    max_rwsize,			/* l */
+	    max_rwsize,			/* l */
 	    &now_tv,			/* T */
 	    &boot_tv,			/* T */
 	    128, /* SecBufOff */	/* w */
@@ -318,7 +405,7 @@
 	    sr->sr_cfg->skc_negtok_len,	/* # */
 	    sr->sr_cfg->skc_negtok);	/* c */
 
-	smb2_send_reply(sr);
+	/* smb2_send_reply(sr); in caller */
 
 	(void) ksocket_setsockopt(s->sock, SOL_SOCKET,
 	    SO_SNDBUF, (const void *)&smb2_tcp_bufsize,
@@ -346,7 +433,7 @@
  * VALIDATE_NEGOTIATE_INFO [MS-SMB2] 2.2.32.6
  */
 uint32_t
-smb2_fsctl_vneginfo(smb_request_t *sr, smb_fsctl_t *fsctl)
+smb2_nego_validate(smb_request_t *sr, smb_fsctl_t *fsctl)
 {
 	smb_session_t *s = sr->session;
 	int rc;
@@ -354,8 +441,7 @@
 	/*
 	 * The spec. says to parse the VALIDATE_NEGOTIATE_INFO here
 	 * and verify that the original negotiate was not modified.
-	 * The only tampering we need worry about is secmode, and
-	 * we're not taking that from the client, so don't bother.
+	 * The request MUST be signed, and we MUST validate the signature.
 	 *
 	 * One interesting requirement here is that we MUST reply
 	 * with exactly the same information as we returned in our
@@ -363,15 +449,53 @@
 	 * If we don't the client closes the connection.
 	 */
 
+	/* dialects[8] taken from cl_versions[8] in smb2_newrq_negotiate */
+	uint32_t capabilities;
+	uint16_t secmode, num_dialects, dialects[8];
+	uint8_t clnt_guid[16];
+
+	if ((sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) == 0)
+		goto drop;
+
+	if (fsctl->InputCount < 24)
+		goto drop;
+
+	(void) smb_mbc_decodef(fsctl->in_mbc, "l16cww",
+	    &capabilities, /* l */
+	    &clnt_guid, /* 16c */
+	    &secmode, /* w */
+	    &num_dialects); /* w */
+
+	if (num_dialects == 0 || num_dialects > 8)
+		goto drop;
+	if (secmode != s->cli_secmode)
+		goto drop;
+	if (capabilities != s->capabilities)
+		goto drop;
+	if (memcmp(clnt_guid, s->clnt_uuid, sizeof (clnt_guid)) != 0)
+		goto drop;
+
+	if (fsctl->InputCount < (24 + num_dialects * sizeof (*dialects)))
+		goto drop;
+
+	rc = smb_mbc_decodef(fsctl->in_mbc, "#w", num_dialects, dialects);
+	if (rc != 0)
+		goto drop;
+
+	if (smb2_find_best_dialect(s, dialects, num_dialects) != s->dialect)
+		goto drop;
+
 	rc = smb_mbc_encodef(
 	    fsctl->out_mbc, "l#cww",
-	    smb2srv_capabilities,	/* l */
+	    s->srv_cap,			/* l */
 	    UUID_LEN,			/* # */
 	    &s->s_cfg.skc_machine_uuid, /* c */
-	    s->secmode,			/* w */
+	    s->srv_secmode,		/* w */
 	    s->dialect);		/* w */
-	if (rc)
-		return (NT_STATUS_INTERNAL_ERROR);
+	if (rc == 0)
+		return (rc);
 
-	return (0);
+drop:
+	smb_session_disconnect(s);
+	return (NT_STATUS_ACCESS_DENIED);
 }
