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

Ralph Böhme rb at sernet.de
Thu Oct 2 04:56:44 MDT 2014


Hi all!

On Mon, Sep 29, 2014 at 10:43:56PM -0500, Steve French wrote:
> I am also ok with using the Microsoft UID and perm mapping (if I
> could figure out where they store the sticky and setuid/setgid bits
> ....) to enhance our current "cifsacl" mount option.

attached is an updated AAPL patchset [1]. Summary of changes:

* fixes for issues found by Volker and metze

* added a torture test

* move MS NFS style uid, gid, mode mapping from vfs_fruit to the core
  POSIX ACL functions

With minor changes, the MS NFS stuff could be used by the Linux smb
client. Atm I'm only enabling this functionality via smb2/create AAPL
context capability negotation, but that can be modified easily.

Comments welcome! :)

If the change to include MS NFS stuff in the core POSIX ACL routines
is accepted, I'll post and updated squashed patchset.

-Ralph

[1] <https://github.com/slowfranklin/samba/commits/aapl>

-- 
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 0c70ee255134f33c68d0443ccf402cc67dafa2f6 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 1/8] 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 0b34723..fbab3e1 100644
--- a/libcli/smb/smb2_constants.h
+++ b/libcli/smb/smb2_constants.h
@@ -207,6 +207,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 c24c3cf150d3a46785e0f75aa5e43f9e084f4d0a 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 2/8] libcli/security: add NFS SID mappings

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

