--- old/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c	Mon Aug  5 17:26:35 2019
+++ new/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c	Mon Aug  5 17:26:35 2019
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -32,6 +32,8 @@
 #include <smbsrv/smb_fsops.h>
 #include <smbsrv/smb_vops.h>
 
+int smb_nt_create_enable_extended_response = 1;
+
 /*
  * smb_com_nt_create_andx
  *
@@ -210,8 +212,7 @@
 			op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
 	}
 
-	DTRACE_SMB_2(op__NtCreateX__start, smb_request_t *, sr,
-	    struct open_param *, op);
+	DTRACE_SMB_START(op__NtCreateX, smb_request_t *, sr); /* arg.open */
 
 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 }
@@ -219,7 +220,7 @@
 void
 smb_post_nt_create_andx(smb_request_t *sr)
 {
-	DTRACE_SMB_1(op__NtCreateX__done, smb_request_t *, sr);
+	DTRACE_SMB_DONE(op__NtCreateX, smb_request_t *, sr);
 
 	if (sr->arg.open.dir != NULL) {
 		smb_ofile_release(sr->arg.open.dir);
@@ -227,6 +228,9 @@
 	}
 }
 
+/*
+ * A lot like smb_nt_transact_create
+ */
 smb_sdrc_t
 smb_com_nt_create_andx(struct smb_request *sr)
 {
@@ -234,9 +238,21 @@
 	smb_attr_t		*ap = &op->fqi.fq_fattr;
 	smb_ofile_t		*of;
 	int			rc;
-	unsigned char		DirFlag;
+	uint8_t			DirFlag;
 	uint32_t		status;
 
+	if (op->create_options & ~SMB_NTCREATE_VALID_OPTIONS) {
+		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+		    ERRDOS, ERROR_INVALID_PARAMETER);
+		return (SDRC_ERROR);
+	}
+
+	if (op->create_options & FILE_OPEN_BY_FILE_ID) {
+		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
+		    ERRDOS, ERROR_NOT_SUPPORTED);
+		return (SDRC_ERROR);
+	}
+
 	if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
 	    !(op->desired_access & DELETE)) {
 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
@@ -274,13 +290,15 @@
 		op->fqi.fq_dnode = op->dir->f_node;
 	}
 
-	op->op_oplock_levelII = B_TRUE;
-
 	status = smb_common_open(sr);
 	if (status != NT_STATUS_SUCCESS) {
 		smbsr_status(sr, status, 0, 0);
 		return (SDRC_ERROR);
 	}
