[PATCH] SMB2 AAPL create context (was: Mac OS Mavericks über slow)

Ralph Böhme rb at sernet.de
Sat Nov 1 01:43:14 MDT 2014


Hi Jeremy,

On Fri, Oct 31, 2014 at 01:58:38PM -0700, Jeremy Allison wrote:
> Ralph, can you re-post the AAPL create context
> patch with your latest changes ?
> 
> I'd love to get this reviewed and into the
> code base now you're a Team member :-).

that would be great!

Patchset attached, couldn't rebase on master as sn is still down.

-Ralph

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de,mailto:kontakt@sernet.de
-------------- next part --------------
>From c1ff91b6dd0ced0a3934cb2dadb21d9b218d9fd2 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Fri, 22 Aug 2014 03:48:50 +0200
Subject: [PATCH 01/11] s3:smbd: add SMB2 AAPL create context defines and
 options

Add a global SMB2 specific option 'use_aapl_crtctx'. It's off by
default, but later enabled in the vfs_fruit module.

Add a AAPL specific capability flag 'smb2_crtctx_aapl_readdir_attr',
when used several fields in an SMB2/FIND reply are repurposed
returning Mac specific file attributes including resource fork length,
unix mode and max_access.

Add define and flag for NFS ACE in AAPL create context. With this
extension, a client can use get_info(sec)/set_info(sec) for

- retrieving UNIX uid,gid and mode of a file with get_info
- modifying UNIX mode with set_info

Signed-off-by: Ralph Boehme <rb at sernet.de>
---
 libcli/smb/smb2_constants.h  |  1 +
 libcli/smb/smb2_create_ctx.h | 46 ++++++++++++++++++++++++++++++++++++++++++++
 source3/smbd/globals.h       |  3 +++
 3 files changed, 50 insertions(+)
 create mode 100644 libcli/smb/smb2_create_ctx.h

diff --git a/libcli/smb/smb2_constants.h b/libcli/smb/smb2_constants.h
index 191de2b..1a6c5ad 100644
--- a/libcli/smb/smb2_constants.h
+++ b/libcli/smb/smb2_constants.h
@@ -222,6 +222,7 @@
 #define SMB2_CREATE_TAG_RQLS "RqLs"
 #define SMB2_CREATE_TAG_DH2Q "DH2Q"
 #define SMB2_CREATE_TAG_DH2C "DH2C"
+#define SMB2_CREATE_TAG_AAPL "AAPL"
 #define SMB2_CREATE_TAG_APP_INSTANCE_ID "\x45\xBC\xA6\x6A\xEF\xA7\xF7\x4A\x90\x08\xFA\x46\x2E\x14\x4D\x74"
 
 /* SMB2 notify flags */
diff --git a/libcli/smb/smb2_create_ctx.h b/libcli/smb/smb2_create_ctx.h
new file mode 100644
index 0000000..cb194f5
--- /dev/null
+++ b/libcli/smb/smb2_create_ctx.h
@@ -0,0 +1,46 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   SMB2 create context specifc stuff
+
+   Copyright (C) Ralph Boehme 2014
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LIBCLI_SMB2_CREATE_CTX_H__
+#define __LIBCLI_SMB2_CREATE_CTX_H__
+
+/* http://opensource.apple.com/source/smb/smb-697.1.1/kernel/netsmb/smb_2.h */
+
+/* "AAPL" Context Command Codes */
+#define SMB2_CRTCTX_AAPL_SERVER_QUERY 1
+#define SMB2_CRTCTX_AAPL_RESOLVE_ID   2
+
+/* "AAPL" Server Query request/response bitmap */
+#define SMB2_CRTCTX_AAPL_SERVER_CAPS 1
+#define SMB2_CRTCTX_AAPL_VOLUME_CAPS 2
+#define SMB2_CRTCTX_AAPL_MODEL_INFO  4
+
+/* "AAPL" Client/Server Capabilities bitmap */
+#define SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR 1
+#define SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE  2
+#define SMB2_CRTCTX_AAPL_UNIX_BASED             4
+#define SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE       8
+
+/* "AAPL" Volume Capabilities bitmap */
+#define SMB2_CRTCTX_AAPL_SUPPORT_RESOLVE_ID 1
+#define SMB2_CRTCTX_AAPL_CASE_SENSITIVE     2
+
+#endif
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index d0015d5..5137e5e 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -504,6 +504,9 @@ struct smbXsrv_connection {
 			uint32_t max_trans;
 			uint32_t max_read;
 			uint32_t max_write;
+			bool use_aapl_crtctx;
+			bool smb2_crtctx_aapl_readdir_attr;
+			bool smb2_crtctx_aapl_unix_info;
 		} server;
 
 		struct smbd_smb2_request *requests;
-- 
1.9.3


>From 4d87ab4745996c59235891fe874db6b4ab984b81 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Mon, 8 Sep 2014 23:18:35 +0200
Subject: [PATCH 02/11] libcli/security: add NFS SID mappings

Signed-off-by: Ralph Boehme <rb at sernet.de>
---
 libcli/security/dom_sid.h  |  5 +++++
 libcli/security/util_sid.c | 17 +++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/libcli/security/dom_sid.h b/libcli/security/dom_sid.h
index c4a417b..cf3cedea 100644
--- a/libcli/security/dom_sid.h
+++ b/libcli/security/dom_sid.h
@@ -53,6 +53,11 @@ extern const struct dom_sid global_sid_Builtin_Replicator;
 extern const struct dom_sid global_sid_Builtin_PreWin2kAccess;
 extern const struct dom_sid global_sid_Unix_Users;
 extern const struct dom_sid global_sid_Unix_Groups;
+extern const struct dom_sid global_sid_Unix_NFS;
+extern const struct dom_sid global_sid_Unix_NFS_Users;
+extern const struct dom_sid global_sid_Unix_NFS_Groups;
+extern const struct dom_sid global_sid_Unix_NFS_Mode;
+extern const struct dom_sid global_sid_Unix_NFS_Other;
 
 int dom_sid_compare_auth(const struct dom_sid *sid1,
 			 const struct dom_sid *sid2);