diff --git a/libcli/security/dom_sid.h b/libcli/security/dom_sid.h
index c4a417b..a3f52cb 100644
--- a/libcli/security/dom_sid.h
+++ b/libcli/security/dom_sid.h
@@ -53,6 +53,10 @@ 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_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..eda7247 100644
--- a/libcli/security/util_sid.c
+++ b/libcli/security/util_sid.c
@@ -96,6 +96,21 @@ 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_Users =		/* Unix users, 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 groups, 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 f9d1d4ca776672f84ddfacc3b05968715e998ae5 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 3/8] 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 0441d5e..01757d3 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -1719,6 +1719,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 82fa05bf98ebd284fd165936ee75f59f9b9c818e 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 4/8] 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 d50aee2c80aab09ffc8152b79e3c3e1df7e72d79 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Mon, 8 Sep 2014 23:22:44 +0200
Subject: [PATCH 5/8] vfs_fruit: SMB2 AAPL create_context: NFS ACEs

Return uid, gid and mode in NFS ACEs append them to the ACL we get
from the next VFS module.

Extract mode from client NFS ACE and apply it.

Signed-off-by: Ralph Boehme <rb at sernet.de>
---
 source3/modules/vfs_fruit.c | 184 ++++++++++++++++++++++++++++++++++++++++++++
 source3/smbd/smb2_create.c  |   8 ++
 2 files changed, 192 insertions(+)

diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 01757d3..6e86b20 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -2912,6 +2912,184 @@ fail:
 	return status;
 }
 
+/* NT ACL operations. */
+
+static NTSTATUS fruit_fget_nt_acl(vfs_handle_struct *handle,
+				  files_struct *fsp,
+				  uint32 security_info,
+				  TALLOC_CTX *mem_ctx,
+				  struct security_descriptor **ppdesc)
+{
+	NTSTATUS result;
+	struct security_descriptor *sd;
+	struct security_ace ace;
+	struct dom_sid sid;
+
+	result = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
+					  mem_ctx, ppdesc);
+	if (!NT_STATUS_IS_OK(result)) {
+	    return result;
+	}
+
+	if (!handle->conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_unix_info) {
+	     return result;
+	}
+
+	sd = *ppdesc;
+	if (sd == NULL) {
+		return result;
+	}
+
+	/* Add special NFS ACE with 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);
+	result = security_descriptor_dacl_add(sd, &ace);
+	if (!NT_STATUS_IS_OK(result)) {
+	    return result;
+	}
+
+	/* Add special NFS ACE with 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);
+	result = security_descriptor_dacl_add(sd, &ace);
+	if (!NT_STATUS_IS_OK(result)) {
+	    return result;
+	}
+
+	/* Add special NFS ACE with 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);
+	result = security_descriptor_dacl_add(sd, &ace);
+	if (!NT_STATUS_IS_OK(result)) {
+	    return result;
+	}
+
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS fruit_get_nt_acl(vfs_handle_struct *handle,
+				 const char *name,
+				 uint32 security_info,
+				 TALLOC_CTX *mem_ctx,
+				 struct security_descriptor **ppdesc)
+{
+	NTSTATUS result;
+	struct security_descriptor *sd;
+	struct security_ace ace;
+	struct dom_sid sid;
+	struct smb_filename *smb_fname = NULL;
+	int rc;
+
+	result = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info,
+					 mem_ctx, ppdesc);
+
+	if (!NT_STATUS_IS_OK(result)) {
+	    return result;
+	}
+
+	if (!handle->conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_unix_info) {
+	     return NT_STATUS_OK;
+	}
+
+	sd = *ppdesc;
+	if (sd == NULL) {
+		return NT_STATUS_OK;
+	}
+
+	smb_fname = synthetic_smb_fname(talloc_tos(), name, NULL, NULL);
+	if (smb_fname == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	rc = SMB_VFS_STAT(handle->conn, smb_fname);
+	if (rc != 0) {
+		goto out;
+	}
+
+	/* Add special NFS ACE with mode */
+	sid_compose(&sid, &global_sid_Unix_NFS_Mode,
+		    smb_fname->st.st_ex_mode);
+	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+	result = security_descriptor_dacl_add(sd, &ace);
+	if (!NT_STATUS_IS_OK(result)) {
+		goto out;
+	}
+
+	/* Add special NFS ACE with uid */
+	sid_compose(&sid, &global_sid_Unix_NFS_Users,
+		    smb_fname->st.st_ex_uid);
+	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+	result = security_descriptor_dacl_add(sd, &ace);
+	if (!NT_STATUS_IS_OK(result)) {
+		goto out;
+	}
+
+	/* Add special NFS ACE with gid */
+	sid_compose(&sid, &global_sid_Unix_NFS_Groups,
+		    smb_fname->st.st_ex_gid);
+	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+	result = security_descriptor_dacl_add(sd, &ace);
+	if (!NT_STATUS_IS_OK(result)) {
+		goto out;
+	}
+
+out:
+	TALLOC_FREE(smb_fname);
+	return result;
+}
+
+static NTSTATUS fruit_fset_nt_acl(vfs_handle_struct *handle,
+				  files_struct *fsp,
+				  uint32 security_info_sent,
+				  const struct security_descriptor *psd)
+{
+	int i, rc;
+	bool do_chmod = false;
+	mode_t mode;
+
+	if (!handle->conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_unix_info
+	    || psd->dacl == NULL
+	    || psd->dacl->aces == NULL) {
+		return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp,
+						security_info_sent, psd);
+	}
+
+	/* Search NFS ACE with mode */
+	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) {
+			mode = (mode_t)psd->dacl->aces[i].trustee.sub_auths[2];
+			mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
+			do_chmod = true;
+			break;
+		}
+	}
+
+	if (do_chmod) {
+		/* Apply mode and return without calling VFS_NEXT */
+		DEBUG(10, ("fruit_fset_nt_acl: %s, %04o\n",
+			   fsp_str_dbg(fsp), mode));
+		if (fsp->fh->fd != -1) {
+			rc = SMB_VFS_FCHMOD(fsp, mode);
+		} else {
+			rc = SMB_VFS_CHMOD(handle->conn,
+					   fsp->fsp_name->base_name,
+					   mode);
+		}
+
+		if (rc != 0) {
+			DEBUG(10, ("fruit_fset_nt_acl: %s, %04o error %s\n",
+				   fsp_str_dbg(fsp), mode, strerror(errno)));
+			return map_nt_error_from_unix_common(errno);
+		}
+		return NT_STATUS_OK;
+	}
+
+	return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
+}
+
 static struct vfs_fn_pointers vfs_fruit_fns = {
 	.connect_fn = fruit_connect,
 
@@ -2933,6 +3111,12 @@ static struct vfs_fn_pointers vfs_fruit_fns = {
 	.ftruncate_fn = fruit_ftruncate,
 	.fallocate_fn = fruit_fallocate,
 	.create_file_fn = fruit_create_file,
+
+	/* NT ACL operations. */
+
+	.fget_nt_acl_fn = fruit_fget_nt_acl,
+	.get_nt_acl_fn = fruit_get_nt_acl,
+	.fset_nt_acl_fn = fruit_fset_nt_acl,
 };
 
 NTSTATUS vfs_fruit_init(void);
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 d2b63fa161d840a548b0ac628561a4eb272c3f9b 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 6/8] 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 63490b2c7cc81083f13b9a9723e96cbb9bb4fe1b 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 7/8] 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


>From 5565923550458b3208fca81dbd291d30972c787f Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Wed, 1 Oct 2014 23:39:54 +0200
Subject: [PATCH 8/8] s3: smbd: POSIX ACLs: support for MS NFS style 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.

Signed-off-by: Ralph Boehme <rb at sernet.de>
---
 source3/modules/vfs_fruit.c | 184 --------------------------------------------
 source3/smbd/posix_acls.c   |  85 ++++++++++++++++++++
 2 files changed, 85 insertions(+), 184 deletions(-)

diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 6e86b20..01757d3 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -2912,184 +2912,6 @@ fail:
 	return status;
 }
 
-/* NT ACL operations. */
-
-static NTSTATUS fruit_fget_nt_acl(vfs_handle_struct *handle,
-				  files_struct *fsp,
-				  uint32 security_info,
-				  TALLOC_CTX *mem_ctx,
-				  struct security_descriptor **ppdesc)
-{
-	NTSTATUS result;
-	struct security_descriptor *sd;
-	struct security_ace ace;
-	struct dom_sid sid;
-
-	result = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
-					  mem_ctx, ppdesc);
-	if (!NT_STATUS_IS_OK(result)) {
-	    return result;
-	}
-
-	if (!handle->conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_unix_info) {
-	     return result;
-	}
-
-	sd = *ppdesc;
-	if (sd == NULL) {
-		return result;
-	}
-
-	/* Add special NFS ACE with 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);
-	result = security_descriptor_dacl_add(sd, &ace);
-	if (!NT_STATUS_IS_OK(result)) {
-	    return result;
-	}
-
-	/* Add special NFS ACE with 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);
-	result = security_descriptor_dacl_add(sd, &ace);
-	if (!NT_STATUS_IS_OK(result)) {
-	    return result;
-	}
-
-	/* Add special NFS ACE with 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);
-	result = security_descriptor_dacl_add(sd, &ace);
-	if (!NT_STATUS_IS_OK(result)) {
-	    return result;
-	}
-
-	return NT_STATUS_OK;
-}
-
-static NTSTATUS fruit_get_nt_acl(vfs_handle_struct *handle,
-				 const char *name,
-				 uint32 security_info,
-				 TALLOC_CTX *mem_ctx,
-				 struct security_descriptor **ppdesc)
-{
-	NTSTATUS result;
-	struct security_descriptor *sd;
-	struct security_ace ace;
-	struct dom_sid sid;
-	struct smb_filename *smb_fname = NULL;
-	int rc;
-
-	result = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info,
-					 mem_ctx, ppdesc);
-
-	if (!NT_STATUS_IS_OK(result)) {
-	    return result;
-	}
-
-	if (!handle->conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_unix_info) {
-	     return NT_STATUS_OK;
-	}
-
-	sd = *ppdesc;
-	if (sd == NULL) {
-		return NT_STATUS_OK;
-	}
-
-	smb_fname = synthetic_smb_fname(talloc_tos(), name, NULL, NULL);
-	if (smb_fname == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-	rc = SMB_VFS_STAT(handle->conn, smb_fname);
-	if (rc != 0) {
-		goto out;
-	}
-
-	/* Add special NFS ACE with mode */
-	sid_compose(&sid, &global_sid_Unix_NFS_Mode,
-		    smb_fname->st.st_ex_mode);
-	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
-	result = security_descriptor_dacl_add(sd, &ace);
-	if (!NT_STATUS_IS_OK(result)) {
-		goto out;
-	}
-
-	/* Add special NFS ACE with uid */
-	sid_compose(&sid, &global_sid_Unix_NFS_Users,
-		    smb_fname->st.st_ex_uid);
-	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
-	result = security_descriptor_dacl_add(sd, &ace);
-	if (!NT_STATUS_IS_OK(result)) {
-		goto out;
-	}
-
-	/* Add special NFS ACE with gid */
-	sid_compose(&sid, &global_sid_Unix_NFS_Groups,
-		    smb_fname->st.st_ex_gid);
-	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
-	result = security_descriptor_dacl_add(sd, &ace);
-	if (!NT_STATUS_IS_OK(result)) {
-		goto out;
-	}
-
-out:
-	TALLOC_FREE(smb_fname);
-	return result;
-}
-
-static NTSTATUS fruit_fset_nt_acl(vfs_handle_struct *handle,
-				  files_struct *fsp,
-				  uint32 security_info_sent,
-				  const struct security_descriptor *psd)
-{
-	int i, rc;
-	bool do_chmod = false;
-	mode_t mode;
-
-	if (!handle->conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_unix_info
-	    || psd->dacl == NULL
-	    || psd->dacl->aces == NULL) {
-		return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp,
-						security_info_sent, psd);
-	}
-
-	/* Search NFS ACE with mode */
-	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) {
-			mode = (mode_t)psd->dacl->aces[i].trustee.sub_auths[2];
-			mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
-			do_chmod = true;
-			break;
-		}
-	}
-
-	if (do_chmod) {
-		/* Apply mode and return without calling VFS_NEXT */
-		DEBUG(10, ("fruit_fset_nt_acl: %s, %04o\n",
-			   fsp_str_dbg(fsp), mode));
-		if (fsp->fh->fd != -1) {
-			rc = SMB_VFS_FCHMOD(fsp, mode);
-		} else {
-			rc = SMB_VFS_CHMOD(handle->conn,
-					   fsp->fsp_name->base_name,
-					   mode);
-		}
-
-		if (rc != 0) {
-			DEBUG(10, ("fruit_fset_nt_acl: %s, %04o error %s\n",
-				   fsp_str_dbg(fsp), mode, strerror(errno)));
-			return map_nt_error_from_unix_common(errno);
-		}
-		return NT_STATUS_OK;
-	}
-
-	return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
-}
-
 static struct vfs_fn_pointers vfs_fruit_fns = {
 	.connect_fn = fruit_connect,
 
@@ -3111,12 +2933,6 @@ static struct vfs_fn_pointers vfs_fruit_fns = {
 	.ftruncate_fn = fruit_ftruncate,
 	.fallocate_fn = fruit_fallocate,
 	.create_file_fn = fruit_create_file,
-
-	/* NT ACL operations. */
-
-	.fget_nt_acl_fn = fruit_fget_nt_acl,
-	.get_nt_acl_fn = fruit_get_nt_acl,
-	.fset_nt_acl_fn = fruit_fset_nt_acl,
 };
 
 NTSTATUS vfs_fruit_init(void);
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 126b822..418294e 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;
 
@@ -2075,6 +2076,52 @@ static bool create_canon_ace_lists(files_struct *fsp,
 
 				free_canon_ace_list(file_ace);
 				free_canon_ace_list(dir_ace);
+
+				/*
+				 * Search MS NFS style ACE with UNIX
+				 * mode or uid/gid
+				 */
+				if ((dom_sid_compare_domain(
+					     &global_sid_Unix_NFS_Users,
+					     &psa->trustee) == 0) ||
+				    (dom_sid_compare_domain(
+					    &global_sid_Unix_NFS_Groups,
+					    &psa->trustee) == 0)) {
+					/* Ignore user/group ACE */
+					continue;
+				}
+				if (dom_sid_compare_domain(&global_sid_Unix_NFS_Mode,
+							   &psa->trustee) == 0) {
+					int result;
+					mode_t mode;
+					if (!fsp->conn->sconn->client->connections->smb2.server.smb2_crtctx_aapl_unix_info) {
+						/* Ignore it */
+						continue;
+					}
+
+					/* Apply mode */
+					mode = (mode_t)psa->trustee.sub_auths[2];
+					mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
+
+					DEBUG(10, ("MS NFS chmod request %s, %04o\n",
+						   fsp_str_dbg(fsp), mode));
+
+					if (fsp->fh->fd != -1) {
+						result = SMB_VFS_FCHMOD(fsp, mode);
+					} else {
+						result = SMB_VFS_CHMOD(fsp->conn,
+								       fsp->fsp_name->base_name,
+								       mode);
+					}
+
+					if (result != 0) {
+						DEBUG(10, ("failed to chmod: %s, %04o error %s\n",
+							   fsp_str_dbg(fsp), mode, strerror(errno)));
+						return false;
+					}
+					return false;
+				}
+
 				DEBUG(0, ("create_canon_ace_lists: unable to map SID "
 					  "%s to uid or gid.\n",
 					  sid_string_dbg(&current_ace->trustee)));
@@ -3265,6 +3312,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
 	struct dom_sid orig_owner_sid;
 	struct security_descriptor *psd = NULL;
 	int i;
+	NTSTATUS status;
 
 	/*
 	 * Get the owner, group and world SIDs.
@@ -3425,6 +3473,43 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
 	}
 
 	/*
+	 * 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, sbuf->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(0,("failed to add MS NFS style ACE\n"));
+			sd_size = 0;
+			goto done;
+		}
+
+		/* MS NFS style uid */
+		sid_compose(&sid, &global_sid_Unix_NFS_Users, sbuf->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(0,("failed to add MS NFS style ACE\n"));
+			sd_size = 0;
+			goto done;
+		}
+
+		/* MS NFS style gid */
+		sid_compose(&sid, &global_sid_Unix_NFS_Groups, sbuf->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(0,("failed to add MS NFS style ACE\n"));
+			sd_size = 0;
+			goto done;
+		}
+	}
+
+	/*
 	 * Windows 2000: The DACL_PROTECTED flag in the security
 	 * descriptor marks the ACL as non-inheriting, i.e., no
 	 * ACEs from higher level directories propagate to this
-- 
1.9.3



More information about the samba-technical mailing list