+	if (op->op_oplock_level != SMB_OPLOCK_NONE) {
+		/* Oplock req. in op->op_oplock_level etc. */
+		smb1_oplock_acquire(sr, B_TRUE);
+	}
 
 	/*
 	 * NB: after the above smb_common_open() success,
@@ -293,48 +311,12 @@
 	case STYPE_DISKTREE:
 	case STYPE_PRINTQ:
 		if (op->create_options & FILE_DELETE_ON_CLOSE)
-			smb_ofile_set_delete_on_close(of);
-
+			smb_ofile_set_delete_on_close(sr, of);
 		DirFlag = smb_node_is_dir(of->f_node) ? 1 : 0;
-		rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
-		    34,
-		    sr->andx_com,
-		    0x67,
-		    op->op_oplock_level,
-		    sr->smb_fid,
-		    op->action_taken,
-		    &ap->sa_crtime,
-		    &ap->sa_vattr.va_atime,
-		    &ap->sa_vattr.va_mtime,
-		    &ap->sa_vattr.va_ctime,
-		    op->dattr & FILE_ATTRIBUTE_MASK,
-		    ap->sa_allocsz,
-		    ap->sa_vattr.va_size,
-		    op->ftype,
-		    op->devstate,
-		    DirFlag,
-		    0);
 		break;
 
 	case STYPE_IPC:
-		rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlqqqqlqqwwbw",
-		    34,
-		    sr->andx_com,
-		    0x67,
-		    0,
-		    sr->smb_fid,
-		    op->action_taken,
-		    0LL,
-		    0LL,
-		    0LL,
-		    0LL,
-		    FILE_ATTRIBUTE_NORMAL,
-		    0x1000LL,
-		    0LL,
-		    op->ftype,
-		    op->devstate,
-		    0,
-		    0);
+		DirFlag = 0;
 		break;
 
 	default:
@@ -342,6 +324,83 @@
 		    ERRDOS, ERROR_INVALID_FUNCTION);
 		goto errout;
 	}
+
+	if ((op->nt_flags & NT_CREATE_FLAG_EXTENDED_RESPONSE) != 0 &&
+	    smb_nt_create_enable_extended_response != 0) {
+		uint32_t MaxAccess = 0;
+		if (of->f_node != NULL) {
+			smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);
+		}
+		MaxAccess |= of->f_granted_access;
+
+		/*
+		 * Here is a really ugly protocol wart in SMB1:
+		 *
+		 * [MS-SMB] Sec. 2.2.4.9.2: Windows-based SMB servers
+		 * send 50 (0x32) words in the extended response although
+		 * they set the WordCount field to 0x2A.
+		 *
+		 * In other words, THEY LIE!  We really do need to encode
+		 * 50 words here, but lie and say we encoded 42 words.
+		 * This means we can't use smbsr_encode_result() to
+		 * build this response, because the rules it breaks
+		 * would cause errors in smbsr_check_result().
+		 *
+		 * And that's not all (it gets worse...)
+		 * Because of the bogus word count, some clients will
+		 * read the byte count from within what should be the
+		 * fileid field below.  Leave that zero, like Win7.
+		 *
+		 * Apparently the only really useful thing in this
+		 * extended response is MaxAccess.
+		 */
+		sr->smb_wct = 50; /* real word count */
+		sr->smb_bcc = 0;
+		rc = smb_mbc_encodef(&sr->reply,
+		    "bb.wbwlTTTTlqqwwb16.qllw",
+		    42,		/* fake word count (b) */
+		    sr->andx_com,		/* (b.) */
+		    0x87,	/* andx offset	   (w) */
+		    op->op_oplock_level,	/* (b) */
+		    sr->smb_fid,		/* (w) */
+		    op->action_taken,		/* (l) */
+		    &ap->sa_crtime,		/* (T) */
+		    &ap->sa_vattr.va_atime,	/* (T) */
+		    &ap->sa_vattr.va_mtime,	/* (T) */
+		    &ap->sa_vattr.va_ctime,	/* (T) */
+		    op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
+		    ap->sa_allocsz,		/* (q) */
+		    ap->sa_vattr.va_size,	/* (q) */
+		    op->ftype,			/* (w) */
+		    op->devstate,		/* (w) */
+		    DirFlag,			/* (b) */
+		    /* volume guid		  (16.) */
+		    0,	/* file ID (see above)	   (q) */
+		    MaxAccess,			/* (l) */
+		    0,		/* guest access	   (l) */
+		    0);		/* byte count	   (w) */
+	} else {
+		rc = smbsr_encode_result(
+		    sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
+		    34,		/* word count	   (b) */
+		    sr->andx_com,		/* (b.) */
+		    0x67,	/* andx offset	   (w) */
+		    op->op_oplock_level,	/* (b) */
+		    sr->smb_fid,		/* (w) */
+		    op->action_taken,		/* (l) */
+		    &ap->sa_crtime,		/* (T) */
+		    &ap->sa_vattr.va_atime,	/* (T) */
+		    &ap->sa_vattr.va_mtime,	/* (T) */
+		    &ap->sa_vattr.va_ctime,	/* (T) */
+		    op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
+		    ap->sa_allocsz,		/* (q) */
+		    ap->sa_vattr.va_size,	/* (q) */
+		    op->ftype,			/* (w) */
+		    op->devstate,		/* (w) */
+		    DirFlag,			/* (b) */
+		    0);		/* byte count	   (w) */
+	}
+
 	if (rc == 0)
 		return (SDRC_SUCCESS);
 