diff --git a/libcli/security/util_sid.c b/libcli/security/util_sid.c
index 8e42826..5127109 100644
--- a/libcli/security/util_sid.c
+++ b/libcli/security/util_sid.c
@@ -96,6 +96,23 @@ const struct dom_sid global_sid_Unix_Users =			/* Unmapped Unix users */
 const struct dom_sid global_sid_Unix_Groups =			/* Unmapped Unix groups */
 { 1, 1, {0,0,0,0,0,22}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
 
+/*
+ * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
+ */
+const struct dom_sid global_sid_Unix_NFS =             /* MS NFS and Apple style */
+{ 1, 1, {0,0,0,0,0,5}, {88,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const struct dom_sid global_sid_Unix_NFS_Users =		/* Unix uid, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,1,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const struct dom_sid global_sid_Unix_NFS_Groups =		/* Unix gid, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,2,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+const struct dom_sid global_sid_Unix_NFS_Mode =			/* Unix mode */
+{ 1, 2, {0,0,0,0,0,5}, {88,3,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* Unused, left here for documentary purposes */
+#if 0
+const struct dom_sid global_sid_Unix_NFS_Other =		/* Unix other, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,4,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#endif
+
 /* Unused, left here for documentary purposes */
 #if 0
 #define SECURITY_NULL_SID_AUTHORITY    0
-- 
1.9.3


>From 5467a378f330a4ecfa7af94386c7276b3dd95a63 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Tue, 16 Sep 2014 02:16:28 +0200
Subject: [PATCH 03/11] vfs_fruit: check option "smb2 create tag:aapl"

The default for the option is true, which means we support Apple's
AAPL SMB2 create context stuff.

Signed-off-by: Ralph Boehme <rb at sernet.de>
---
 source3/modules/vfs_fruit.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index c1555f0..98547d4 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -1718,6 +1718,10 @@ static int fruit_connect(vfs_handle_struct *handle,
 			"0x0d:0xf00d");
 	}
 
+	if (lp_parm_bool(-1, "smb2 create tag", "aapl", true)) {
+		handle->conn->sconn->client->connections->smb2.server.use_aapl_crtctx = true;
+	}
+
 	return rc;
 }
 
-- 
1.9.3


>From 5d454d70d9619081c87d55da3f7dd208fece0b97 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Fri, 22 Aug 2014 03:54:33 +0200
Subject: [PATCH 04/11] s3:smbd: SMB2 AAPL create context: SMB2/FIND extension

smb2_crtctx_aapl_readdir_attr = true | false

If enabled, several fields in an SMB2/FIND reply are repurposed
returning Mac specific file attributes including resource fork
length, UNIX mode, FinderInfo and max_access.

Signed-off-by: Ralph Boehme <rb at sernet.de>
---
 source3/smbd/smb2_create.c | 106 +++++++++++++++++++++++++++++
 source3/smbd/trans2.c      | 165 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 265 insertions(+), 6 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 48bc486..36640a0 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -24,6 +24,7 @@
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
 #include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smb2_create_ctx.h"
 #include "../librpc/gen_ndr/ndr_security.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "messages.h"
@@ -598,6 +599,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		uint64_t allocation_size = 0;
 		struct smb2_create_blob *twrp = NULL;
 		struct smb2_create_blob *qfid = NULL;
+		struct smb2_create_blob *aapl = NULL;
 		struct GUID _create_guid = GUID_zero();
 		struct GUID *create_guid = NULL;
 		bool update_open = false;
@@ -618,6 +620,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					     SMB2_CREATE_TAG_TWRP);
 		qfid = smb2_create_blob_find(&in_context_blobs,
 					     SMB2_CREATE_TAG_QFID);
+		if (smb2req->xconn->smb2.server.use_aapl_crtctx) {
+			aapl = smb2_create_blob_find(&in_context_blobs,
+						     SMB2_CREATE_TAG_AAPL);
+		}
 
 		fname = talloc_strdup(state, in_name);
 		if (tevent_req_nomem(fname, req)) {
@@ -804,6 +810,24 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			}
 		}
 
+		if (aapl) {
+			uint32_t cmd;
+
+			if (aapl->data.length != 24) {
+				DEBUG(1, ("unexpected AAPL ctxt legnth: %ju\n",
+					  (uintmax_t)aapl->data.length));
+				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+				return tevent_req_post(req, ev);
+			}
+
+			cmd = IVAL(aapl->data.data, 0);
+			if (cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) {
+				DEBUG(1, ("unsupported AAPL cmd: %d\n", cmd));
+				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+				return tevent_req_post(req, ev);
+			}
+		}
+
 		/* these are ignored for SMB2 */
 		in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
 		in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
@@ -1086,6 +1110,88 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				return tevent_req_post(req, ev);
 			}
 		}
+
+		if (aapl) {
+			/* We know we have a SMB2_CRTCTX_AAPL_SERVER_QUERY query */
+			bool ok;
+			uint8_t p[16];
+			DATA_BLOB blob = data_blob_talloc(smb2req, NULL, 0);
+			uint64_t req_bitmap, client_caps;
+			uint64_t server_caps = SMB2_CRTCTX_AAPL_UNIX_BASED;
+
+			req_bitmap = BVAL(aapl->data.data, 8);
+			client_caps = BVAL(aapl->data.data, 16);
+
+			SIVAL(p, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY);
+			SIVAL(p, 4, 0);
+			SBVAL(p, 8, req_bitmap);
+			ok = data_blob_append(smb2req, &blob, p, 16);
+			if (!ok) {
+				tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+				return tevent_req_post(req, ev);
+			}
+
+			if (req_bitmap & SMB2_CRTCTX_AAPL_SERVER_CAPS) {
+				if ((client_caps & SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR) &&
+				    (smb2req->tcon->compat->fs_capabilities & FILE_NAMED_STREAMS)) {
+					server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR;
+					smb2req->xconn->smb2.server.smb2_crtctx_aapl_readdir_attr = true;
+				}
+				SBVAL(p, 0, server_caps);
+				ok = data_blob_append(smb2req, &blob, p, 8);
+				if (!ok) {
+					tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+					return tevent_req_post(req, ev);
+				}
+			}
+
+			if (req_bitmap & SMB2_CRTCTX_AAPL_VOLUME_CAPS) {
+				SBVAL(p, 0,
+				      lp_case_sensitive(SNUM(smb2req->tcon->compat)) ?
+				      SMB2_CRTCTX_AAPL_CASE_SENSITIVE : 0);
+				ok = data_blob_append(smb2req, &blob, p, 8);
+				if (!ok) {
+					tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+					return tevent_req_post(req, ev);
+				}
+			}
+
+			if (req_bitmap & SMB2_CRTCTX_AAPL_MODEL_INFO) {
+				smb_ucs2_t *model;
+				size_t modellen;
+				ok = convert_string_talloc(smb2req,
+							   CH_UNIX, CH_UTF16LE,
+							   "Samba", strlen("Samba"),
+							   &model, &modellen);
+				if (!ok) {
+					tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+					return tevent_req_post(req, ev);
+				}
+
+				SIVAL(p, 0, 0);
+				SIVAL(p + 4, 0, modellen);
+				ok = data_blob_append(smb2req, &blob, p, 8);
+				if (!ok) {
+					tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+					return tevent_req_post(req, ev);
+				}
+
+				ok = data_blob_append(smb2req, &blob, model, modellen);
+				if (!ok) {
+					tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+					return tevent_req_post(req, ev);
+				}
+				talloc_free(model);
+			}
+
+			status = smb2_create_blob_add(state, &out_context_blobs,
+						      SMB2_CREATE_TAG_AAPL,
+						      blob);
+			if (!NT_STATUS_IS_OK(status)) {
+				tevent_req_nterror(req, status);
+				return tevent_req_post(req, ev);
+			}
+		}
 	}
 
 	smb2req->compat_chain_fsp = smb1req->chain_fsp;
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 60128ef..c556162 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -40,6 +40,7 @@
 #include "rpc_server/srv_pipe_hnd.h"
 #include "printing.h"
 #include "lib/util_ea.h"
+#include "MacExtensions.h"
 
 #define DIR_ENTRY_SAFETY_MARGIN 4096
 
@@ -1594,6 +1595,96 @@ static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
 	return true;
 }
 
+/**
+ * Check and possibly read AFPINFO_STREAM stream from a file or dir
+ *
+ * If the file has an associated AFPINFO_STREAM stream, FinderInfo is
+ * returned in packed format in the buffer pointed to by
+ * compressed_finder_info. The buffer must suitably sized (16 bytes).
+ **/
+static void get_compressed_finder_info(connection_struct *conn,
+				       const struct smb_filename *smb_fname,
+				       char *compressed_finder_info)
+{
+	struct smb_filename *infoname = NULL;
+	files_struct *fsp = NULL;
+	NTSTATUS status;
+	ssize_t len;
+	uint8_t ai[AFP_INFO_SIZE];
+	uint32_t date_added;
+	int ret;
+
+	memset(compressed_finder_info, '\0', 16);
+
+	infoname = synthetic_smb_fname(talloc_tos(),
+				       smb_fname->base_name,
+				       AFPINFO_STREAM,
+				       NULL);
+
+	DEBUG(10, ("reading AFPINFO_STREAM for %s\n",
+		   smb_fname_str_dbg(infoname)));
+
+	ret = SMB_VFS_STAT(conn, infoname);
+	if (ret != 0) {
+		goto error;
+	}
+
+        status = SMB_VFS_CREATE_FILE(
+	    conn,                                   /* conn */
+	    NULL,                                   /* req */
+	    0,                                      /* root_dir_fid */
+	    infoname,                               /* fname */
+	    FILE_READ_DATA,                         /* access_mask */
+	    (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
+	     FILE_SHARE_DELETE),
+	    FILE_OPEN,                              /* create_disposition*/
+	    0,                                      /* create_options */
+	    0,                                      /* file_attributes */
+	    INTERNAL_OPEN_ONLY,                     /* oplock_request */
+	    NULL,                                   /* lease */
+	    0,                                      /* allocation_size */
+	    0,                                      /* private_flags */
+	    NULL,                                   /* sd */
+	    NULL,                                   /* ea_list */
+	    &fsp,                                   /* result */
+	    NULL);                                  /* pinfo */
+
+	if (!NT_STATUS_IS_OK(status)) {
+		goto error;
+	}
+
+	len = SMB_VFS_PREAD(fsp, ai, AFP_INFO_SIZE, 0);
+	if (len != AFP_INFO_SIZE) {
+		DEBUG(1, ("bad length: %ju\n", (intmax_t)len));
+		goto error;
+	}
+
+	/* AD_DATE_DELTA = 946684800 */
+	date_added = convert_time_t_to_uint32_t(
+		smb_fname->st.st_ex_btime.tv_sec)
+		- 946684800;
+
+	if (S_ISREG(smb_fname->st.st_ex_mode)) {
+		/* finder_type */
+		memcpy(compressed_finder_info, ai + 16, 4);
+		/* finder_creator */
+		memcpy(compressed_finder_info + 4, ai + 20, 4);
+	}
+	/* finder_flags */
+	memcpy(compressed_finder_info + 8, ai + 24, 2);
+	/* finder_ext_flags */
+	memcpy(compressed_finder_info + 10, ai + 40, 2);
+	/* finder_date_added, could also use stat_ex.btime instead */
+	RSIVAL(compressed_finder_info, 12, date_added);
+
+error:
+	if (fsp != NULL) {
+		SMB_VFS_CLOSE(fsp);
+	}
+	talloc_free(infoname);
+	return;
+}
+
 static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
 				    connection_struct *conn,
 				    uint16_t flags2,
@@ -2097,17 +2188,61 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
 		q = p; p += 4; /* q is placeholder for name length */
 		if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
 			SIVAL(p, 0, IO_REPARSE_TAG_DFS);
+		} else if ((conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_readdir_attr) &&
+			   (conn->fs_capabilities & FILE_NAMED_STREAMS)) {
+			/*
+			 * OS X specific SMB2 extension negotiated via
+			 * AAPL create context: return max_access in
+			 * ea_size field.
+			 */
+			uint32_t max_access_granted;
+			status = smbd_calculate_access_mask(conn,
+							    smb_fname,
+							    false,
+							    SEC_FLAG_MAXIMUM_ALLOWED,
+							    &max_access_granted);
+			if (!NT_STATUS_IS_OK(status)) {
+				max_access_granted = 0;
+			}
+			SIVAL(p, 0, max_access_granted);
 		} else {
 			unsigned int ea_size = estimate_ea_size(conn, NULL,
 								smb_fname);
 			SIVAL(p,0,ea_size); /* Extended attributes */
 		}
 		p += 4;
-		/* Clear the short name buffer. This is
-		 * IMPORTANT as not doing so will trigger
-		 * a Win2k client bug. JRA.
-		 */
-		if (!was_8_3 && check_mangled_names) {
+
+		if ((conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_readdir_attr) &&
+		    (conn->fs_capabilities & FILE_NAMED_STREAMS)) {
+			/*
+			 * OS X specific SMB2 extension negotiated via
+			 * AAPL create context: return resource fork
+			 * lenght and compressed FinderInfo in
+			 * shortname field.
+			 */
+			int ret;
+			struct smb_filename *resoname;
+			uint64_t rfork_size = 0;
+			/*
+			 * According to documentation short_name_len
+			 * should be 0, but on the wire behaviour
+			 * shows its set to 24 by clients.
+			 */
+			SSVAL(p, 0, 24);
+
+			resoname = synthetic_smb_fname(talloc_tos(),
+						       smb_fname->base_name,
+						       AFPRESOURCE_STREAM,
+						       NULL);
+			ret = SMB_VFS_STAT(conn, resoname);
+			if (ret == 0) {
+				rfork_size = resoname->st.st_ex_size;
+			}
+			TALLOC_FREE(resoname);
+			SBVAL(p + 2, 0, rfork_size);
+
+			get_compressed_finder_info(conn, smb_fname, p + 10);
+		} else if (!was_8_3 && check_mangled_names) {
 			char mangled_name[13]; /* mangled 8.3 name. */
 			if (!name_to_8_3(fname,mangled_name,True,
 					conn->params)) {
@@ -2127,10 +2262,28 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
 			}
 			SSVAL(p, 0, len);
 		} else {
+			/* Clear the short name buffer. This is
+			 * IMPORTANT as not doing so will trigger
+			 * a Win2k client bug. JRA.
+			 */
 			memset(p,'\0',26);
 		}
 		p += 26;
-		SSVAL(p,0,0); p += 2; /* Reserved ? */
+
+		/* Reserved ? */
+		if (conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_readdir_attr &&
+		    (conn->fs_capabilities & FILE_NAMED_STREAMS)) {
+			/*
+			 * OS X specific SMB2 extension negotiated via
+			 * AAPL create context: return UNIX mode in
+			 * reserved field.
+			 */
+			SSVAL(p, 0, (uint16_t)smb_fname->st.st_ex_mode);
+		} else {
+			SSVAL(p, 0, 0);
+		}
+		p += 2;
+
 		SBVAL(p,0,file_index); p += 8;
 		status = srvstr_push(base_data, flags2, p,
 				  fname, PTR_DIFF(end_data, p),
-- 
1.9.3


>From 0d2a738ab9f9cc21832d15b4691ae10537e9abcb Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 11 Oct 2014 09:12:05 +0200
Subject: [PATCH 05/11] libcli/security: add a function to remove MS NFS SIDs
 from sd

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 libcli/security/security_descriptor.c | 53 +++++++++++++++++++++++++++++++++++
 libcli/security/security_descriptor.h |  2 ++
 2 files changed, 55 insertions(+)

diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
index 8304b20..c39f181 100644
--- a/libcli/security/security_descriptor.c
+++ b/libcli/security/security_descriptor.c
@@ -595,3 +595,56 @@ struct security_ace *security_ace_create(TALLOC_CTX *mem_ctx,
 
 	return ace;
 }
+
+/*******************************************************************
+ Remove MS NFS ACEs from a sd
+*******************************************************************/
+
+NTSTATUS security_descriptor_ms_nfs_rm(struct security_descriptor *psd)
+{
+	int i;
+	struct security_acl *acl = psd->dacl;
+
+	if (acl == NULL) {
+		return NT_STATUS_OK;
+	}
+
+	for (i=0; i < acl->num_aces;) {
+		if (dom_sid_compare_domain(&global_sid_Unix_NFS_Users,
+					   &acl->aces[i].trustee) == 0) {
+			memmove(&acl->aces[i], &acl->aces[i+1],
+				sizeof(acl->aces[i]) * (acl->num_aces - (i+1)));
+			acl->num_aces--;
+			if (acl->num_aces == 0) {
+				acl->aces = NULL;
+			}
+			continue;
+		}
+
+		if (dom_sid_compare_domain(&global_sid_Unix_NFS_Groups,
+					   &acl->aces[i].trustee) == 0) {
+			memmove(&acl->aces[i], &acl->aces[i+1],
+				sizeof(acl->aces[i]) * (acl->num_aces - (i+1)));
+			acl->num_aces--;
+			if (acl->num_aces == 0) {
+				acl->aces = NULL;
+			}
+			continue;
+		}
+
+		if (dom_sid_compare_domain(&global_sid_Unix_NFS_Mode,
+					   &acl->aces[i].trustee) == 0) {
+			memmove(&acl->aces[i], &acl->aces[i+1],
+				sizeof(acl->aces[i]) * (acl->num_aces - (i+1)));
+			acl->num_aces--;
+			if (acl->num_aces == 0) {
+				acl->aces = NULL;
+			}
+			continue;
+		}
+
+		i++;
+	}
+
+	return NT_STATUS_OK;
+}
diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h
index 1c7f893..17fb1dc 100644
--- a/libcli/security/security_descriptor.h
+++ b/libcli/security/security_descriptor.h
@@ -81,4 +81,6 @@ struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx,
 						       struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */
 						       uint32_t (*generic_map)(uint32_t access_mask));
 
+NTSTATUS security_descriptor_ms_nfs_rm(struct security_descriptor *psd);
+
 #endif /* __SECURITY_DESCRIPTOR_H__ */
-- 
1.9.3


>From 0570ee74158e1d4c6790d46ae39b6e8d24d7faab Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 14 Oct 2014 13:54:05 +0200
Subject: [PATCH 06/11] libcli/security: add a function that checks for MS NFS
 ACEs

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 libcli/security/security_descriptor.c | 22 ++++++++++++++++++++++
 libcli/security/security_descriptor.h |  1 +
 2 files changed, 23 insertions(+)

diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
index c39f181..f0e1f19 100644
--- a/libcli/security/security_descriptor.c
+++ b/libcli/security/security_descriptor.c
@@ -648,3 +648,25 @@ NTSTATUS security_descriptor_ms_nfs_rm(struct security_descriptor *psd)
 
 	return NT_STATUS_OK;
 }
+
+/*******************************************************************
+ Remove MS NFS ACEs from a sd
+*******************************************************************/
+bool security_descriptor_with_ms_nfs(const struct security_descriptor *psd)
+{
+	int i;
+
+	if (psd->dacl == NULL) {
+		return false;
+	}
+
+	for (i = 0; i < psd->dacl->num_aces; i++) {
+		if (dom_sid_compare_domain(
+			    &global_sid_Unix_NFS,
+			    &psd->dacl->aces[i].trustee) == 0) {
+			return true;
+		}
+	}
+
+	return false;
+}
diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h
index 17fb1dc..6511f04 100644
--- a/libcli/security/security_descriptor.h
+++ b/libcli/security/security_descriptor.h
@@ -82,5 +82,6 @@ struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx,
 						       uint32_t (*generic_map)(uint32_t access_mask));
 
 NTSTATUS security_descriptor_ms_nfs_rm(struct security_descriptor *psd);
+bool security_descriptor_with_ms_nfs(const struct security_descriptor *psd);
 
 #endif /* __SECURITY_DESCRIPTOR_H__ */
-- 
1.9.3


>From f64eb605a9fca1a2f29be882110411ea97e48956 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 11 Oct 2014 09:13:39 +0200
Subject: [PATCH 07/11] s3:smbd: support for MS NFS uid, gid and mode

Add optional support for MS NFS style mapping. uid, gid and mode can
be queried with get_secinfo, mode can be changed with
set_secinfo. This is only enabled by smb2/create context AAPL
capability negotiation atm.

Do the checking for MS NFS mode in nttrans.c, this facilitates all VFS
modules can work with it.

Due to semantic defficiencies roundtripping POSIX ACLs, if a set_acl
request contains a MS NFS mode SID, just apply the mode and skip the
rest.

Other ACL models that map mode<->ACEs in one way or another (in
contrast to Darwin were both are completely distinct domains), other
VFS modules may have to adapt for this change too.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/nttrans.c     | 104 +++++++++++++++++++++++++++++++++++++++++++++
 source3/smbd/posix_acls.c  |  18 ++++++++
 source3/smbd/smb2_create.c |   8 ++++
 3 files changed, 130 insertions(+)

diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index edad3e4..6528349 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -858,6 +858,44 @@ static void canonicalize_inheritance_bits(struct security_descriptor *psd)
 }
 
 /****************************************************************************
+ Search MS NFS style ACE with UNIX mode
+****************************************************************************/
+static NTSTATUS check_ms_nfs(files_struct *fsp,
+			     struct security_descriptor *psd,
+			     mode_t *pmode,
+			     bool *pdo_chmod)
+{
+	int i;
+
+	*pdo_chmod = false;
+
+	if (psd->dacl == NULL) {
+		return NT_STATUS_OK;
+	}
+
+	if (!fsp->conn->sconn->client->connections->
+	    smb2.server.smb2_crtctx_aapl_unix_info) {
+		return NT_STATUS_OK;
+	}
+
+	for (i = 0; i < psd->dacl->num_aces; i++) {
+		if (dom_sid_compare_domain(
+			    &global_sid_Unix_NFS_Mode,
+			    &psd->dacl->aces[i].trustee) == 0) {
+			*pmode = (mode_t)psd->dacl->aces[i].trustee.sub_auths[2];
+			*pmode &= (S_IRWXU | S_IRWXG | S_IRWXO);
+			*pdo_chmod = true;
+
+			DEBUG(10, ("MS NFS chmod request %s, %04o\n",
+				   fsp_str_dbg(fsp), *pmode));
+			break;
+		}
+	}
+
+	return NT_STATUS_OK;
+}
+
+/****************************************************************************
  Internal fn to set security descriptors.
 ****************************************************************************/
 
@@ -865,6 +903,9 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
 		       uint32_t security_info_sent)
 {
 	NTSTATUS status;
+	bool do_chmod;
+	mode_t ms_nfs_mode;
+	int result;
 
 	if (!CAN_WRITE(fsp->conn)) {
 		return NT_STATUS_ACCESS_DENIED;
@@ -927,8 +968,34 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
 		NDR_PRINT_DEBUG(security_descriptor, psd);
 	}
 
+	status = check_ms_nfs(fsp, psd, &ms_nfs_mode, &do_chmod);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto exit;
+	}
+
 	status = SMB_VFS_FSET_NT_ACL(fsp, security_info_sent, psd);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto exit;
+	}
+
+	if (do_chmod) {
+		if (fsp->fh->fd != -1) {
+			result = SMB_VFS_FCHMOD(fsp, ms_nfs_mode);
+		} else {
+			result = SMB_VFS_CHMOD(fsp->conn,
+					       fsp->fsp_name->base_name,
+					       ms_nfs_mode);
+		}
 
+		if (result != 0) {
+			DEBUG(2, ("chmod: %s, %04o error %s\n", fsp_str_dbg(fsp),
+				  ms_nfs_mode, strerror(errno)));
+			status = map_nt_error_from_unix(errno);
+			return status;
+		}
+	}
+
+exit:
 	TALLOC_FREE(psd);
 
 	return status;
@@ -1922,6 +1989,43 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
 		return status;
 	}
 
+	/*
+	 * Add MS NFS style ACEs with uid, gid and mode
+	 */
+	if (conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_unix_info) {
+		struct security_ace ace;
+		struct dom_sid sid;
+		/* MS NFS style mode */
+		sid_compose(&sid, &global_sid_Unix_NFS_Mode, fsp->fsp_name->st.st_ex_mode);
+		init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+		status = security_descriptor_dacl_add(psd, &ace);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(1,("failed to add MS NFS style ACE\n"));
+			TALLOC_FREE(frame);
+			return status;
+		}
+
+		/* MS NFS style uid */
+		sid_compose(&sid, &global_sid_Unix_NFS_Users, fsp->fsp_name->st.st_ex_uid);
+		init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+		status = security_descriptor_dacl_add(psd, &ace);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(1,("failed to add MS NFS style ACE\n"));
+			TALLOC_FREE(frame);
+			return status;
+		}
+
+		/* MS NFS style gid */
+		sid_compose(&sid, &global_sid_Unix_NFS_Groups, fsp->fsp_name->st.st_ex_gid);
+		init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+		status = security_descriptor_dacl_add(psd, &ace);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(1,("failed to add MS NFS style ACE\n"));
+			TALLOC_FREE(frame);
+			return status;
+		}
+	}
+
 	if (!(security_info_wanted & SECINFO_OWNER)) {
 		psd->owner_sid = NULL;
 	}
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 126b822..bc75fa5 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -29,6 +29,7 @@
 #include "../librpc/gen_ndr/idmap.h"
 #include "../librpc/gen_ndr/ndr_smb_acl.h"
 #include "lib/param/loadparm.h"
+#include "smbd/globals.h"
 
 extern const struct generic_mapping file_generic_mapping;
 
@@ -3653,6 +3654,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
 	bool acl_set_support = false;
 	bool ret = false;
 	struct security_descriptor *psd = NULL;
+	int i;
 
 	DEBUG(10,("set_nt_acl: called for file %s\n",
 		  fsp_str_dbg(fsp)));
@@ -3666,6 +3668,22 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
+	/*
+	 * MS NFS mode, here's the deal: the client merely wants to
+	 * modify the mode, but roundtripping get_acl/set/acl would
+	 * add additional POSIX ACEs.  So in case we get a request
+	 * containing a MS NFS mode SID, we do nothing here.
+	 */
+	if ((security_info_sent & SECINFO_DACL) && (psd_orig->dacl)) {
+		for (i = 0; i < psd_orig->dacl->num_aces; i++) {
+			if (dom_sid_compare_domain(
+				    &global_sid_Unix_NFS,
+				    &psd_orig->dacl->aces[i].trustee) == 0) {
+			return NT_STATUS_OK;
+			}
+		}
+	}
+
 	psd = security_descriptor_copy(talloc_tos(), psd_orig);
 	if (psd == NULL) {
 		return NT_STATUS_NO_MEMORY;
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 36640a0..53c6d7d 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -1137,6 +1137,14 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR;
 					smb2req->xconn->smb2.server.smb2_crtctx_aapl_readdir_attr = true;
 				}
+
+				/*
+				 * The client doesn't set the flag, so we can't
+				 * check for it and just set it unconditionally
+				 */
+				server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE;
+				smb2req->xconn->smb2.server.smb2_crtctx_aapl_unix_info = true;
+
 				SBVAL(p, 0, server_caps);
 				ok = data_blob_append(smb2req, &blob, p, 8);
 				if (!ok) {
-- 
1.9.3


>From adcbabd9cba72da111470951a93f996412478921 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 11 Oct 2014 09:16:24 +0200
Subject: [PATCH 08/11] vfs:nfs4alcs: ignore MS NFS ACLs

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/nfs4_acls.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c
index cf61af9..1aa819a 100644
--- a/source3/modules/nfs4_acls.c
+++ b/source3/modules/nfs4_acls.c
@@ -778,6 +778,9 @@ static bool smbacl4_fill_ace4(
 			ace_v4->who.gid = gid;
 		} else if (sid_to_uid(&ace_nt->trustee, &uid)) {
 			ace_v4->who.uid = uid;
+		} else if (dom_sid_compare_domain(&ace_nt->trustee,
+						  &global_sid_Unix_NFS) == 0) {
+			return false;
 		} else {
 			DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
 				  "convert %s to uid or gid\n",
-- 
1.9.3


>From 0bca1a875fa2a619b5d92d4d175edbd4882ba50f Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 11 Oct 2014 09:17:24 +0200
Subject: [PATCH 09/11] vfs_acl_xattr/tdb: ignore MS NFS ACLs

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_acl_common.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index b749157..920c811 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -775,6 +775,15 @@ static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
 		psd->group_sid = orig_psd->group_sid;
 	}
 	if (security_info_sent & SECINFO_DACL) {
+		if (security_descriptor_with_ms_nfs(orig_psd)) {
+			/*
+			 * If the sd contains a MS NFS SID, do
+			 * nothing, it's a chmod() request from OS X
+			 * with AAPL context.
+			 */
+			TALLOC_FREE(frame);
+			return NT_STATUS_OK;
+		}
 		psd->dacl = orig_psd->dacl;
 		psd->type |= SEC_DESC_DACL_PRESENT;
 	}
-- 
1.9.3


>From 6aed36ca19add31c6a8a4505447f37d309d2a8f4 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Wed, 1 Oct 2014 14:36:43 +0200
Subject: [PATCH 10/11] s4:libcli/raw: make short_name available in buffer

This will be used in smb2/create AAPL context torture tests, where the
server returns an Mac OS X specific data blob in the short name
buffer. It's not a string, so the existing string extraction doesn't
cut it.

Signed-off-by: Ralph Boehme <rb at sernet.de>
---
 source4/libcli/raw/interfaces.h | 1 +
 source4/libcli/raw/rawsearch.c  | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h
index 9003c12..fcb5082 100644
--- a/source4/libcli/raw/interfaces.h
+++ b/source4/libcli/raw/interfaces.h
@@ -2739,6 +2739,7 @@ union smb_search_data {
 		uint32_t  attrib;
 		uint32_t  ea_size;
 		uint64_t file_id;
+		uint8_t short_name_buf[24];
 		struct smb_wire_string short_name;
 		struct smb_wire_string name;
 	} id_both_directory_info;
diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c
index 0705faa..31d0b50 100644
--- a/source4/libcli/raw/rawsearch.c
+++ b/source4/libcli/raw/rawsearch.c
@@ -456,6 +456,11 @@ NTSTATUS smb_raw_search_common(TALLOC_CTX *mem_ctx,
 		smbcli_blob_pull_string(NULL, mem_ctx, blob,
 				     &data->id_both_directory_info.short_name,
 				     68, 70, STR_LEN8BIT | STR_UNICODE);
+		if (data->id_both_directory_info.short_name.private_length == 24) {
+		    memcpy(data->id_both_directory_info.short_name_buf, blob->data + 70, 24);
+		} else {
+		    memset(data->id_both_directory_info.short_name_buf, 0, 24);
+		}
 		data->id_both_directory_info.file_id     = BVAL(blob->data,            96);
 		len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
 					      &data->id_both_directory_info.name,
-- 
1.9.3


>From 4e264e89907260760fcc6077772e7c3910872edf Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Sat, 27 Sep 2014 17:21:12 +0200
Subject: [PATCH 11/11] s4:torture:vfs_fruit: smb2/create context AAPL test

Signed-off-by: Ralph Boehme <rb at sernet.de>
---
 source4/torture/vfs/fruit.c | 273 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 273 insertions(+)

diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c
index 0c8d3a4..5d4a411 100644
--- a/source4/torture/vfs/fruit.c
+++ b/source4/torture/vfs/fruit.c
@@ -24,6 +24,7 @@
 #include "libcli/libcli.h"
 #include "libcli/smb2/smb2.h"
 #include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb/smb2_create_ctx.h"
 #include "lib/cmdline/popt_common.h"
 #include "param/param.h"
 #include "libcli/resolve/resolve.h"
@@ -1358,6 +1359,277 @@ done:
 	return ret;
 }
 
+static bool test_aapl(struct torture_context *tctx,
+		      struct smb2_tree *tree1,
+		      struct smb2_tree *tree2)
+{
+	TALLOC_CTX *mem_ctx = talloc_new(tctx);
+	const char *fname = BASEDIR "\\test_aapl";
+	NTSTATUS status;
+	struct smb2_handle testdirh;
+	bool ret = true;
+	struct smb2_create io;
+	DATA_BLOB data;
+	struct smb2_create_blob *aapl = NULL;
+	AfpInfo *info;
+	const char *type_creator = "SMB,OLE!";
+	char type_creator_buf[9];
+	uint32_t aapl_cmd;
+	uint32_t aapl_reply_bitmap;
+	uint32_t aapl_server_caps;
+	uint32_t aapl_vol_caps;
+	char *model;
+	struct smb2_find f;
+	unsigned int count;
+	union smb_search_data *d;
+	uint64_t rfork_len;
+
+	smb2_deltree(tree1, BASEDIR);
+
+	status = torture_smb2_testdir(tree1, BASEDIR, &testdirh);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	smb2_util_close(tree1, testdirh);
+
+	ZERO_STRUCT(io);
+	io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
+	io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
+	io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+	io.in.share_access = (NTCREATEX_SHARE_ACCESS_DELETE |
+			      NTCREATEX_SHARE_ACCESS_READ |
+			      NTCREATEX_SHARE_ACCESS_WRITE);
+	io.in.fname = fname;
+
+	/*
+	 * Issuing an SMB2/CREATE with a suitably formed AAPL context,
+	 * controls behaviour of Apple's SMB2 extensions for the whole
+	 * session!
+	 */
+
+	data = data_blob_talloc(mem_ctx, NULL, 3 * sizeof(uint64_t));
+	SBVAL(data.data, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY);
+	SBVAL(data.data, 8, (SMB2_CRTCTX_AAPL_SERVER_CAPS |
+			     SMB2_CRTCTX_AAPL_VOLUME_CAPS |
+			     SMB2_CRTCTX_AAPL_MODEL_INFO));
+	SBVAL(data.data, 16, (SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR |
+			      SMB2_CRTCTX_AAPL_UNIX_BASED |
+			      SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE));
+
+	torture_comment(tctx, "Testing SMB2 create context AAPL\n");
+	status = smb2_create_blob_add(tctx, &io.in.blobs, "AAPL", data);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	status = smb2_create(tree1, tctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+	status = smb2_util_close(tree1, io.out.file.handle);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	/*
+	 * Now check returned AAPL context
+	 */
+	torture_comment(tctx, "Comparing returned AAPL capabilites\n");
+
+	aapl = smb2_create_blob_find(&io.out.blobs,
+				     SMB2_CREATE_TAG_AAPL);
+
+	if (aapl->data.length != 50) {
+		/*
+		 * uint32_t CommandCode = kAAPL_SERVER_QUERY
+		 * uint32_t Reserved = 0;
+		 * uint64_t ReplyBitmap = kAAPL_SERVER_CAPS |
+		 *                        kAAPL_VOLUME_CAPS |
+		 *                        kAAPL_MODEL_INFO;
+		 * uint64_t ServerCaps = kAAPL_SUPPORTS_READDIR_ATTR |
+		 *                       kAAPL_SUPPORTS_OSX_COPYFILE;
+		 * uint64_t VolumeCaps = kAAPL_SUPPORT_RESOLVE_ID |
+		 *                       kAAPL_CASE_SENSITIVE;
+		 * uint32_t Pad2 = 0;
+		 * uint32_t ModelStringLen = 10;
+		 * ucs2_t ModelString[5] = "Samba";
+		 */
+		ret = false;
+		goto done;
+	}
+
+	aapl_cmd = IVAL(aapl->data.data, 0);
+	if (aapl_cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) unexpected cmd: %d",
+			       __location__, (int)aapl_cmd);
+		ret = false;
+		goto done;
+	}
+
+	aapl_reply_bitmap = BVAL(aapl->data.data, 8);
+	if (aapl_reply_bitmap != (SMB2_CRTCTX_AAPL_SERVER_CAPS |
+				  SMB2_CRTCTX_AAPL_VOLUME_CAPS |
+				  SMB2_CRTCTX_AAPL_MODEL_INFO)) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) unexpected reply_bitmap: %d",
+			       __location__, (int)aapl_reply_bitmap);
+		ret = false;
+		goto done;
+	}
+
+	aapl_server_caps = BVAL(aapl->data.data, 16);
+	if (aapl_server_caps != (SMB2_CRTCTX_AAPL_UNIX_BASED |
+				 SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR |
+				 SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE)) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) unexpected server_caps: %d",
+			       __location__, (int)aapl_server_caps);
+		ret = false;
+		goto done;
+	}
+
+	aapl_vol_caps = BVAL(aapl->data.data, 24);
+	if (aapl_vol_caps != SMB2_CRTCTX_AAPL_CASE_SENSITIVE) {
+		/* this will fail on a case insensitive fs ... */
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) unexpected vol_caps: %d",
+			       __location__, (int)aapl_vol_caps);
+		ret = false;
+		goto done;
+	}
+
+	ret = convert_string_talloc(mem_ctx,
+				    CH_UTF16LE, CH_UNIX,
+				    aapl->data.data + 40, 10,
+				    &model, NULL);
+	if (ret == false) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) convert_string_talloc() failed",
+			       __location__);
+		goto done;
+	}
+	if (strncmp(model, "Samba", 5) != 0) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) expected model \"Samba\", got: \"%s\"",
+			       __location__, model);
+		ret = false;
+		goto done;
+	}
+
+	/*
+	 * Now that Requested AAPL extensions are enabled, setup some
+	 * Mac files with metadata and resource fork
+	 */
+	ret = torture_setup_file(mem_ctx, tree1, fname, false);
+	if (ret == false) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) torture_setup_file() failed",
+			       __location__);
+		goto done;
+	}
+
+	info = torture_afpinfo_new(mem_ctx);
+	if (info == NULL) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) torture_afpinfo_new() failed",
+			       __location__);
+		ret = false;
+		goto done;
+	}
+
+	memcpy(info->afpi_FinderInfo, type_creator, 8);
+	ret = torture_write_afpinfo(tree1, tctx, mem_ctx, fname, info);
+	if (ret == false) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) torture_write_afpinfo() failed",
+			       __location__);
+		goto done;
+	}
+
+	ret = write_stream(tree1, __location__, tctx, mem_ctx,
+			   fname, AFPRESOURCE_STREAM,
+			   0, 3, "foo");
+	if (ret == false) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) write_stream() failed",
+			       __location__);
+		goto done;
+	}
+
+	/*
+	 * Ok, file is prepared, now call smb2/find
+	 */
+
+	ZERO_STRUCT(io);
+	io.in.desired_access = SEC_RIGHTS_DIR_ALL;
+	io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+	io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+	io.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
+			      NTCREATEX_SHARE_ACCESS_WRITE |
+			      NTCREATEX_SHARE_ACCESS_DELETE);
+	io.in.create_disposition = NTCREATEX_DISP_OPEN;
+	io.in.fname = BASEDIR;
+	status = smb2_create(tree1, tctx, &io);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	ZERO_STRUCT(f);
+	f.in.file.handle	= io.out.file.handle;
+	f.in.pattern		= "test_aapl";
+	f.in.continue_flags	= SMB2_CONTINUE_FLAG_SINGLE;
+	f.in.max_response_size	= 0x1000;
+	f.in.level              = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
+
+	status = smb2_find_level(tree1, tree1, &f, &count, &d);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	status = smb2_util_close(tree1, io.out.file.handle);
+	CHECK_STATUS(status, NT_STATUS_OK);
+
+	if (strcmp(d[0].id_both_directory_info.name.s, "test_aapl") != 0) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) write_stream() failed",
+			       __location__);
+		ret = false;
+		goto done;
+	}
+
+	if (d[0].id_both_directory_info.short_name.private_length != 24) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) bad short_name length %" PRIu32 ", expected 24",
+			       __location__, d[0].id_both_directory_info.short_name.private_length);
+		ret = false;
+		goto done;
+	}
+
+	torture_comment(tctx, "short_name buffer:\n");
+	dump_data(0, d[0].id_both_directory_info.short_name_buf, 24);
+
+	/*
+	 * Extract data as specified by the AAPL extension:
+	 * - ea_size contains max_access
+	 * - short_name contains resource fork length + FinderInfo
+	 * - reserved2 contains the unix mode
+	 */
+	torture_comment(tctx, "mac_access: %" PRIx32 "\n",
+			d[0].id_both_directory_info.ea_size);
+
+	rfork_len = BVAL(d[0].id_both_directory_info.short_name_buf, 0);
+	if (rfork_len != 3) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) expected resource fork length 3, got: %" PRIu64,
+			       __location__, rfork_len);
+		ret = false;
+		goto done;
+	}
+
+	memcpy(type_creator_buf, d[0].id_both_directory_info.short_name_buf + 8, 8);
+	type_creator_buf[8] = 0;
+	if (strcmp(type_creator, type_creator_buf) != 0) {
+		torture_result(tctx, TORTURE_FAIL,
+			       "(%s) expected type/creator \"%s\" , got: %s",
+			       __location__, type_creator, type_creator_buf);
+		ret = false;
+		goto done;
+	}
+
+done:
+	talloc_free(mem_ctx);
+	return ret;
+}
+
 /*
  * Note: This test depends on "vfs objects = catia fruit
  * streams_xattr".  Note: To run this test, use
@@ -1376,6 +1648,7 @@ struct torture_suite *torture_vfs_fruit(void)
 	torture_suite_add_2ns_smb2_test(suite, "write metadata", test_write_atalk_metadata);
 	torture_suite_add_2ns_smb2_test(suite, "resource fork IO", test_write_atalk_rfork_io);
 	torture_suite_add_2ns_smb2_test(suite, "OS X AppleDouble file conversion", test_adouble_conversion);
+	torture_suite_add_2ns_smb2_test(suite, "SMB2/CREATE context AAPL", test_aapl);
 
 	return suite;
 }
-- 
1.9.3



More information about the samba-technical mailing list