[RFC] vfs_nfs4acl_xattr NFS4.1 support, support for XDR encoding and more...

Ralph Böhme slow at samba.org
Thu Nov 2 18:44:21 UTC 2017


On Thu, Nov 02, 2017 at 11:56:23AM +0100, Ralph Böhme wrote:
> Ok, I'll then follow-up with a patchset that changes the ACL version to 4.1 and
> the xattr name to "security.nfs4acl_ndr" instead of "security.nfs4acl".

attached.

Please review & push if happy. Thanks!

-slow

-- 
Ralph Boehme, Samba Team       https://samba.org/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/
-------------- next part --------------
From cd0a2b24d8a480a73048d1ae86cc0a238bd90e1d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 7 Sep 2017 17:26:58 +0200
Subject: [PATCH 01/27] selftest: split out failing owner related subtest from
 samba3.raw.acls.create_file|dir

All the other subtests in samba3.raw.acls.create_file|dir pass with
nfs4acl_xattr, it's just the subtest that tries to set the owner which
fails with everything else then acl_xattr.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail         | 11 +++----
 source4/torture/raw/acls.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+), 5 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 15e6b1d5c70..258548ec858 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -22,14 +22,14 @@
 ^samba3.raw.samba3hide.samba3hide\((nt4_dc|ad_dc)\) # This test fails against an smbd environment with NT ACLs enabled
 ^samba3.raw.samba3closeerr.samba3closeerr\(nt4_dc\) # This test fails against an smbd environment with NT ACLs enabled
 ^samba3.raw.acls nfs4acl_xattr-simple.INHERITFLAGS\(nt4_dc\) # This (and the follow nfs4acl_xattr tests fail because our NFSv4 backend isn't a complete mapping yet.
-^samba3.raw.acls nfs4acl_xattr-simple.create_file\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-simple.create_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-simple.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-simple.create_owner_dir\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple.nulldacl\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple.generic\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple.inheritance\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.INHERITFLAGS\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.create_file\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.create_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-special.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-special.create_owner_dir\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.nulldacl\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.generic\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.inheritance\(nt4_dc\)
@@ -106,7 +106,8 @@
 ^samba4.raw.streams.*.perms
 ^samba4.raw.acls.INHERITFLAGS
 ^samba4.raw.acls.*.create_dir
-^samba4.raw.acls.*.create_file
+^samba4.raw.acls.*.create_owner_dir
+^samba4.raw.acls.*.create_owner_file
 ^samba4.smb2.create.*.acldir
 ^samba4.smb2.create.*.impersonation
 ^samba4.smb2.acls.*.generic
diff --git a/source4/torture/raw/acls.c b/source4/torture/raw/acls.c
index dfeb13df560..9e3202b6fbd 100644
--- a/source4/torture/raw/acls.c
+++ b/source4/torture/raw/acls.c
@@ -342,6 +342,60 @@ static bool test_nttrans_create_ext(struct torture_context *tctx,
 	status = delete_func(cli->tree, fname);
 	CHECK_STATUS(status, NT_STATUS_OK);
 
+ done:
+	smbcli_close(cli->tree, fnum);
+	smb_raw_exit(cli->session);
+	smbcli_deltree(cli->tree, BASEDIR);
+	return ret;
+}
+
+/*
+  test using nttrans create to create a file and directory with an initial acl
+  and owner.
+*/
+static bool test_nttrans_create_ext_owner(
+	struct torture_context *tctx,
+	struct smbcli_state *cli, bool test_dir)
+{
+	NTSTATUS status;
+	union smb_open io;
+	const char *fname = BASEDIR "\\foo.txt";
+	bool ret = true;
+	int fnum = -1;
+	struct security_ace ace;
+	struct security_descriptor *sd;
+	uint32_t attrib =
+	    FILE_ATTRIBUTE_HIDDEN |
+	    FILE_ATTRIBUTE_SYSTEM |
+	    (test_dir ? FILE_ATTRIBUTE_DIRECTORY : 0);
+	NTSTATUS (*delete_func)(struct smbcli_tree *, const char *) =
+	    test_dir ? smbcli_rmdir : smbcli_unlink;
+
+	ZERO_STRUCT(ace);
+
+	smbcli_deltree(cli->tree, BASEDIR);
+
+	if (!torture_setup_dir(cli, BASEDIR))
+		return false;
+
+	io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+	io.ntcreatex.in.root_fid.fnum = 0;
+	io.ntcreatex.in.flags = 0;
+	io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+	io.ntcreatex.in.create_options =
+	    test_dir ? NTCREATEX_OPTIONS_DIRECTORY : 0;
+	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+	io.ntcreatex.in.share_access =
+		NTCREATEX_SHARE_ACCESS_READ |
+		NTCREATEX_SHARE_ACCESS_WRITE;
+	io.ntcreatex.in.alloc_size = 0;
+	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+	io.ntcreatex.in.security_flags = 0;
+	io.ntcreatex.in.fname = fname;
+	io.ntcreatex.in.sec_desc = NULL;
+	io.ntcreatex.in.ea_list = NULL;
+
 	torture_comment(tctx, "creating with attributes, ACL and owner\n");
 
 	sd = security_descriptor_dacl_create(tctx,
@@ -389,6 +443,22 @@ static bool test_nttrans_create_dir(struct torture_context *tctx,
 	return test_nttrans_create_ext(tctx, cli, true);
 }
 
+static bool test_nttrans_create_owner_file(struct torture_context *tctx,
+    struct smbcli_state *cli)
+{
+	torture_comment(tctx, "Testing nttrans create with sec_desc with owner on file\n");
+
+	return test_nttrans_create_ext_owner(tctx, cli, false);
+}
+
+static bool test_nttrans_create_owner_dir(struct torture_context *tctx,
+    struct smbcli_state *cli)
+{
+	torture_comment(tctx, "Testing nttrans create with sec_desc with owner on directory\n");
+
+	return test_nttrans_create_ext_owner(tctx, cli, true);
+}
+
 #define CHECK_ACCESS_FLAGS(_fnum, flags) do { \
 	union smb_fileinfo _q; \
 	_q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; \
@@ -2466,6 +2536,8 @@ struct torture_suite *torture_raw_acls(TALLOC_CTX *mem_ctx)
 	torture_suite_add_1smb_test(suite, "sd", test_sd);
 	torture_suite_add_1smb_test(suite, "create_file", test_nttrans_create_file);
 	torture_suite_add_1smb_test(suite, "create_dir", test_nttrans_create_dir);
+	torture_suite_add_1smb_test(suite, "create_owner_file", test_nttrans_create_owner_file);
+	torture_suite_add_1smb_test(suite, "create_owner_dir", test_nttrans_create_owner_dir);
 	torture_suite_add_1smb_test(suite, "nulldacl", test_nttrans_create_null_dacl);
 	torture_suite_add_1smb_test(suite, "creator", test_creator_sid);
 	torture_suite_add_1smb_test(suite, "generic", test_generic_bits);
-- 
2.13.6


From 94b2b5e4b197d4f1c5d8c2534b8ffc96af2b84fd Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 28 Sep 2017 07:48:59 +0200
Subject: [PATCH 02/27] vfs_acl_common: directly pass default_acl_style

This is in preperation of moving make_default_filesystem_acl() and
making it globally accessible. No change in behaviour.

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

diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index 7958fd1ca72..5e63b580378 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -565,16 +565,16 @@ static NTSTATUS make_default_acl_windows(TALLOC_CTX *ctx,
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS make_default_filesystem_acl(TALLOC_CTX *ctx,
-					    struct acl_common_config *config,
-					    const char *name,
-					    SMB_STRUCT_STAT *psbuf,
-					    struct security_descriptor **ppdesc)
+static NTSTATUS make_default_filesystem_acl(
+	TALLOC_CTX *ctx,
+	enum default_acl_style acl_style,
+	const char *name,
+	SMB_STRUCT_STAT *psbuf,
+	struct security_descriptor **ppdesc)
 {
 	NTSTATUS status;
 
-	switch (config->default_acl_style) {
-
+	switch (acl_style) {
 	case DEFAULT_ACL_POSIX:
 		status =  make_default_acl_posix(ctx, name, psbuf, ppdesc);
 		break;
@@ -584,7 +584,7 @@ static NTSTATUS make_default_filesystem_acl(TALLOC_CTX *ctx,
 		break;
 
 	default:
-		DBG_ERR("unknown acl style %d", config->default_acl_style);
+		DBG_ERR("unknown acl style %d", acl_style);
 		status = NT_STATUS_INTERNAL_ERROR;
 		break;
 	}
@@ -908,7 +908,7 @@ NTSTATUS get_nt_acl_common(
 
 			status = make_default_filesystem_acl(
 				mem_ctx,
-				config,
+				config->default_acl_style,
 				smb_fname->base_name,
 				psbuf,
 				&psd);
-- 
2.13.6


From 6bc6a36d54a8652b6bc687f229cdf84547b00a49 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 28 Sep 2017 07:53:48 +0200
Subject: [PATCH 03/27] s3/smbd: make make_default_filesystem_acl public

This will be used by another VFS module in a subsequent commit.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_acl_common.c | 216 +--------------------------------------
 source3/modules/vfs_acl_common.h |   2 +-
 source3/smbd/posix_acls.c        | 216 +++++++++++++++++++++++++++++++++++++++
 source3/smbd/proto.h             |  11 ++
 4 files changed, 232 insertions(+), 213 deletions(-)

diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index 5e63b580378..546e97b9b5d 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -41,15 +41,13 @@ static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
 				SECINFO_DACL | \
 				SECINFO_SACL)
 
-static const struct enum_list default_acl_style[] = {
-	{DEFAULT_ACL_POSIX,	"posix"},
-	{DEFAULT_ACL_WINDOWS,	"windows"}
-};
-
 bool init_acl_common_config(vfs_handle_struct *handle,
 			    const char *module_name)
 {
 	struct acl_common_config *config = NULL;
+	const struct enum_list *default_acl_style_list = NULL;
+
+	default_acl_style_list = get_default_acl_style_list();
 
 	config = talloc_zero(handle->conn, struct acl_common_config);
 	if (config == NULL) {
@@ -65,7 +63,7 @@ bool init_acl_common_config(vfs_handle_struct *handle,
 	config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
 						 module_name,
 						 "default acl style",
-						 default_acl_style,
+						 default_acl_style_list,
 						 DEFAULT_ACL_POSIX);
 
 	SMB_VFS_HANDLE_SET_DATA(handle, config, NULL,
@@ -386,212 +384,6 @@ static NTSTATUS add_directory_inheritable_components(vfs_handle_struct *handle,
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS make_default_acl_posix(TALLOC_CTX *ctx,
-				       const char *name,
-				       SMB_STRUCT_STAT *psbuf,
-				       struct security_descriptor **ppdesc)
-{
-	struct dom_sid owner_sid, group_sid;
-	size_t size = 0;
-	struct security_ace aces[4];
-	uint32_t access_mask = 0;
-	mode_t mode = psbuf->st_ex_mode;
-	struct security_acl *new_dacl = NULL;
-	int idx = 0;
-
-	DBG_DEBUG("file %s mode = 0%o\n",name, (int)mode);
-
-	uid_to_sid(&owner_sid, psbuf->st_ex_uid);
-	gid_to_sid(&group_sid, psbuf->st_ex_gid);
-
-	/*
-	 We provide up to 4 ACEs
-		- Owner
-		- Group
-		- Everyone
-		- NT System
-	*/
-
-	if (mode & S_IRUSR) {
-		if (mode & S_IWUSR) {
-			access_mask |= SEC_RIGHTS_FILE_ALL;
-		} else {
-			access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
-		}
-	}
-	if (mode & S_IWUSR) {
-		access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
-	}
-
-	init_sec_ace(&aces[idx],
-			&owner_sid,
-			SEC_ACE_TYPE_ACCESS_ALLOWED,
-			access_mask,
-			0);
-	idx++;
-
-	access_mask = 0;
-	if (mode & S_IRGRP) {
-		access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
-	}
-	if (mode & S_IWGRP) {
-		/* note that delete is not granted - this matches posix behaviour */
-		access_mask |= SEC_RIGHTS_FILE_WRITE;
-	}
-	if (access_mask) {
-		init_sec_ace(&aces[idx],
-			&group_sid,
-			SEC_ACE_TYPE_ACCESS_ALLOWED,
-			access_mask,
-			0);
-		idx++;
-	}
-
-	access_mask = 0;
-	if (mode & S_IROTH) {
-		access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
-	}
-	if (mode & S_IWOTH) {
-		access_mask |= SEC_RIGHTS_FILE_WRITE;
-	}
-	if (access_mask) {
-		init_sec_ace(&aces[idx],
-			&global_sid_World,
-			SEC_ACE_TYPE_ACCESS_ALLOWED,
-			access_mask,
-			0);
-		idx++;
-	}
-
-	init_sec_ace(&aces[idx],
-			&global_sid_System,
-			SEC_ACE_TYPE_ACCESS_ALLOWED,
-			SEC_RIGHTS_FILE_ALL,
-			0);
-	idx++;
-
-	new_dacl = make_sec_acl(ctx,
-			NT4_ACL_REVISION,
-			idx,
-			aces);
-
-	if (!new_dacl) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	*ppdesc = make_sec_desc(ctx,
-			SECURITY_DESCRIPTOR_REVISION_1,
-			SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
-			&owner_sid,
-			&group_sid,
-			NULL,
-			new_dacl,
-			&size);
-	if (!*ppdesc) {
-		return NT_STATUS_NO_MEMORY;
-	}
-	return NT_STATUS_OK;
-}
-
-static NTSTATUS make_default_acl_windows(TALLOC_CTX *ctx,
-					 const char *name,
-					 SMB_STRUCT_STAT *psbuf,
-					 struct security_descriptor **ppdesc)
-{
-	struct dom_sid owner_sid, group_sid;
-	size_t size = 0;
-	struct security_ace aces[4];
-	uint32_t access_mask = 0;
-	mode_t mode = psbuf->st_ex_mode;
-	struct security_acl *new_dacl = NULL;
-	int idx = 0;
-
-	DBG_DEBUG("file [%s] mode [0%o]\n", name, (int)mode);
-
-	uid_to_sid(&owner_sid, psbuf->st_ex_uid);
-	gid_to_sid(&group_sid, psbuf->st_ex_gid);
-
-	/*
-	 * We provide 2 ACEs:
-	 * - Owner
-	 * - NT System
-	 */
-
-	if (mode & S_IRUSR) {
-		if (mode & S_IWUSR) {
-			access_mask |= SEC_RIGHTS_FILE_ALL;
-		} else {
-			access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
-		}
-	}
-	if (mode & S_IWUSR) {
-		access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
-	}
-
-	init_sec_ace(&aces[idx],
-		     &owner_sid,
-		     SEC_ACE_TYPE_ACCESS_ALLOWED,
-		     access_mask,
-		     0);
-	idx++;
-
-	init_sec_ace(&aces[idx],
-		     &global_sid_System,
-		     SEC_ACE_TYPE_ACCESS_ALLOWED,
-		     SEC_RIGHTS_FILE_ALL,
-		     0);
-	idx++;
-
-	new_dacl = make_sec_acl(ctx,
-				NT4_ACL_REVISION,
-				idx,
-				aces);
-
-	if (!new_dacl) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	*ppdesc = make_sec_desc(ctx,
-				SECURITY_DESCRIPTOR_REVISION_1,
-				SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
-				&owner_sid,
-				&group_sid,
-				NULL,
-				new_dacl,
-				&size);
-	if (!*ppdesc) {
-		return NT_STATUS_NO_MEMORY;
-	}
-	return NT_STATUS_OK;
-}
-
-static NTSTATUS make_default_filesystem_acl(
-	TALLOC_CTX *ctx,
-	enum default_acl_style acl_style,
-	const char *name,
-	SMB_STRUCT_STAT *psbuf,
-	struct security_descriptor **ppdesc)
-{
-	NTSTATUS status;
-
-	switch (acl_style) {
-	case DEFAULT_ACL_POSIX:
-		status =  make_default_acl_posix(ctx, name, psbuf, ppdesc);
-		break;
-
-	case DEFAULT_ACL_WINDOWS:
-		status =  make_default_acl_windows(ctx, name, psbuf, ppdesc);
-		break;
-
-	default:
-		DBG_ERR("unknown acl style %d", acl_style);
-		status = NT_STATUS_INTERNAL_ERROR;
-		break;
-	}
-
-	return status;
-}
-
 /**
  * Validate an ACL blob
  *
diff --git a/source3/modules/vfs_acl_common.h b/source3/modules/vfs_acl_common.h
index c52fc5094c5..24803e0215e 100644
--- a/source3/modules/vfs_acl_common.h
+++ b/source3/modules/vfs_acl_common.h
@@ -22,7 +22,7 @@
 #ifndef __VFS_ACL_COMMON_H__
 #define __VFS_ACL_COMMON_H__
 
-enum default_acl_style {DEFAULT_ACL_POSIX, DEFAULT_ACL_WINDOWS};
+#include "smbd/proto.h"
 
 struct acl_common_config {
 	bool ignore_system_acls;
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 7bd65390406..7337c5e8ecb 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -4857,3 +4857,219 @@ int posix_sys_acl_blob_get_fd(vfs_handle_struct *handle,
 	TALLOC_FREE(frame);
 	return 0;
 }
+
+static NTSTATUS make_default_acl_posix(TALLOC_CTX *ctx,
+				       const char *name,
+				       SMB_STRUCT_STAT *psbuf,
+				       struct security_descriptor **ppdesc)
+{
+	struct dom_sid owner_sid, group_sid;
+	size_t size = 0;
+	struct security_ace aces[4];
+	uint32_t access_mask = 0;
+	mode_t mode = psbuf->st_ex_mode;
+	struct security_acl *new_dacl = NULL;
+	int idx = 0;
+
+	DBG_DEBUG("file %s mode = 0%o\n",name, (int)mode);
+
+	uid_to_sid(&owner_sid, psbuf->st_ex_uid);
+	gid_to_sid(&group_sid, psbuf->st_ex_gid);
+
+	/*
+	 We provide up to 4 ACEs
+		- Owner
+		- Group
+		- Everyone
+		- NT System
+	*/
+
+	if (mode & S_IRUSR) {
+		if (mode & S_IWUSR) {
+			access_mask |= SEC_RIGHTS_FILE_ALL;
+		} else {
+			access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+		}
+	}
+	if (mode & S_IWUSR) {
+		access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
+	}
+
+	init_sec_ace(&aces[idx],
+			&owner_sid,
+			SEC_ACE_TYPE_ACCESS_ALLOWED,
+			access_mask,
+			0);
+	idx++;
+
+	access_mask = 0;
+	if (mode & S_IRGRP) {
+		access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+	}
+	if (mode & S_IWGRP) {
+		/* note that delete is not granted - this matches posix behaviour */
+		access_mask |= SEC_RIGHTS_FILE_WRITE;
+	}
+	if (access_mask) {
+		init_sec_ace(&aces[idx],
+			&group_sid,
+			SEC_ACE_TYPE_ACCESS_ALLOWED,
+			access_mask,
+			0);
+		idx++;
+	}
+
+	access_mask = 0;
+	if (mode & S_IROTH) {
+		access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+	}
+	if (mode & S_IWOTH) {
+		access_mask |= SEC_RIGHTS_FILE_WRITE;
+	}
+	if (access_mask) {
+		init_sec_ace(&aces[idx],
+			&global_sid_World,
+			SEC_ACE_TYPE_ACCESS_ALLOWED,
+			access_mask,
+			0);
+		idx++;
+	}
+
+	init_sec_ace(&aces[idx],
+			&global_sid_System,
+			SEC_ACE_TYPE_ACCESS_ALLOWED,
+			SEC_RIGHTS_FILE_ALL,
+			0);
+	idx++;
+
+	new_dacl = make_sec_acl(ctx,
+			NT4_ACL_REVISION,
+			idx,
+			aces);
+
+	if (!new_dacl) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	*ppdesc = make_sec_desc(ctx,
+			SECURITY_DESCRIPTOR_REVISION_1,
+			SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
+			&owner_sid,
+			&group_sid,
+			NULL,
+			new_dacl,
+			&size);
+	if (!*ppdesc) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS make_default_acl_windows(TALLOC_CTX *ctx,
+					 const char *name,
+					 SMB_STRUCT_STAT *psbuf,
+					 struct security_descriptor **ppdesc)
+{
+	struct dom_sid owner_sid, group_sid;
+	size_t size = 0;
+	struct security_ace aces[4];
+	uint32_t access_mask = 0;
+	mode_t mode = psbuf->st_ex_mode;
+	struct security_acl *new_dacl = NULL;
+	int idx = 0;
+
+	DBG_DEBUG("file [%s] mode [0%o]\n", name, (int)mode);
+
+	uid_to_sid(&owner_sid, psbuf->st_ex_uid);
+	gid_to_sid(&group_sid, psbuf->st_ex_gid);
+
+	/*
+	 * We provide 2 ACEs:
+	 * - Owner
+	 * - NT System
+	 */
+
+	if (mode & S_IRUSR) {
+		if (mode & S_IWUSR) {
+			access_mask |= SEC_RIGHTS_FILE_ALL;
+		} else {
+			access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+		}
+	}
+	if (mode & S_IWUSR) {
+		access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
+	}
+
+	init_sec_ace(&aces[idx],
+		     &owner_sid,
+		     SEC_ACE_TYPE_ACCESS_ALLOWED,
+		     access_mask,
+		     0);
+	idx++;
+
+	init_sec_ace(&aces[idx],
+		     &global_sid_System,
+		     SEC_ACE_TYPE_ACCESS_ALLOWED,
+		     SEC_RIGHTS_FILE_ALL,
+		     0);
+	idx++;
+
+	new_dacl = make_sec_acl(ctx,
+				NT4_ACL_REVISION,
+				idx,
+				aces);
+
+	if (!new_dacl) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	*ppdesc = make_sec_desc(ctx,
+				SECURITY_DESCRIPTOR_REVISION_1,
+				SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
+				&owner_sid,
+				&group_sid,
+				NULL,
+				new_dacl,
+				&size);
+	if (!*ppdesc) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	return NT_STATUS_OK;
+}
+
+static const struct enum_list default_acl_style_list[] = {
+	{DEFAULT_ACL_POSIX,	"posix"},
+	{DEFAULT_ACL_WINDOWS,	"windows"}
+};
+
+const struct enum_list *get_default_acl_style_list(void)
+{
+	return default_acl_style_list;
+}
+
+NTSTATUS make_default_filesystem_acl(
+	TALLOC_CTX *ctx,
+	enum default_acl_style acl_style,
+	const char *name,
+	SMB_STRUCT_STAT *psbuf,
+	struct security_descriptor **ppdesc)
+{
+	NTSTATUS status;
+
+	switch (acl_style) {
+	case DEFAULT_ACL_POSIX:
+		status =  make_default_acl_posix(ctx, name, psbuf, ppdesc);
+		break;
+
+	case DEFAULT_ACL_WINDOWS:
+		status =  make_default_acl_windows(ctx, name, psbuf, ppdesc);
+		break;
+
+	default:
+		DBG_ERR("unknown acl style %d", acl_style);
+		status = NT_STATUS_INTERNAL_ERROR;
+		break;
+	}
+
+	return status;
+}
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index a688341c64d..2e40711df41 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -806,6 +806,17 @@ int posix_sys_acl_blob_get_fd(vfs_handle_struct *handle,
 			      char **blob_description,
 			      DATA_BLOB *blob);
 
+enum default_acl_style {DEFAULT_ACL_POSIX, DEFAULT_ACL_WINDOWS};
+
+const struct enum_list *get_default_acl_style_list(void);
+
+NTSTATUS make_default_filesystem_acl(
+	TALLOC_CTX *ctx,
+	enum default_acl_style acl_style,
+	const char *name,
+	SMB_STRUCT_STAT *psbuf,
+	struct security_descriptor **ppdesc);
+
 /* The following definitions come from smbd/process.c  */
 
 void smbd_setup_sig_term_handler(struct smbd_server_connection *sconn);
-- 
2.13.6


From 1db3743b72cd5c98df7eab4b159b64eb9235315e Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 17 Oct 2017 15:18:52 +0200
Subject: [PATCH 04/27] s3/posix_acls: add default ACL style "everyone"

This synthesizes an ACL with a single ACE with full permissions for
everyone. Not used for now, this comes later.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 docs-xml/manpages/vfs_acl_tdb.8.xml   |  6 +++-
 docs-xml/manpages/vfs_acl_xattr.8.xml |  6 +++-
 source3/smbd/posix_acls.c             | 58 ++++++++++++++++++++++++++++++++++-
 source3/smbd/proto.h                  |  2 +-
 4 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/docs-xml/manpages/vfs_acl_tdb.8.xml b/docs-xml/manpages/vfs_acl_tdb.8.xml
index e36ccd91aa2..58cc0914c22 100644
--- a/docs-xml/manpages/vfs_acl_tdb.8.xml
+++ b/docs-xml/manpages/vfs_acl_tdb.8.xml
@@ -89,7 +89,7 @@
 		</varlistentry>
 
 		<varlistentry>
-		<term>acl_tdb:default acl style = [posix|windows]</term>
+		<term>acl_tdb:default acl style = [posix|windows|everyone]</term>
 		<listitem>
 		<para>
 		This parameter determines the type of ACL that is synthesized in
@@ -108,6 +108,10 @@
 		owner and <emphasis>NT Authority\SYSTEM</emphasis>.
 		</para>
 		<para>
+		When set to <emphasis>everyone</emphasis>, an ACL is synthesized
+		giving full permissions to everyone (S-1-1-0).
+		</para>
+		<para>
 		The default for this option is <emphasis>posix</emphasis>.
 		</para>
 		</listitem>
diff --git a/docs-xml/manpages/vfs_acl_xattr.8.xml b/docs-xml/manpages/vfs_acl_xattr.8.xml
index 43731f7ee92..f70e17c6ffe 100644
--- a/docs-xml/manpages/vfs_acl_xattr.8.xml
+++ b/docs-xml/manpages/vfs_acl_xattr.8.xml
@@ -93,7 +93,7 @@
 		</varlistentry>
 
 		<varlistentry>
-		<term>acl_xattr:default acl style = [posix|windows]</term>
+		<term>acl_xattr:default acl style = [posix|windows|everyone]</term>
 		<listitem>
 		<para>
 		This parameter determines the type of ACL that is synthesized in
@@ -112,6 +112,10 @@
 		owner and <emphasis>NT Authority\SYSTEM</emphasis>.
 		</para>
 		<para>
+		When set to <emphasis>everyone</emphasis>, an ACL is synthesized
+		giving full permissions to everyone (S-1-1-0).
+		</para>
+		<para>
 		The default for this option is <emphasis>posix</emphasis>.
 		</para>
 		</listitem>
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 7337c5e8ecb..2d5c0e04555 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -5037,9 +5037,61 @@ static NTSTATUS make_default_acl_windows(TALLOC_CTX *ctx,
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS make_default_acl_everyone(TALLOC_CTX *ctx,
+					  const char *name,
+					  SMB_STRUCT_STAT *psbuf,
+					  struct security_descriptor **ppdesc)
+{
+	struct dom_sid owner_sid, group_sid;
+	size_t size = 0;
+	struct security_ace aces[4];
+	mode_t mode = psbuf->st_ex_mode;
+	struct security_acl *new_dacl = NULL;
+	int idx = 0;
+
+	DBG_DEBUG("file [%s] mode [0%o]\n", name, (int)mode);
+
+	uid_to_sid(&owner_sid, psbuf->st_ex_uid);
+	gid_to_sid(&group_sid, psbuf->st_ex_gid);
+
+	/*
+	 * We provide one ACEs: full access for everyone
+	 */
+
+	init_sec_ace(&aces[idx],
+		     &global_sid_World,
+		     SEC_ACE_TYPE_ACCESS_ALLOWED,
+		     SEC_RIGHTS_FILE_ALL,
+		     0);
+	idx++;
+
+	new_dacl = make_sec_acl(ctx,
+				NT4_ACL_REVISION,
+				idx,
+				aces);
+
+	if (!new_dacl) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	*ppdesc = make_sec_desc(ctx,
+				SECURITY_DESCRIPTOR_REVISION_1,
+				SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
+				&owner_sid,
+				&group_sid,
+				NULL,
+				new_dacl,
+				&size);
+	if (!*ppdesc) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	return NT_STATUS_OK;
+}
+
 static const struct enum_list default_acl_style_list[] = {
 	{DEFAULT_ACL_POSIX,	"posix"},
-	{DEFAULT_ACL_WINDOWS,	"windows"}
+	{DEFAULT_ACL_WINDOWS,	"windows"},
+	{DEFAULT_ACL_EVERYONE,	"everyone"},
 };
 
 const struct enum_list *get_default_acl_style_list(void)
@@ -5065,6 +5117,10 @@ NTSTATUS make_default_filesystem_acl(
 		status =  make_default_acl_windows(ctx, name, psbuf, ppdesc);
 		break;
 
+	case DEFAULT_ACL_EVERYONE:
+		status =  make_default_acl_everyone(ctx, name, psbuf, ppdesc);
+		break;
+
 	default:
 		DBG_ERR("unknown acl style %d", acl_style);
 		status = NT_STATUS_INTERNAL_ERROR;
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 2e40711df41..c85a6cccd5b 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -806,7 +806,7 @@ int posix_sys_acl_blob_get_fd(vfs_handle_struct *handle,
 			      char **blob_description,
 			      DATA_BLOB *blob);
 
-enum default_acl_style {DEFAULT_ACL_POSIX, DEFAULT_ACL_WINDOWS};
+enum default_acl_style {DEFAULT_ACL_POSIX, DEFAULT_ACL_WINDOWS, DEFAULT_ACL_EVERYONE};
 
 const struct enum_list *get_default_acl_style_list(void);
 
-- 
2.13.6


From 703cbff2fa912563f2dde90c476a40964fcb213d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 16 Oct 2017 17:04:01 +0200
Subject: [PATCH 05/27] vfs_nfs4acl_xattr: remove a layer of indirection

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_nfs4acl_xattr.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 951faa47849..909c624948c 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -331,18 +331,6 @@ static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
 	return ret == 0;
 }
 
-/* nfs4_set_nt_acl()
- * set the local file's acls obtaining it in NT form
- * using the NFSv4 format conversion
- */
-static NTSTATUS nfs4_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
-			   uint32_t security_info_sent,
-			   const struct security_descriptor *psd)
-{
-	return smb_set_nt_acl_nfs4(handle, fsp, NULL, security_info_sent, psd,
-			nfs4acl_xattr_fset_smb4acl);
-}
-
 static struct SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
 {
 	struct SMB4ACL_T *pacl = NULL;
@@ -590,7 +578,8 @@ static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
 			 uint32_t security_info_sent,
 			 const struct security_descriptor *psd)
 {
-	return nfs4_set_nt_acl(handle, fsp, security_info_sent, psd);
+	return smb_set_nt_acl_nfs4(handle, fsp, NULL, security_info_sent,
+				   psd,	nfs4acl_xattr_fset_smb4acl);
 }
 
 /*
-- 
2.13.6


From c68f83da1a7cdf4cfef353295ece66221df90650 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 19 Oct 2017 15:50:07 +0200
Subject: [PATCH 06/27] vfs_nfs4acl_xattr: move interesting functions pointers
 to the top

Move interesting functions to the top of the vfs_fn_pointers struct, no
change in behaviour.

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

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 909c624948c..7465ba8afbf 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -643,6 +643,10 @@ static int nfs4acl_xattr_fail__sys_acl_blob_get_fd(vfs_handle_struct *handle, fi
 /* VFS operations structure */
 
 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
+	.fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
+	.get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
+	.fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
+
 	.sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file,
 	.sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd,
 	.sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file,
@@ -650,9 +654,6 @@ static struct vfs_fn_pointers nfs4acl_xattr_fns = {
 	.sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file,
 	.sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd,
 	.sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file,
-	.fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
-	.get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
-	.fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
 };
 
 NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *);
-- 
2.13.6


From dfa0bba76cbca10626e4ede2498dbc7c49e67dca Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 19 Oct 2017 12:29:47 +0200
Subject: [PATCH 07/27] librpc/idl: rename NFS4 ACL xattr name define

No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 librpc/idl/nfs4acl.idl              | 2 +-
 source3/modules/vfs_nfs4acl_xattr.c | 8 ++++----
 source4/ntvfs/posix/pvfs_acl_nfs4.c | 4 ++--
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/librpc/idl/nfs4acl.idl b/librpc/idl/nfs4acl.idl
index 5a3d0268f21..3d6894a604c 100644
--- a/librpc/idl/nfs4acl.idl
+++ b/librpc/idl/nfs4acl.idl
@@ -13,7 +13,7 @@ import "misc.idl", "security.idl";
 ]
 interface nfs4acl_interface
 {
-	const char *NFS4ACL_XATTR_NAME = "system.nfs4acl";
+	const char *NFS4ACL_NDR_XATTR_NAME = "system.nfs4acl";
 
 	const char *NFS4ACL_XATTR_OWNER_WHO	 = "OWNER@";
 	const char *NFS4ACL_XATTR_GROUP_WHO	 = "GROUP@";
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 7465ba8afbf..fd47b86255e 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -135,7 +135,7 @@ static NTSTATUS nfs4_fget_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ct
 			errno = ENOMEM;
 			return NT_STATUS_NO_MEMORY;
 		}
-		length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, NFS4ACL_XATTR_NAME, blob.data, blob.length);
+		length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, NFS4ACL_NDR_XATTR_NAME, blob.data, blob.length);
 		blob.length = length;
 	} while (length == -1 && errno == ERANGE);
 	if (length == -1) {
@@ -167,7 +167,7 @@ static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle,
 			return NT_STATUS_NO_MEMORY;
 		}
 		length = SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
-				NFS4ACL_XATTR_NAME, blob.data, blob.length);
+				NFS4ACL_NDR_XATTR_NAME, blob.data, blob.length);
 		blob.length = length;
 	} while (length == -1 && errno == ERANGE);
 	if (length == -1) {
@@ -281,7 +281,7 @@ static bool nfs4acl_xattr_set_smb4acl(vfs_handle_struct *handle,
 		errno = EINVAL;
 		return false;
 	}
-	ret = SMB_VFS_NEXT_SETXATTR(handle, smb_fname, NFS4ACL_XATTR_NAME,
+	ret = SMB_VFS_NEXT_SETXATTR(handle, smb_fname, NFS4ACL_NDR_XATTR_NAME,
 				    blob.data, blob.length, 0);
 	if (ret != 0) {
 		DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
@@ -322,7 +322,7 @@ static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
 	if (fsp->fh->fd == -1) {
 		DEBUG(0, ("Error: fsp->fh->fd == -1\n"));
 	}
-	ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_XATTR_NAME,
+	ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_NDR_XATTR_NAME,
 				     blob.data, blob.length, 0);
 	if (ret != 0) {
 		DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
diff --git a/source4/ntvfs/posix/pvfs_acl_nfs4.c b/source4/ntvfs/posix/pvfs_acl_nfs4.c
index b07d2ba9b41..fc6c230817d 100644
--- a/source4/ntvfs/posix/pvfs_acl_nfs4.c
+++ b/source4/ntvfs/posix/pvfs_acl_nfs4.c
@@ -47,7 +47,7 @@ static NTSTATUS pvfs_acl_load_nfs4(struct pvfs_state *pvfs, struct pvfs_filename
 	NT_STATUS_HAVE_NO_MEMORY(acl);
 
 	status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name, fd, 
-				     NFS4ACL_XATTR_NAME,
+				     NFS4ACL_NDR_XATTR_NAME,
 				     acl, (void *) ndr_pull_nfs4acl);
 	if (!NT_STATUS_IS_OK(status)) {
 		talloc_free(acl);
@@ -176,7 +176,7 @@ static NTSTATUS pvfs_acl_save_nfs4(struct pvfs_state *pvfs, struct pvfs_filename
 
 	privs = root_privileges();
 	status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
-				     NFS4ACL_XATTR_NAME, 
+				     NFS4ACL_NDR_XATTR_NAME,
 				     &acl, (void *) ndr_push_nfs4acl);
 	talloc_free(privs);
 
-- 
2.13.6


From 59b535f31a6ce07d8eca3a717dac9b02f282cc1e Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 2 Nov 2017 12:17:48 +0100
Subject: [PATCH 08/27] librpc/idl: rename NFS4 ACL xattr name

The "system" xattr namespace is reserved for the kernel. Any attempt to
use xattrs in that namesspace will fail with EOPNOTSUPP, regardless of
priveleges. In autobuild we're using the xattr_tdb VFS module, so it
works there.

Using the "security" namespace instead makes this module generally
usable with Linux filesystem xattrs as storage backend.

Additionally prefix the xattr name with "_ndr". This is in preperation
of later commits that add a ACL blob marshalling format based on XDR. To
avoid xattr name collision, both format will use distinct xattr names by
default.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 librpc/idl/nfs4acl.idl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/librpc/idl/nfs4acl.idl b/librpc/idl/nfs4acl.idl
index 3d6894a604c..79e742c90e7 100644
--- a/librpc/idl/nfs4acl.idl
+++ b/librpc/idl/nfs4acl.idl
@@ -13,7 +13,7 @@ import "misc.idl", "security.idl";
 ]
 interface nfs4acl_interface
 {
-	const char *NFS4ACL_NDR_XATTR_NAME = "system.nfs4acl";
+	const char *NFS4ACL_NDR_XATTR_NAME = "security.nfs4acl_ndr";
 
 	const char *NFS4ACL_XATTR_OWNER_WHO	 = "OWNER@";
 	const char *NFS4ACL_XATTR_GROUP_WHO	 = "GROUP@";
-- 
2.13.6


From 2beb042b7af4a211e2e1b17f73beb9c0af5c096a Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 19 Oct 2017 14:22:00 +0200
Subject: [PATCH 09/27] librpc/idl: add versions consts to nfs4acl.idl

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 librpc/idl/nfs4acl.idl | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/librpc/idl/nfs4acl.idl b/librpc/idl/nfs4acl.idl
index 79e742c90e7..1f0cfbf7a04 100644
--- a/librpc/idl/nfs4acl.idl
+++ b/librpc/idl/nfs4acl.idl
@@ -19,6 +19,10 @@ interface nfs4acl_interface
 	const char *NFS4ACL_XATTR_GROUP_WHO	 = "GROUP@";
 	const char *NFS4ACL_XATTR_EVERYONE_WHO   = "EVERYONE@";
 
+	const uint8 ACL4_XATTR_VERSION_40      = 0x00;
+	const uint8 ACL4_XATTR_VERSION_41      = 0x01;
+	const uint8 ACL4_XATTR_VERSION_DEFAULT = ACL4_XATTR_VERSION_40;
+
 	/* these structures use the same bit values and other constants as
 	   in security.idl */
 	typedef [flag(NDR_BIG_ENDIAN)] struct {
-- 
2.13.6


From 7c92dc2a5e68c968ca0e198e69e088c41fbc8c17 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 19 Oct 2017 16:34:44 +0200
Subject: [PATCH 10/27] vfs_nfs4acl_xattr: add a runtime configuration object

No change in behaviour, all option defaults are set to the original
behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/nfs4acl_xattr.h     | 32 ++++++++++++++
 source3/modules/vfs_nfs4acl_xattr.c | 88 +++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+)
 create mode 100644 source3/modules/nfs4acl_xattr.h

diff --git a/source3/modules/nfs4acl_xattr.h b/source3/modules/nfs4acl_xattr.h
new file mode 100644
index 00000000000..3eeb4703bc8
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) Ralph Boehme 2017
+ *
+ * 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 __NFS4ACL_XATTR_H__
+#define __NFS4ACL_XATTR_H__
+
+enum nfs4acl_encoding {NFS4ACL_ENCODING_NDR, NFS4ACL_ENCODING_XDR};
+
+struct nfs4acl_config {
+	unsigned nfs_version;
+	enum nfs4acl_encoding encoding;
+	char *xattr_name;
+	struct smbacl4_vfs_params nfs4_params;
+	enum default_acl_style default_acl_style;
+};
+
+#endif /* __NFS4ACL_XATTR_H__ */
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index fd47b86255e..312123a265f 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -9,6 +9,7 @@
  * Copyright (C) Tim Potter, 1999-2000
  * Copyright (C) Alexander Bokovoy, 2002
  * Copyright (C) Andrew Bartlett, 2002,2012
+ * Copyright (C) Ralph Boehme 2017
  *
  * 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
@@ -30,10 +31,16 @@
 #include "smbd/smbd.h"
 #include "nfs4_acls.h"
 #include "librpc/gen_ndr/ndr_nfs4acl.h"
+#include "nfs4acl_xattr.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
 
+static const struct enum_list nfs4acl_encoding[] = {
+	{NFS4ACL_ENCODING_NDR, "ndr"},
+	{NFS4ACL_ENCODING_XDR, "xdr"},
+};
+
 static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 {
 	enum ndr_err_code ndr_err;
@@ -582,6 +589,86 @@ static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
 				   psd,	nfs4acl_xattr_fset_smb4acl);
 }
 
+static int nfs4acl_connect(struct vfs_handle_struct *handle,
+			   const char *service,
+			   const char *user)
+{
+	struct nfs4acl_config *config = NULL;
+	const struct enum_list *default_acl_style_list = NULL;
+	const char *default_xattr_name = NULL;
+	int enumval;
+	unsigned nfs_version;
+	int ret;
+
+	default_acl_style_list = get_default_acl_style_list();
+
+	config = talloc_zero(handle->conn, struct nfs4acl_config);
+	if (config == NULL) {
+		DBG_ERR("talloc_zero() failed\n");
+		return -1;
+	}
+
+	ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
+	if (ret < 0) {
+		TALLOC_FREE(config);
+		return ret;
+	}
+
+	ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
+	if (ret < 0) {
+		TALLOC_FREE(config);
+		return ret;
+	}
+
+	enumval = lp_parm_enum(SNUM(handle->conn),
+			       "nfs4acl_xattr",
+			       "encoding",
+			       nfs4acl_encoding,
+			       NFS4ACL_ENCODING_NDR);
+	if (enumval == -1) {
+		DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
+		return -1;
+	}
+	config->encoding = (enum nfs4acl_encoding)enumval;
+
+	switch (config->encoding) {
+	case NFS4ACL_ENCODING_NDR:
+	default:
+		default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
+		break;
+	}
+
+	nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
+					    "nfs4acl_xattr",
+					    "version",
+					    40);
+	switch (nfs_version) {
+	case 40:
+		config->nfs_version = ACL4_XATTR_VERSION_40;
+		break;
+	default:
+		config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
+		break;
+	}
+
+	config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
+						 "nfs4acl_xattr",
+						 "default acl style",
+						 default_acl_style_list,
+						 DEFAULT_ACL_EVERYONE);
+
+	config->xattr_name = lp_parm_talloc_string(config,
+						   SNUM(handle->conn),
+						   "nfs4acl_xattr",
+						   "xattr_name",
+						   default_xattr_name);
+
+	SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
+				return -1);
+
+	return 0;
+}
+
 /*
    As long as Samba does not support an exiplicit method for a module
    to define conflicting vfs methods, we should override all conflicting
@@ -643,6 +730,7 @@ static int nfs4acl_xattr_fail__sys_acl_blob_get_fd(vfs_handle_struct *handle, fi
 /* VFS operations structure */
 
 static struct vfs_fn_pointers nfs4acl_xattr_fns = {
+	.connect_fn = nfs4acl_connect,
 	.fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
 	.get_nt_acl_fn = nfs4acl_xattr_get_nt_acl,
 	.fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
-- 
2.13.6


From da476cedd3f7080c10080fb0517297e3b3c99afd Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 16 Oct 2017 18:05:51 +0200
Subject: [PATCH 11/27] vfs_nfs4acl_xattr: modernize ACL inheritance

This changes the way ACL inheritance is achieved in this
module.

Previously the module recursed to the next parent directory until the
share root was reached or a directory with an ACL xattr. If the share
root didn't contain an ACL xattr either a default ACL would be used.

This commit removed this recursive scanning and replaces it with the
same mechanism used by vfs_acl_xattr: by setting "inherit acls = yes"
just let smbd do the heavy lefting and inheritance.

For any file without ACL xattr we still synthesize a default ACL,
leveraging the existing default ACL function used by vfs_acl_xattr.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail                  |   2 -
 source3/modules/vfs_nfs4acl_xattr.c | 277 ++++++++----------------------------
 2 files changed, 57 insertions(+), 222 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 258548ec858..030520f7e58 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -26,13 +26,11 @@
 ^samba3.raw.acls nfs4acl_xattr-simple.create_owner_dir\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple.nulldacl\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple.generic\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-simple.inheritance\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.INHERITFLAGS\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.create_owner_file\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.create_owner_dir\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.nulldacl\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.generic\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.inheritance\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.inherit_creator_owner\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.inherit_creator_group\(nt4_dc\)
 ^samba3.base.delete.deltest16a
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 312123a265f..fc30f66f1d4 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -260,43 +260,6 @@ static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 	return true;
 }
 
-static bool nfs4acl_xattr_set_smb4acl(vfs_handle_struct *handle,
-				      const struct smb_filename *smb_fname,
-				      struct SMB4ACL_T *smbacl)
-{
-	TALLOC_CTX *frame = talloc_stackframe();
-	struct nfs4acl *nfs4acl;
-	int ret;
-	bool denymissingspecial;
-	DATA_BLOB blob;
-
-	denymissingspecial = lp_parm_bool(handle->conn->params->service,
-					  "nfs4acl_xattr",
-					  "denymissingspecial", false);
-
-	if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
-				     denymissingspecial)) {
-		DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
-		TALLOC_FREE(frame);
-		return false;
-	}
-
-	blob = nfs4acl_acl2blob(frame, nfs4acl);
-	if (!blob.data) {
-		DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
-		TALLOC_FREE(frame);
-		errno = EINVAL;
-		return false;
-	}
-	ret = SMB_VFS_NEXT_SETXATTR(handle, smb_fname, NFS4ACL_NDR_XATTR_NAME,
-				    blob.data, blob.length, 0);
-	if (ret != 0) {
-		DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
-	}
-	TALLOC_FREE(frame);
-	return ret == 0;
-}
-
 /* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
 static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
 				       files_struct *fsp,
@@ -338,194 +301,47 @@ static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
 	return ret == 0;
 }
 
-static struct SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
-{
-	struct SMB4ACL_T *pacl = NULL;
-	struct SMB4ACE_T *pace;
-	SMB_ACE4PROP_T ace = {
-		.flags = SMB_ACE4_ID_SPECIAL,
-		.who = {
-			.id = SMB_ACE4_WHO_EVERYONE,
-		},
-		.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE,
-		.aceFlags = 0,
-		.aceMask = SMB_ACE4_ALL_MASKS,
-	};
-
-	DEBUG(10, ("Building default full access acl\n"));
-
-	pacl = smb_create_smb4acl(mem_ctx);
-	if (pacl == NULL) {
-		DEBUG(0, ("talloc failed\n"));
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	pace = smb_add_ace4(pacl, &ace);
-	if (pace == NULL) {
-		DEBUG(0, ("talloc failed\n"));
-		TALLOC_FREE(pacl);
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	return pacl;
-}
-
-/*
- * Because there is no good way to guarantee that a new xattr will be
- * created on file creation there might be no acl xattr on a file when
- * trying to read the acl. In this case the acl xattr will get
- * constructed at that time from the parent acl.
- * If the parent ACL doesn't have an xattr either the call will
- * recurse to the next parent directory until the share root is
- * reached. If the share root doesn't contain an ACL xattr either a
- * default ACL will be used.
- * Also a default ACL will be set if a non inheriting ACL is encountered.
- *
- * Basic algorithm:
- *   read acl xattr blob
- *   if acl xattr blob doesn't exist
- *     stat current directory to know if it's a file or directory
- *     read acl xattr blob from parent dir
- *     acl xattr blob to smb nfs4 acl
- *     calculate inherited smb nfs4 acl
- *     without inheritance use default smb nfs4 acl
- *     smb nfs4 acl to acl xattr blob
- *     set acl xattr blob
- *     return smb nfs4 acl
- *   else
- *     acl xattr blob to smb nfs4 acl
- *
- * Todo: Really use mem_ctx after fixing interface of nfs4_acls
- */
-static struct SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
-	const struct smb_filename *smb_fname_in,
-	TALLOC_CTX *mem_ctx)
+static NTSTATUS nfs4acl_xattr_default_sd(
+	struct vfs_handle_struct *handle,
+	const struct smb_filename *smb_fname,
+	TALLOC_CTX *mem_ctx,
+	struct security_descriptor **sd)
 {
-	char *parent_dir = NULL;
-	struct SMB4ACL_T *pparentacl = NULL;
-	struct SMB4ACL_T *pchildacl = NULL;
-	struct SMB4ACE_T *pace;
-	SMB_ACE4PROP_T ace;
-	bool isdir;
-	struct smb_filename *smb_fname = NULL;
-	struct smb_filename *smb_fname_parent = NULL;
-	NTSTATUS status;
+	struct nfs4acl_config *config = NULL;
+	enum default_acl_style default_acl_style;
+	mode_t required_mode;
+	SMB_STRUCT_STAT sbuf = smb_fname->st;
 	int ret;
-	TALLOC_CTX *frame = talloc_stackframe();
 
-	DEBUG(10, ("nfs4acls_inheritacl invoked for %s\n",
-			smb_fname_in->base_name));
-	smb_fname = cp_smb_filename_nostream(frame, smb_fname_in);
-	if (smb_fname == NULL) {
-		TALLOC_FREE(frame);
-		errno = ENOMEM;
-		return NULL;
-	}
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
 
-	ret = SMB_VFS_STAT(handle->conn, smb_fname);
-	if (ret == -1) {
-		DEBUG(0,("nfs4acls_inheritacl: failed to stat "
-			 "directory %s. Error was %s\n",
-			 smb_fname_str_dbg(smb_fname),
-			 strerror(errno)));
-		TALLOC_FREE(frame);
-		return NULL;
-	}
-	isdir = S_ISDIR(smb_fname->st.st_ex_mode);
+	default_acl_style = config->default_acl_style;
 
-	if (!parent_dirname(talloc_tos(),
-			    smb_fname->base_name,
-			    &parent_dir,
-			    NULL)) {
-		TALLOC_FREE(frame);
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	smb_fname_parent = synthetic_smb_fname(talloc_tos(),
-				parent_dir,
-				NULL,
-				NULL,
-				0);
-	if (smb_fname_parent == NULL) {
-		TALLOC_FREE(frame);
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	status = nfs4_get_nfs4_acl(handle, frame, smb_fname_parent,
-					&pparentacl);
-	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)
-	    && strncmp(parent_dir, ".", 2) != 0) {
-		pparentacl = nfs4acls_inheritacl(handle,
-						smb_fname_parent,
-						frame);
-	}
-	else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
-		pparentacl = nfs4acls_defaultacl(frame);
-
-	}
-	else if (!NT_STATUS_IS_OK(status)) {
-		TALLOC_FREE(frame);
-		return NULL;
-	}
-
-	pchildacl = smb_create_smb4acl(mem_ctx);
-	if (pchildacl == NULL) {
-		DEBUG(0, ("talloc failed\n"));
-		TALLOC_FREE(frame);
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	for (pace = smb_first_ace4(pparentacl); pace != NULL;
-	     pace = smb_next_ace4(pace)) {
-		struct SMB4ACE_T *pchildace;
-		ace = *smb_get_ace4(pace);
-		if ((isdir && !(ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) ||
-		    (!isdir && !(ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE))) {
-			DEBUG(10, ("non inheriting ace type: %d, iflags: %x, "
-				   "flags: %x, mask: %x, who: %d\n",
-				   ace.aceType, ace.flags, ace.aceFlags,
-				   ace.aceMask, ace.who.id));
-			continue;
-		}
-		DEBUG(10, ("inheriting ace type: %d, iflags: %x, "
-			   "flags: %x, mask: %x, who: %d\n",
-			   ace.aceType, ace.flags, ace.aceFlags,
-			   ace.aceMask, ace.who.id));
-		ace.aceFlags |= SMB_ACE4_INHERITED_ACE;
-		if (ace.aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) {
-			ace.aceFlags &= ~SMB_ACE4_INHERIT_ONLY_ACE;
-		}
-		if (ace.aceFlags & SMB_ACE4_NO_PROPAGATE_INHERIT_ACE) {
-			ace.aceFlags &= ~SMB_ACE4_FILE_INHERIT_ACE;
-			ace.aceFlags &= ~SMB_ACE4_DIRECTORY_INHERIT_ACE;
-			ace.aceFlags &= ~SMB_ACE4_NO_PROPAGATE_INHERIT_ACE;
-		}
-		pchildace = smb_add_ace4(pchildacl, &ace);
-		if (pchildace == NULL) {
-			DEBUG(0, ("talloc failed\n"));
-			TALLOC_FREE(frame);
-			errno = ENOMEM;
-			return NULL;
+	if (!VALID_STAT(sbuf)) {
+		ret = vfs_stat_smb_basename(handle->conn,
+					    smb_fname,
+					    &sbuf);
+		if (ret != 0) {
+			return map_nt_error_from_unix(errno);
 		}
 	}
 
-	/* Set a default ACL if we didn't inherit anything. */
-	if (smb_first_ace4(pchildacl) == NULL) {
-		TALLOC_FREE(pchildacl);
-		pchildacl = nfs4acls_defaultacl(mem_ctx);
+	if (S_ISDIR(sbuf.st_ex_mode)) {
+		required_mode = 0777;
+	} else {
+		required_mode = 0666;
+	}
+	if ((sbuf.st_ex_mode & required_mode) != required_mode) {
+		default_acl_style = DEFAULT_ACL_POSIX;
 	}
 
-	/* store the returned ACL to get it directly in the
-	   future and avoid dynamic inheritance behavior. */
-	nfs4acl_xattr_set_smb4acl(handle, smb_fname, pchildacl);
-
-	TALLOC_FREE(frame);
-	return pchildacl;
+	return make_default_filesystem_acl(mem_ctx,
+					   default_acl_style,
+					   smb_fname->base_name,
+					   &sbuf,
+					   sd);
 }
 
 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
@@ -540,10 +356,11 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
 
 	status = nfs4_fget_nfs4_acl(handle, frame, fsp, &pacl);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
-		pacl = nfs4acls_inheritacl(handle, fsp->fsp_name,
-					   frame);
+		TALLOC_FREE(frame);
+		return nfs4acl_xattr_default_sd(
+			handle, fsp->fsp_name, mem_ctx, ppdesc);
 	}
-	else if (!NT_STATUS_IS_OK(status)) {
+	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(frame);
 		return status;
 	}
@@ -566,9 +383,11 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
 
 	status = nfs4_get_nfs4_acl(handle, frame, smb_fname, &pacl);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
-		pacl = nfs4acls_inheritacl(handle, smb_fname, frame);
+		TALLOC_FREE(frame);
+		return nfs4acl_xattr_default_sd(
+			handle,	smb_fname, mem_ctx, ppdesc);
 	}
-	else if (!NT_STATUS_IS_OK(status)) {
+	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(frame);
 		return status;
 	}
@@ -666,6 +485,24 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 	SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
 				return -1);
 
+	/*
+	 * Ensure we have the parameters correct if we're using this module.
+	 */
+	DBG_NOTICE("Setting 'inherit acls = true', "
+		   "'dos filemode = true', "
+		   "'force unknown acl user = true', "
+		   "'create mask = 0666', "
+		   "'directory mask = 0777' and "
+		   "'store dos attributes = yes' "
+		   "for service [%s]\n", service);
+
+	lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
+	lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
+	lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
+	lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
+	lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
+	lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
+
 	return 0;
 }
 
-- 
2.13.6


From 9dd3e5bb79a651b62978638b643b26166f3703a2 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 19 Oct 2017 21:53:40 +0200
Subject: [PATCH 12/27] vfs_nfs4acl_xattr: code polish

README.Coding adjustments, DEBUG macro modernisation, variable name
sanitizing. No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_nfs4acl_xattr.c | 90 ++++++++++++++++++++-----------------
 1 file changed, 48 insertions(+), 42 deletions(-)

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index fc30f66f1d4..700a15b8151 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -44,8 +44,9 @@ static const struct enum_list nfs4acl_encoding[] = {
 static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 {
 	enum ndr_err_code ndr_err;
-	struct nfs4acl *acl = talloc(mem_ctx, struct nfs4acl);
-	if (!acl) {
+	struct nfs4acl *acl = talloc_zero(mem_ctx, struct nfs4acl);
+
+	if (acl == NULL) {
 		errno = ENOMEM;
 		return NULL;
 	}
@@ -54,8 +55,7 @@ static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 		(ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
 
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-		DEBUG(0, ("ndr_pull_acl_t failed: %s\n",
-			  ndr_errstr(ndr_err)));
+		DBG_ERR("ndr_pull_acl_t failed: %s\n", ndr_errstr(ndr_err));
 		TALLOC_FREE(acl);
 		return NULL;
 	}
@@ -66,12 +66,12 @@ static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
 {
 	enum ndr_err_code ndr_err;
 	DATA_BLOB blob;
+
 	ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
 		(ndr_push_flags_fn_t)ndr_push_nfs4acl);
 
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-		DEBUG(0, ("ndr_push_acl_t failed: %s\n",
-			  ndr_errstr(ndr_err)));
+		DBG_ERR("ndr_push_acl_t failed: %s\n", ndr_errstr(ndr_err));
 		return data_blob_null;
 	}
 	return blob;
@@ -79,26 +79,33 @@ static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
 
 static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
 					 DATA_BLOB *blob,
-					 struct SMB4ACL_T **ppacl)
+					 struct SMB4ACL_T **_smb4acl)
 {
-	int i;
 	struct nfs4acl *nfs4acl = NULL;
-	struct SMB4ACL_T *pacl = NULL;
+	struct SMB4ACL_T *smb4acl = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
+	int i;
+
 	nfs4acl = nfs4acl_blob2acl(blob, frame);
+	if (nfs4acl == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_INTERNAL_ERROR;
+	}
 
-	/* create SMB4ACL data */
-	if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
+	smb4acl = smb_create_smb4acl(mem_ctx);
+	if (smb4acl == NULL) {
 		TALLOC_FREE(frame);
 		return NT_STATUS_NO_MEMORY;
 	}
-	for(i=0; i<nfs4acl->a_count; i++) {
+
+	for (i = 0; i < nfs4acl->a_count; i++) {
 		SMB_ACE4PROP_T aceprop;
 
 		aceprop.aceType  = (uint32_t) nfs4acl->ace[i].e_type;
 		aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
 		aceprop.aceMask  = (uint32_t) nfs4acl->ace[i].e_mask;
 		aceprop.who.id   = (uint32_t) nfs4acl->ace[i].e_id;
+
 		if (!strcmp(nfs4acl->ace[i].e_who,
 			    NFS4ACL_XATTR_OWNER_WHO)) {
 			aceprop.flags = SMB_ACE4_ID_SPECIAL;
@@ -114,13 +121,13 @@ static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
 		} else {
 			aceprop.flags = 0;
 		}
-		if(smb_add_ace4(pacl, &aceprop) == NULL) {
+		if (smb_add_ace4(smb4acl, &aceprop) == NULL) {
 			TALLOC_FREE(frame);
 			return NT_STATUS_NO_MEMORY;
 		}
 	}
 
-	*ppacl = pacl;
+	*_smb4acl = smb4acl;
 	TALLOC_FREE(frame);
 	return NT_STATUS_OK;
 }
@@ -188,17 +195,16 @@ static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle,
 
 static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 				    struct SMB4ACL_T *smbacl,
-				    struct nfs4acl **pnfs4acl,
+				    struct nfs4acl **_nfs4acl,
 				    bool denymissingspecial)
 {
-	struct nfs4acl *nfs4acl;
-	struct SMB4ACE_T *smbace;
+	struct nfs4acl *nfs4acl = NULL;
+	struct SMB4ACE_T *smbace = NULL;
 	bool have_special_id = false;
 	int i;
 
-	/* allocate the field of NFS4 aces */
 	nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
-	if(nfs4acl == NULL) {
+	if (nfs4acl == NULL) {
 		errno = ENOMEM;
 		return false;
 	}
@@ -207,16 +213,16 @@ static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 
 	nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
 					 nfs4acl->a_count);
-	if(nfs4acl->ace == NULL) {
+	if (nfs4acl->ace == NULL) {
 		TALLOC_FREE(nfs4acl);
 		errno = ENOMEM;
 		return false;
 	}
 
-	/* handle all aces */
-	for(smbace = smb_first_ace4(smbacl), i = 0;
-			smbace!=NULL;
-			smbace = smb_next_ace4(smbace), i++) {
+	for (smbace = smb_first_ace4(smbacl), i = 0;
+	     smbace != NULL;
+	     smbace = smb_next_ace4(smbace), i++)
+	{
 		SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
 
 		nfs4acl->ace[i].e_type        = aceprop->aceType;
@@ -238,8 +244,8 @@ static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 					NFS4ACL_XATTR_GROUP_WHO;
 				break;
 			default:
-				DEBUG(8, ("unsupported special_id %d\n", \
-					aceprop->who.special_id));
+				DBG_DEBUG("unsupported special_id %d\n",
+					  aceprop->who.special_id);
 				continue; /* don't add it !!! */
 			}
 			have_special_id = true;
@@ -256,7 +262,7 @@ static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 
 	SMB_ASSERT(i == nfs4acl->a_count);
 
-	*pnfs4acl = nfs4acl;
+	*_nfs4acl = nfs4acl;
 	return true;
 }
 
@@ -284,7 +290,7 @@ static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
 
 	blob = nfs4acl_acl2blob(frame, nfs4acl);
 	if (!blob.data) {
-		DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
+		DBG_ERR("Failed to convert ACL to linear blob for xattr\n");
 		TALLOC_FREE(frame);
 		errno = EINVAL;
 		return false;
@@ -295,7 +301,7 @@ static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
 	ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_NDR_XATTR_NAME,
 				     blob.data, blob.length, 0);
 	if (ret != 0) {
-		DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
+		DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
 	}
 	TALLOC_FREE(frame);
 	return ret == 0;
@@ -348,17 +354,17 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
 				   struct files_struct *fsp,
 				   uint32_t security_info,
 				   TALLOC_CTX *mem_ctx,
-				   struct security_descriptor **ppdesc)
+				   struct security_descriptor **sd)
 {
-	struct SMB4ACL_T *pacl;
-	NTSTATUS status;
+	struct SMB4ACL_T *smb4acl = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
+	NTSTATUS status;
 
-	status = nfs4_fget_nfs4_acl(handle, frame, fsp, &pacl);
+	status = nfs4_fget_nfs4_acl(handle, frame, fsp, &smb4acl);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 		TALLOC_FREE(frame);
 		return nfs4acl_xattr_default_sd(
-			handle, fsp->fsp_name, mem_ctx, ppdesc);
+			handle, fsp->fsp_name, mem_ctx, sd);
 	}
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(frame);
@@ -366,7 +372,7 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
 	}
 
 	status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
-				      ppdesc, pacl);
+				      sd, smb4acl);
 	TALLOC_FREE(frame);
 	return status;
 }
@@ -375,17 +381,17 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
 				  const struct smb_filename *smb_fname,
 				  uint32_t security_info,
 				  TALLOC_CTX *mem_ctx,
-				  struct security_descriptor **ppdesc)
+				  struct security_descriptor **sd)
 {
-	struct SMB4ACL_T *pacl;
-	NTSTATUS status;
+	struct SMB4ACL_T *smb4acl = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
+	NTSTATUS status;
 
-	status = nfs4_get_nfs4_acl(handle, frame, smb_fname, &pacl);
+	status = nfs4_get_nfs4_acl(handle, frame, smb_fname, &smb4acl);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 		TALLOC_FREE(frame);
 		return nfs4acl_xattr_default_sd(
-			handle,	smb_fname, mem_ctx, ppdesc);
+			handle,	smb_fname, mem_ctx, sd);
 	}
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(frame);
@@ -393,8 +399,8 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
 	}
 
 	status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
-				     security_info, mem_ctx, ppdesc,
-				     pacl);
+				     security_info, mem_ctx, sd,
+				     smb4acl);
 	TALLOC_FREE(frame);
 	return status;
 }
-- 
2.13.6


From e54d8c9831791b71c05acf953d2377ff948d95a6 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 23 Oct 2017 16:35:52 +0200
Subject: [PATCH 13/27] vfs_nfs4acl_xattr: refactoring

Refactor the code in preperation of factoring out ACL blob to smb4acl
and vice versa mapping functions.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_nfs4acl_xattr.c | 273 +++++++++++++++++++++++-------------
 1 file changed, 176 insertions(+), 97 deletions(-)

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 700a15b8151..2bc546150e0 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -41,6 +41,64 @@ static const struct enum_list nfs4acl_encoding[] = {
 	{NFS4ACL_ENCODING_XDR, "xdr"},
 };
 
+static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
+				 files_struct *fsp,
+				 const struct smb_filename *smb_fname_in,
+				 TALLOC_CTX *mem_ctx,
+				 DATA_BLOB *blob)
+{
+	struct nfs4acl_config *config = NULL;
+	const struct smb_filename *smb_fname = NULL;
+	size_t allocsize = 256;
+	ssize_t length;
+	bool ok;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	*blob = data_blob_null;
+
+	if (fsp == NULL && smb_fname_in == NULL) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+	smb_fname = smb_fname_in;
+	if (smb_fname == NULL) {
+		smb_fname = fsp->fsp_name;
+	}
+	if (smb_fname == NULL) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	do {
+		allocsize *= 4;
+		ok = data_blob_realloc(mem_ctx, blob, allocsize);
+		if (!ok) {
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		if (fsp != NULL && fsp->fh->fd != -1) {
+			length = SMB_VFS_NEXT_FGETXATTR(handle,
+							fsp,
+							config->xattr_name,
+							blob->data,
+							blob->length);
+		} else {
+			length = SMB_VFS_NEXT_GETXATTR(handle,
+						       smb_fname,
+						       config->xattr_name,
+						       blob->data,
+						       blob->length);
+		}
+	} while (length == -1 && errno == ERANGE && allocsize <= 65536);
+
+	if (length == -1) {
+		return map_nt_error_from_unix(errno);
+	}
+
+	return NT_STATUS_OK;
+}
+
 static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 {
 	enum ndr_err_code ndr_err;
@@ -77,15 +135,21 @@ static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
 	return blob;
 }
 
-static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
-					 DATA_BLOB *blob,
-					 struct SMB4ACL_T **_smb4acl)
+static NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
+				  TALLOC_CTX *mem_ctx,
+				  DATA_BLOB *blob,
+				  struct SMB4ACL_T **_smb4acl)
 {
 	struct nfs4acl *nfs4acl = NULL;
 	struct SMB4ACL_T *smb4acl = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
+	struct nfs4acl_config *config = NULL;
 	int i;
 
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
 	nfs4acl = nfs4acl_blob2acl(blob, frame);
 	if (nfs4acl == NULL) {
 		TALLOC_FREE(frame);
@@ -132,67 +196,6 @@ static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
-/* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
-static NTSTATUS nfs4_fget_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
-				   files_struct *fsp, struct SMB4ACL_T **ppacl)
-{
-	NTSTATUS status;
-	DATA_BLOB blob = data_blob_null;
-	ssize_t length;
-	TALLOC_CTX *frame = talloc_stackframe();
-
-	do {
-		blob.length += 1000;
-		blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
-		if (!blob.data) {
-			TALLOC_FREE(frame);
-			errno = ENOMEM;
-			return NT_STATUS_NO_MEMORY;
-		}
-		length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, NFS4ACL_NDR_XATTR_NAME, blob.data, blob.length);
-		blob.length = length;
-	} while (length == -1 && errno == ERANGE);
-	if (length == -1) {
-		TALLOC_FREE(frame);
-		return map_nt_error_from_unix(errno);
-	}
-	status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl);
-	TALLOC_FREE(frame);
-	return status;
-}
-
-/* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */
-static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle,
-				TALLOC_CTX *mem_ctx,
-				const struct smb_filename *smb_fname,
-				struct SMB4ACL_T **ppacl)
-{
-	NTSTATUS status;
-	DATA_BLOB blob = data_blob_null;
-	ssize_t length;
-	TALLOC_CTX *frame = talloc_stackframe();
-
-	do {
-		blob.length += 1000;
-		blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
-		if (!blob.data) {
-			TALLOC_FREE(frame);
-			errno = ENOMEM;
-			return NT_STATUS_NO_MEMORY;
-		}
-		length = SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
-				NFS4ACL_NDR_XATTR_NAME, blob.data, blob.length);
-		blob.length = length;
-	} while (length == -1 && errno == ERANGE);
-	if (length == -1) {
-		TALLOC_FREE(frame);
-		return map_nt_error_from_unix(errno);
-	}
-	status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl);
-	TALLOC_FREE(frame);
-	return status;
-}
-
 static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 				    struct SMB4ACL_T *smbacl,
 				    struct nfs4acl **_nfs4acl,
@@ -266,45 +269,36 @@ static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 	return true;
 }
 
-/* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
-static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
-				       files_struct *fsp,
-				       struct SMB4ACL_T *smbacl)
+static NTSTATUS nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct *handle,
+					    TALLOC_CTX *mem_ctx,
+					    struct SMB4ACL_T *smb4acl,
+					    DATA_BLOB *_blob)
 {
-	TALLOC_CTX *frame = talloc_stackframe();
-	struct nfs4acl *nfs4acl;
-	int ret;
-	bool denymissingspecial;
+	struct nfs4acl *nfs4acl = NULL;
 	DATA_BLOB blob;
+	bool denymissingspecial;
+	bool ok;
 
-	denymissingspecial = lp_parm_bool(fsp->conn->params->service,
+	denymissingspecial = lp_parm_bool(SNUM(handle->conn),
 					  "nfs4acl_xattr",
 					  "denymissingspecial", false);
 
-	if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
-				     denymissingspecial)) {
-		DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
-		TALLOC_FREE(frame);
-		return false;
+	ok = nfs4acl_smb4acl2nfs4acl(talloc_tos(), smb4acl, &nfs4acl,
+				     denymissingspecial);
+	if (!ok) {
+		DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
+		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	blob = nfs4acl_acl2blob(frame, nfs4acl);
-	if (!blob.data) {
+	blob = nfs4acl_acl2blob(mem_ctx, nfs4acl);
+	TALLOC_FREE(nfs4acl);
+	if (blob.data == NULL) {
 		DBG_ERR("Failed to convert ACL to linear blob for xattr\n");
-		TALLOC_FREE(frame);
-		errno = EINVAL;
-		return false;
-	}
-	if (fsp->fh->fd == -1) {
-		DEBUG(0, ("Error: fsp->fh->fd == -1\n"));
-	}
-	ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_NDR_XATTR_NAME,
-				     blob.data, blob.length, 0);
-	if (ret != 0) {
-		DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
+		return NT_STATUS_INTERNAL_ERROR;
 	}
-	TALLOC_FREE(frame);
-	return ret == 0;
+
+	*_blob = blob;
+	return NT_STATUS_OK;
 }
 
 static NTSTATUS nfs4acl_xattr_default_sd(
@@ -350,6 +344,30 @@ static NTSTATUS nfs4acl_xattr_default_sd(
 					   sd);
 }
 
+static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
+				     DATA_BLOB *blob,
+				     TALLOC_CTX *mem_ctx,
+				     struct SMB4ACL_T **smb4acl)
+{
+	struct nfs4acl_config *config = NULL;
+	NTSTATUS status;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	switch (config->encoding) {
+	case NFS4ACL_ENCODING_NDR:
+		status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
+		break;
+	default:
+		status = NT_STATUS_INTERNAL_ERROR;
+		break;
+	}
+
+	return status;
+}
+
 static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
 				   struct files_struct *fsp,
 				   uint32_t security_info,
@@ -358,9 +376,10 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
 {
 	struct SMB4ACL_T *smb4acl = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
+	DATA_BLOB blob;
 	NTSTATUS status;
 
-	status = nfs4_fget_nfs4_acl(handle, frame, fsp, &smb4acl);
+	status = nfs4acl_get_blob(handle, fsp, NULL, frame, &blob);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 		TALLOC_FREE(frame);
 		return nfs4acl_xattr_default_sd(
@@ -371,6 +390,12 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
 		return status;
 	}
 
+	status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return status;
+	}
+
 	status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
 				      sd, smb4acl);
 	TALLOC_FREE(frame);
@@ -385,9 +410,10 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
 {
 	struct SMB4ACL_T *smb4acl = NULL;
 	TALLOC_CTX *frame = talloc_stackframe();
+	DATA_BLOB blob;
 	NTSTATUS status;
 
-	status = nfs4_get_nfs4_acl(handle, frame, smb_fname, &smb4acl);
+	status = nfs4acl_get_blob(handle, NULL, smb_fname, frame, &blob);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 		TALLOC_FREE(frame);
 		return nfs4acl_xattr_default_sd(
@@ -398,6 +424,12 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
 		return status;
 	}
 
+	status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return status;
+	}
+
 	status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
 				     security_info, mem_ctx, sd,
 				     smb4acl);
@@ -405,13 +437,60 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
 	return status;
 }
 
+static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
+				   files_struct *fsp,
+				   struct SMB4ACL_T *smb4acl)
+{
+	struct nfs4acl_config *config = NULL;
+	DATA_BLOB blob;
+	NTSTATUS status;
+	int ret;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return false);
+
+	switch (config->encoding) {
+	case NFS4ACL_ENCODING_NDR:
+		status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
+						     smb4acl, &blob);
+		break;
+	default:
+		status = NT_STATUS_INTERNAL_ERROR;
+		break;
+	}
+	if (!NT_STATUS_IS_OK(status)) {
+		return false;
+	}
+
+	ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
+				     blob.data, blob.length, 0);
+	data_blob_free(&blob);
+	if (ret != 0) {
+		DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
+		return false;
+	}
+
+	return true;
+}
+
 static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
 			 files_struct *fsp,
 			 uint32_t security_info_sent,
 			 const struct security_descriptor *psd)
 {
-	return smb_set_nt_acl_nfs4(handle, fsp, NULL, security_info_sent,
-				   psd,	nfs4acl_xattr_fset_smb4acl);
+	struct nfs4acl_config *config = NULL;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	return smb_set_nt_acl_nfs4(handle,
+				   fsp,
+				   &config->nfs4_params,
+				   security_info_sent,
+				   psd,
+				   nfs4acl_smb4acl_set_fn);
 }
 
 static int nfs4acl_connect(struct vfs_handle_struct *handle,
-- 
2.13.6


From 233447fabfe889689749e9678cd2809d5d5c0cdb Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 23 Oct 2017 16:38:51 +0200
Subject: [PATCH 14/27] vfs_nfs4acl_xattr: fsp->fh->fd can legally be -1

We only open the underlying file if the open access mode contains

FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail                  |  2 --
 source3/modules/vfs_nfs4acl_xattr.c | 10 ++++++++--
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 030520f7e58..f3c605ba582 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -25,12 +25,10 @@
 ^samba3.raw.acls nfs4acl_xattr-simple.create_owner_file\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple.create_owner_dir\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple.nulldacl\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-simple.generic\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.INHERITFLAGS\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.create_owner_file\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.create_owner_dir\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.nulldacl\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.generic\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.inherit_creator_owner\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special.inherit_creator_group\(nt4_dc\)
 ^samba3.base.delete.deltest16a
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 2bc546150e0..b3b5e497061 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -463,8 +463,14 @@ static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
 		return false;
 	}
 
-	ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
-				     blob.data, blob.length, 0);
+	if (fsp->fh->fd != -1) {
+		ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
+					     blob.data, blob.length, 0);
+	} else {
+		ret = SMB_VFS_NEXT_SETXATTR(handle, fsp->fsp_name,
+					    config->xattr_name,
+					    blob.data, blob.length, 0);
+	}
 	data_blob_free(&blob);
 	if (ret != 0) {
 		DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
-- 
2.13.6


From 6f05a7fb15a9d0d065f6dfac6301001f539a5504 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 17 Oct 2017 12:02:53 +0200
Subject: [PATCH 15/27] vfs_nfs4acl_xattr: move the meat of the implementation
 to a seperate file

This is in preperation of modularizing the storage backend. Currently we
store the NFS4 ACL as an IDL/NDR encoded blob in a xattr.

Later commits will add a different backend storing the NFS4 ACL as an
XDR encoded blob in a xattr.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/nfs4acl_xattr_ndr.c | 241 ++++++++++++++++++++++++++++++++++++
 source3/modules/nfs4acl_xattr_ndr.h |  42 +++++++
 source3/modules/vfs_nfs4acl_xattr.c | 203 +-----------------------------
 source3/modules/wscript_build       |   2 +-
 4 files changed, 285 insertions(+), 203 deletions(-)
 create mode 100644 source3/modules/nfs4acl_xattr_ndr.c
 create mode 100644 source3/modules/nfs4acl_xattr_ndr.h

diff --git a/source3/modules/nfs4acl_xattr_ndr.c b/source3/modules/nfs4acl_xattr_ndr.c
new file mode 100644
index 00000000000..af100184c5f
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_ndr.c
@@ -0,0 +1,241 @@
+/*
+ * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ to NT acls and vice versa.
+ *
+ * Copyright (C) Jiri Sasek, 2007
+ * based on the foobar.c module which is copyrighted by Volker Lendecke
+ * based on pvfs_acl_nfs4.c  Copyright (C) Andrew Tridgell 2006
+ *
+ * based on vfs_fake_acls:
+ * Copyright (C) Tim Potter, 1999-2000
+ * Copyright (C) Alexander Bokovoy, 2002
+ * Copyright (C) Andrew Bartlett, 2002,2012
+ * Copyright (C) Ralph Boehme 2017
+ *
+ * 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/>.
+ *
+ */
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "smbd/smbd.h"
+#include "nfs4_acls.h"
+#include "librpc/gen_ndr/ndr_nfs4acl.h"
+#include "nfs4acl_xattr.h"
+#include "nfs4acl_xattr_ndr.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+{
+	enum ndr_err_code ndr_err;
+	struct nfs4acl *acl = talloc_zero(mem_ctx, struct nfs4acl);
+
+	if (acl == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	ndr_err = ndr_pull_struct_blob(blob, acl, acl,
+		(ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
+
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		DBG_ERR("ndr_pull_acl_t failed: %s\n", ndr_errstr(ndr_err));
+		TALLOC_FREE(acl);
+		return NULL;
+	}
+	return acl;
+}
+
+static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
+{
+	enum ndr_err_code ndr_err;
+	DATA_BLOB blob;
+
+	ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
+		(ndr_push_flags_fn_t)ndr_push_nfs4acl);
+
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		DBG_ERR("ndr_push_acl_t failed: %s\n", ndr_errstr(ndr_err));
+		return data_blob_null;
+	}
+	return blob;
+}
+
+NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
+				  TALLOC_CTX *mem_ctx,
+				  DATA_BLOB *blob,
+				  struct SMB4ACL_T **_smb4acl)
+{
+	struct nfs4acl *nfs4acl = NULL;
+	struct SMB4ACL_T *smb4acl = NULL;
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct nfs4acl_config *config = NULL;
+	int i;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	nfs4acl = nfs4acl_blob2acl(blob, frame);
+	if (nfs4acl == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	smb4acl = smb_create_smb4acl(mem_ctx);
+	if (smb4acl == NULL) {
+		TALLOC_FREE(frame);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	for (i = 0; i < nfs4acl->a_count; i++) {
+		SMB_ACE4PROP_T aceprop;
+
+		aceprop.aceType  = (uint32_t) nfs4acl->ace[i].e_type;
+		aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
+		aceprop.aceMask  = (uint32_t) nfs4acl->ace[i].e_mask;
+		aceprop.who.id   = (uint32_t) nfs4acl->ace[i].e_id;
+
+		if (!strcmp(nfs4acl->ace[i].e_who,
+			    NFS4ACL_XATTR_OWNER_WHO)) {
+			aceprop.flags = SMB_ACE4_ID_SPECIAL;
+			aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
+		} else if (!strcmp(nfs4acl->ace[i].e_who,
+				   NFS4ACL_XATTR_GROUP_WHO)) {
+			aceprop.flags = SMB_ACE4_ID_SPECIAL;
+			aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
+		} else if (!strcmp(nfs4acl->ace[i].e_who,
+				   NFS4ACL_XATTR_EVERYONE_WHO)) {
+			aceprop.flags = SMB_ACE4_ID_SPECIAL;
+			aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
+		} else {
+			aceprop.flags = 0;
+		}
+
+		if (smb_add_ace4(smb4acl, &aceprop) == NULL) {
+			TALLOC_FREE(frame);
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	*_smb4acl = smb4acl;
+	TALLOC_FREE(frame);
+	return NT_STATUS_OK;
+}
+
+static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
+				    struct SMB4ACL_T *smbacl,
+				    struct nfs4acl **_nfs4acl,
+				    bool denymissingspecial)
+{
+	struct nfs4acl *nfs4acl = NULL;
+	struct SMB4ACE_T *smbace = NULL;
+	bool have_special_id = false;
+	int i;
+
+	nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
+	if (nfs4acl == NULL) {
+		errno = ENOMEM;
+		return false;
+	}
+
+	nfs4acl->a_count = smb_get_naces(smbacl);
+
+	nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
+					 nfs4acl->a_count);
+	if (nfs4acl->ace == NULL) {
+		TALLOC_FREE(nfs4acl);
+		errno = ENOMEM;
+		return false;
+	}
+
+	for (smbace = smb_first_ace4(smbacl), i = 0;
+	     smbace != NULL;
+	     smbace = smb_next_ace4(smbace), i++)
+	{
+		SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
+
+		nfs4acl->ace[i].e_type        = aceprop->aceType;
+		nfs4acl->ace[i].e_flags       = aceprop->aceFlags;
+		nfs4acl->ace[i].e_mask        = aceprop->aceMask;
+		nfs4acl->ace[i].e_id          = aceprop->who.id;
+		if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
+			switch(aceprop->who.special_id) {
+			case SMB_ACE4_WHO_EVERYONE:
+				nfs4acl->ace[i].e_who =
+					NFS4ACL_XATTR_EVERYONE_WHO;
+				break;
+			case SMB_ACE4_WHO_OWNER:
+				nfs4acl->ace[i].e_who =
+					NFS4ACL_XATTR_OWNER_WHO;
+				break;
+			case SMB_ACE4_WHO_GROUP:
+				nfs4acl->ace[i].e_who =
+					NFS4ACL_XATTR_GROUP_WHO;
+				break;
+			default:
+				DBG_DEBUG("unsupported special_id %d\n",
+					  aceprop->who.special_id);
+				continue; /* don't add it !!! */
+			}
+			have_special_id = true;
+		} else {
+			nfs4acl->ace[i].e_who = "";
+		}
+	}
+
+	if (!have_special_id && denymissingspecial) {
+		TALLOC_FREE(nfs4acl);
+		errno = EACCES;
+		return false;
+	}
+
+	SMB_ASSERT(i == nfs4acl->a_count);
+
+	*_nfs4acl = nfs4acl;
+	return true;
+}
+
+NTSTATUS nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct *handle,
+				     TALLOC_CTX *mem_ctx,
+				     struct SMB4ACL_T *smb4acl,
+				     DATA_BLOB *_blob)
+{
+	struct nfs4acl *nfs4acl = NULL;
+	DATA_BLOB blob;
+	bool denymissingspecial;
+	bool ok;
+
+	denymissingspecial = lp_parm_bool(SNUM(handle->conn),
+					  "nfs4acl_xattr",
+					  "denymissingspecial", false);
+
+	ok = nfs4acl_smb4acl2nfs4acl(talloc_tos(), smb4acl, &nfs4acl,
+				     denymissingspecial);
+	if (!ok) {
+		DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	blob = nfs4acl_acl2blob(mem_ctx, nfs4acl);
+	TALLOC_FREE(nfs4acl);
+	if (blob.data == NULL) {
+		DBG_ERR("Failed to convert ACL to linear blob for xattr\n");
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	*_blob = blob;
+	return NT_STATUS_OK;
+}
diff --git a/source3/modules/nfs4acl_xattr_ndr.h b/source3/modules/nfs4acl_xattr_ndr.h
new file mode 100644
index 00000000000..7db4ce734f5
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_ndr.h
@@ -0,0 +1,42 @@
+/*
+ * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ to NT acls and vice versa.
+ *
+ * Copyright (C) Jiri Sasek, 2007
+ * based on the foobar.c module which is copyrighted by Volker Lendecke
+ * based on pvfs_acl_nfs4.c  Copyright (C) Andrew Tridgell 2006
+ *
+ * based on vfs_fake_acls:
+ * Copyright (C) Tim Potter, 1999-2000
+ * Copyright (C) Alexander Bokovoy, 2002
+ * Copyright (C) Andrew Bartlett, 2002,2012
+ * Copyright (C) Ralph Boehme 2017
+ *
+ * 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 __NFS4ACL_XATTR_NDR_H__
+#define __NFS4ACL_XATTR_NDR_H__
+
+NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
+				  TALLOC_CTX *mem_ctx,
+				  DATA_BLOB *blob,
+				  struct SMB4ACL_T **_smb4acl);
+
+NTSTATUS nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct *handle,
+				     TALLOC_CTX *mem_ctx,
+				     struct SMB4ACL_T *smbacl,
+				     DATA_BLOB *blob);
+
+#endif /* _VFS_NFS4ACL_XATTR_NDR_H */
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index b3b5e497061..b8ff28b75c0 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -32,6 +32,7 @@
 #include "nfs4_acls.h"
 #include "librpc/gen_ndr/ndr_nfs4acl.h"
 #include "nfs4acl_xattr.h"
+#include "nfs4acl_xattr_ndr.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -99,208 +100,6 @@ static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
 	return NT_STATUS_OK;
 }
 
-static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
-{
-	enum ndr_err_code ndr_err;
-	struct nfs4acl *acl = talloc_zero(mem_ctx, struct nfs4acl);
-
-	if (acl == NULL) {
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	ndr_err = ndr_pull_struct_blob(blob, acl, acl,
-		(ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
-
-	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-		DBG_ERR("ndr_pull_acl_t failed: %s\n", ndr_errstr(ndr_err));
-		TALLOC_FREE(acl);
-		return NULL;
-	}
-	return acl;
-}
-
-static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
-{
-	enum ndr_err_code ndr_err;
-	DATA_BLOB blob;
-
-	ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl,
-		(ndr_push_flags_fn_t)ndr_push_nfs4acl);
-
-	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-		DBG_ERR("ndr_push_acl_t failed: %s\n", ndr_errstr(ndr_err));
-		return data_blob_null;
-	}
-	return blob;
-}
-
-static NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
-				  TALLOC_CTX *mem_ctx,
-				  DATA_BLOB *blob,
-				  struct SMB4ACL_T **_smb4acl)
-{
-	struct nfs4acl *nfs4acl = NULL;
-	struct SMB4ACL_T *smb4acl = NULL;
-	TALLOC_CTX *frame = talloc_stackframe();
-	struct nfs4acl_config *config = NULL;
-	int i;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct nfs4acl_config,
-				return NT_STATUS_INTERNAL_ERROR);
-
-	nfs4acl = nfs4acl_blob2acl(blob, frame);
-	if (nfs4acl == NULL) {
-		TALLOC_FREE(frame);
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	smb4acl = smb_create_smb4acl(mem_ctx);
-	if (smb4acl == NULL) {
-		TALLOC_FREE(frame);
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	for (i = 0; i < nfs4acl->a_count; i++) {
-		SMB_ACE4PROP_T aceprop;
-
-		aceprop.aceType  = (uint32_t) nfs4acl->ace[i].e_type;
-		aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
-		aceprop.aceMask  = (uint32_t) nfs4acl->ace[i].e_mask;
-		aceprop.who.id   = (uint32_t) nfs4acl->ace[i].e_id;
-
-		if (!strcmp(nfs4acl->ace[i].e_who,
-			    NFS4ACL_XATTR_OWNER_WHO)) {
-			aceprop.flags = SMB_ACE4_ID_SPECIAL;
-			aceprop.who.special_id = SMB_ACE4_WHO_OWNER;
-		} else if (!strcmp(nfs4acl->ace[i].e_who,
-				   NFS4ACL_XATTR_GROUP_WHO)) {
-			aceprop.flags = SMB_ACE4_ID_SPECIAL;
-			aceprop.who.special_id = SMB_ACE4_WHO_GROUP;
-		} else if (!strcmp(nfs4acl->ace[i].e_who,
-				   NFS4ACL_XATTR_EVERYONE_WHO)) {
-			aceprop.flags = SMB_ACE4_ID_SPECIAL;
-			aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE;
-		} else {
-			aceprop.flags = 0;
-		}
-		if (smb_add_ace4(smb4acl, &aceprop) == NULL) {
-			TALLOC_FREE(frame);
-			return NT_STATUS_NO_MEMORY;
-		}
-	}
-
-	*_smb4acl = smb4acl;
-	TALLOC_FREE(frame);
-	return NT_STATUS_OK;
-}
-
-static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
-				    struct SMB4ACL_T *smbacl,
-				    struct nfs4acl **_nfs4acl,
-				    bool denymissingspecial)
-{
-	struct nfs4acl *nfs4acl = NULL;
-	struct SMB4ACE_T *smbace = NULL;
-	bool have_special_id = false;
-	int i;
-
-	nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
-	if (nfs4acl == NULL) {
-		errno = ENOMEM;
-		return false;
-	}
-
-	nfs4acl->a_count = smb_get_naces(smbacl);
-
-	nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
-					 nfs4acl->a_count);
-	if (nfs4acl->ace == NULL) {
-		TALLOC_FREE(nfs4acl);
-		errno = ENOMEM;
-		return false;
-	}
-
-	for (smbace = smb_first_ace4(smbacl), i = 0;
-	     smbace != NULL;
-	     smbace = smb_next_ace4(smbace), i++)
-	{
-		SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace);
-
-		nfs4acl->ace[i].e_type        = aceprop->aceType;
-		nfs4acl->ace[i].e_flags       = aceprop->aceFlags;
-		nfs4acl->ace[i].e_mask        = aceprop->aceMask;
-		nfs4acl->ace[i].e_id          = aceprop->who.id;
-		if(aceprop->flags & SMB_ACE4_ID_SPECIAL) {
-			switch(aceprop->who.special_id) {
-			case SMB_ACE4_WHO_EVERYONE:
-				nfs4acl->ace[i].e_who =
-					NFS4ACL_XATTR_EVERYONE_WHO;
-				break;
-			case SMB_ACE4_WHO_OWNER:
-				nfs4acl->ace[i].e_who =
-					NFS4ACL_XATTR_OWNER_WHO;
-				break;
-			case SMB_ACE4_WHO_GROUP:
-				nfs4acl->ace[i].e_who =
-					NFS4ACL_XATTR_GROUP_WHO;
-				break;
-			default:
-				DBG_DEBUG("unsupported special_id %d\n",
-					  aceprop->who.special_id);
-				continue; /* don't add it !!! */
-			}
-			have_special_id = true;
-		} else {
-			nfs4acl->ace[i].e_who = "";
-		}
-	}
-
-	if (!have_special_id && denymissingspecial) {
-		TALLOC_FREE(nfs4acl);
-		errno = EACCES;
-		return false;
-	}
-
-	SMB_ASSERT(i == nfs4acl->a_count);
-
-	*_nfs4acl = nfs4acl;
-	return true;
-}
-
-static NTSTATUS nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct *handle,
-					    TALLOC_CTX *mem_ctx,
-					    struct SMB4ACL_T *smb4acl,
-					    DATA_BLOB *_blob)
-{
-	struct nfs4acl *nfs4acl = NULL;
-	DATA_BLOB blob;
-	bool denymissingspecial;
-	bool ok;
-
-	denymissingspecial = lp_parm_bool(SNUM(handle->conn),
-					  "nfs4acl_xattr",
-					  "denymissingspecial", false);
-
-	ok = nfs4acl_smb4acl2nfs4acl(talloc_tos(), smb4acl, &nfs4acl,
-				     denymissingspecial);
-	if (!ok) {
-		DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	blob = nfs4acl_acl2blob(mem_ctx, nfs4acl);
-	TALLOC_FREE(nfs4acl);
-	if (blob.data == NULL) {
-		DBG_ERR("Failed to convert ACL to linear blob for xattr\n");
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	*_blob = blob;
-	return NT_STATUS_OK;
-}
-
 static NTSTATUS nfs4acl_xattr_default_sd(
 	struct vfs_handle_struct *handle,
 	const struct smb_filename *smb_fname,
diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
index b9f2b9da25c..6943d474826 100644
--- a/source3/modules/wscript_build
+++ b/source3/modules/wscript_build
@@ -219,7 +219,7 @@ bld.SAMBA3_MODULE('vfs_zfsacl',
 
 bld.SAMBA3_MODULE('vfs_nfs4acl_xattr',
                   subsystem='vfs',
-                  source='vfs_nfs4acl_xattr.c',
+                  source='vfs_nfs4acl_xattr.c nfs4acl_xattr_ndr.c',
                   deps='NFS4_ACLS sunacl NDR_NFS4ACL',
                   init_function='',
                   internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_nfs4acl_xattr'),
-- 
2.13.6


From 81211c5d097534482de62ed6cef9eec9ceb48cb0 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 19 Oct 2017 22:44:38 +0200
Subject: [PATCH 16/27] librpc/idl: add NFS 4.1 ACL flags

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 librpc/idl/nfs4acl.idl | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/librpc/idl/nfs4acl.idl b/librpc/idl/nfs4acl.idl
index 1f0cfbf7a04..f836436dc6e 100644
--- a/librpc/idl/nfs4acl.idl
+++ b/librpc/idl/nfs4acl.idl
@@ -23,6 +23,11 @@ interface nfs4acl_interface
 	const uint8 ACL4_XATTR_VERSION_41      = 0x01;
 	const uint8 ACL4_XATTR_VERSION_DEFAULT = ACL4_XATTR_VERSION_40;
 
+	const uint8 ACL4_AUTO_INHERIT  = 0x01;
+	const uint8 ACL4_PROTECTED     = 0x02;
+	const uint8 ACL4_DEFAULTED     = 0x04;
+	const uint8 ACL4_WRITE_THROUGH = 0x40;
+
 	/* these structures use the same bit values and other constants as
 	   in security.idl */
 	typedef [flag(NDR_BIG_ENDIAN)] struct {
-- 
2.13.6


From 9e96b6d7cbd7ba4d9b591b85cd61c0754517d27f Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 19 Oct 2017 15:40:52 +0200
Subject: [PATCH 17/27] vfs_nfs4acl_xattr: add support for NFS 4.1 ACL flags in
 the NDR backend

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/nfs4acl_xattr_ndr.c | 63 +++++++++++++++++++++++++++++++++++--
 source3/modules/vfs_nfs4acl_xattr.c |  3 ++
 2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/source3/modules/nfs4acl_xattr_ndr.c b/source3/modules/nfs4acl_xattr_ndr.c
index af100184c5f..ffa3e69cbb5 100644
--- a/source3/modules/nfs4acl_xattr_ndr.c
+++ b/source3/modules/nfs4acl_xattr_ndr.c
@@ -73,6 +73,23 @@ static DATA_BLOB nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *acl)
 	return blob;
 }
 
+static uint16_t nfs4acl_to_smb4acl_flags(uint8_t nfs4acl_flags)
+{
+	uint16_t smb4acl_flags = SEC_DESC_SELF_RELATIVE;
+
+	if (nfs4acl_flags & ACL4_AUTO_INHERIT) {
+		smb4acl_flags |= SEC_DESC_DACL_AUTO_INHERITED;
+	}
+	if (nfs4acl_flags & ACL4_PROTECTED) {
+		smb4acl_flags |= SEC_DESC_DACL_PROTECTED;
+	}
+	if (nfs4acl_flags & ACL4_DEFAULTED) {
+		smb4acl_flags |= SEC_DESC_DACL_DEFAULTED;
+	}
+
+	return smb4acl_flags;
+}
+
 NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
 				  TALLOC_CTX *mem_ctx,
 				  DATA_BLOB *blob,
@@ -100,6 +117,15 @@ NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
 		return NT_STATUS_NO_MEMORY;
 	}
 
+	if (config->nfs_version > ACL4_XATTR_VERSION_40 &&
+	    nfs4acl->a_version > ACL4_XATTR_VERSION_40)
+	{
+		uint16_t smb4acl_flags;
+
+		smb4acl_flags = nfs4acl_to_smb4acl_flags(nfs4acl->a_flags);
+		smbacl4_set_controlflags(smb4acl, smb4acl_flags);
+	}
+
 	for (i = 0; i < nfs4acl->a_count; i++) {
 		SMB_ACE4PROP_T aceprop;
 
@@ -135,16 +161,39 @@ NTSTATUS nfs4acl_ndr_blob_to_smb4(struct vfs_handle_struct *handle,
 	return NT_STATUS_OK;
 }
 
-static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
+static uint8_t smb4acl_to_nfs4acl_flags(uint16_t smb4acl_flags)
+{
+	uint8_t flags = 0;
+
+	if (smb4acl_flags & SEC_DESC_DACL_AUTO_INHERITED) {
+		flags |= ACL4_AUTO_INHERIT;
+	}
+	if (smb4acl_flags & SEC_DESC_DACL_PROTECTED) {
+		flags |= ACL4_PROTECTED;
+	}
+	if (smb4acl_flags & SEC_DESC_DACL_DEFAULTED) {
+		flags |= ACL4_DEFAULTED;
+	}
+
+	return flags;
+}
+
+static bool nfs4acl_smb4acl2nfs4acl(vfs_handle_struct *handle,
+				    TALLOC_CTX *mem_ctx,
 				    struct SMB4ACL_T *smbacl,
 				    struct nfs4acl **_nfs4acl,
 				    bool denymissingspecial)
 {
+	struct nfs4acl_config *config = NULL;
 	struct nfs4acl *nfs4acl = NULL;
 	struct SMB4ACE_T *smbace = NULL;
 	bool have_special_id = false;
 	int i;
 
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return false);
+
 	nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
 	if (nfs4acl == NULL) {
 		errno = ENOMEM;
@@ -161,6 +210,16 @@ static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
 		return false;
 	}
 
+	nfs4acl->a_version = config->nfs_version;
+	if (nfs4acl->a_version > ACL4_XATTR_VERSION_40) {
+		uint16_t smb4acl_flags;
+		uint8_t flags;
+
+		smb4acl_flags = smbacl4_get_controlflags(smbacl);
+		flags = smb4acl_to_nfs4acl_flags(smb4acl_flags);
+		nfs4acl->a_flags = flags;
+	}
+
 	for (smbace = smb_first_ace4(smbacl), i = 0;
 	     smbace != NULL;
 	     smbace = smb_next_ace4(smbace), i++)
@@ -222,7 +281,7 @@ NTSTATUS nfs4acl_smb4acl_to_ndr_blob(vfs_handle_struct *handle,
 					  "nfs4acl_xattr",
 					  "denymissingspecial", false);
 
-	ok = nfs4acl_smb4acl2nfs4acl(talloc_tos(), smb4acl, &nfs4acl,
+	ok = nfs4acl_smb4acl2nfs4acl(handle, talloc_tos(), smb4acl, &nfs4acl,
 				     denymissingspecial);
 	if (!ok) {
 		DBG_ERR("Failed to convert smb ACL to nfs4 ACL.\n");
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index b8ff28b75c0..e0266d23657 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -355,6 +355,9 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 	case 40:
 		config->nfs_version = ACL4_XATTR_VERSION_40;
 		break;
+	case 41:
+		config->nfs_version = ACL4_XATTR_VERSION_41;
+		break;
 	default:
 		config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
 		break;
-- 
2.13.6


From db82d1315bab1f70049529f308d3ba458b693916 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 23 Oct 2017 13:35:49 +0200
Subject: [PATCH 18/27] selftest: add explicit default NFS4 acl version

This is the current default, just make it explicit. A subsequent commit
will bump the default to 4.1.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail        | 20 ++++++++++----------
 selftest/target/Samba3.pm |  6 ++++--
 source3/selftest/tests.py |  4 ++--
 3 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index f3c605ba582..19c0b6973bd 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -21,16 +21,16 @@
 ^samba3.blackbox.smbclient_machine_auth.plain \(nt4_dc:local\)# the NT4 DC does not currently set up a self-join
 ^samba3.raw.samba3hide.samba3hide\((nt4_dc|ad_dc)\) # This test fails against an smbd environment with NT ACLs enabled
 ^samba3.raw.samba3closeerr.samba3closeerr\(nt4_dc\) # This test fails against an smbd environment with NT ACLs enabled
-^samba3.raw.acls nfs4acl_xattr-simple.INHERITFLAGS\(nt4_dc\) # This (and the follow nfs4acl_xattr tests fail because our NFSv4 backend isn't a complete mapping yet.
-^samba3.raw.acls nfs4acl_xattr-simple.create_owner_file\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-simple.create_owner_dir\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-simple.nulldacl\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.INHERITFLAGS\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.create_owner_file\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.create_owner_dir\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.nulldacl\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.inherit_creator_owner\(nt4_dc\)
-^samba3.raw.acls nfs4acl_xattr-special.inherit_creator_group\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-simple-40.INHERITFLAGS\(nt4_dc\) # This (and the follow nfs4acl_xattr tests fail because our NFSv4 backend isn't a complete mapping yet.
+^samba3.raw.acls nfs4acl_xattr-simple-40.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-simple-40.create_owner_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-simple-40.nulldacl\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-special-40.INHERITFLAGS\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-special-40.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-special-40.create_owner_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-special-40.nulldacl\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-special-40.inherit_creator_owner\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-special-40.inherit_creator_group\(nt4_dc\)
 ^samba3.base.delete.deltest16a
 ^samba3.base.delete.deltest17a
 ^samba3.unix.whoami anonymous connection.whoami\(ad_dc\) # We need to resolve if we should be including SID_NT_WORLD and SID_NT_NETWORK in this token
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index f4d033d0c7a..87191841589 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1862,16 +1862,18 @@ sub provision($$$$$$$$$)
 [lp]
 	copy = print1
 
-[nfs4acl_simple]
+[nfs4acl_simple_40]
 	path = $shrdir
 	comment = smb username is [%U]
 	nfs4:mode = simple
+	nfs4acl_xattr:version = 40
 	vfs objects = nfs4acl_xattr xattr_tdb
 
-[nfs4acl_special]
+[nfs4acl_special_40]
 	path = $shrdir
 	comment = smb username is [%U]
 	nfs4:mode = special
+	nfs4acl_xattr:version = 40
 	vfs objects = nfs4acl_xattr xattr_tdb
 
 [xcopy_share]
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index c1e08d56731..bee4315845a 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -461,8 +461,8 @@ for t in tests:
         plantestsuite(t, "ad_member_idmap_ad", [os.path.join(samba3srcdir, "../nsswitch/tests/test_idmap_ad.sh"), '$DOMAIN', '$DC_SERVER', '$DC_PASSWORD'])
     elif t == "raw.acls":
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
-        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple')
-        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_special -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-special')
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-40')
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_special_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-special-40')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/tmpcase -U$USERNAME%$PASSWORD')
     elif t == "smb2.ioctl":
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/fs_specific -U$USERNAME%$PASSWORD', 'fs_specific')
-- 
2.13.6


From cc537cda8188eb736976b247dc2ed16ed30cd126 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 2 Nov 2017 12:45:48 +0100
Subject: [PATCH 19/27] nfs4acls: update default NFS4 ACL version to 4.1

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 librpc/idl/nfs4acl.idl              | 2 +-
 source3/modules/vfs_nfs4acl_xattr.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/librpc/idl/nfs4acl.idl b/librpc/idl/nfs4acl.idl
index f836436dc6e..10a60ed1caf 100644
--- a/librpc/idl/nfs4acl.idl
+++ b/librpc/idl/nfs4acl.idl
@@ -21,7 +21,7 @@ interface nfs4acl_interface
 
 	const uint8 ACL4_XATTR_VERSION_40      = 0x00;
 	const uint8 ACL4_XATTR_VERSION_41      = 0x01;
-	const uint8 ACL4_XATTR_VERSION_DEFAULT = ACL4_XATTR_VERSION_40;
+	const uint8 ACL4_XATTR_VERSION_DEFAULT = ACL4_XATTR_VERSION_41;
 
 	const uint8 ACL4_AUTO_INHERIT  = 0x01;
 	const uint8 ACL4_PROTECTED     = 0x02;
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index e0266d23657..31b85aea13f 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -350,7 +350,7 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 	nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
 					    "nfs4acl_xattr",
 					    "version",
-					    40);
+					    41);
 	switch (nfs_version) {
 	case 40:
 		config->nfs_version = ACL4_XATTR_VERSION_40;
-- 
2.13.6


From aa4f2d1256bf645db7dc198c611095b9ed80de9c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 23 Oct 2017 14:05:19 +0200
Subject: [PATCH 20/27] selftest: test vfs_nfs4acl_xattr with NFS 4.1 ACLs

Only tests with "nfs4:mode = simple" as mode special is supposed to be
broken anyway and simple is recommended.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail        | 3 +++
 selftest/target/Samba3.pm | 6 ++++++
 source3/selftest/tests.py | 1 +
 3 files changed, 10 insertions(+)

diff --git a/selftest/knownfail b/selftest/knownfail
index 19c0b6973bd..36c1697f9a4 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -25,6 +25,9 @@
 ^samba3.raw.acls nfs4acl_xattr-simple-40.create_owner_file\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple-40.create_owner_dir\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-simple-40.nulldacl\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-simple-41.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-simple-41.create_owner_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-simple-41.nulldacl\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special-40.INHERITFLAGS\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special-40.create_owner_file\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special-40.create_owner_dir\(nt4_dc\)
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 87191841589..57db4fa1c60 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1876,6 +1876,12 @@ sub provision($$$$$$$$$)
 	nfs4acl_xattr:version = 40
 	vfs objects = nfs4acl_xattr xattr_tdb
 
+[nfs4acl_simple_41]
+	path = $shrdir
+	comment = smb username is [%U]
+	nfs4:mode = simple
+	vfs objects = nfs4acl_xattr xattr_tdb
+
 [xcopy_share]
 	path = $shrdir
 	comment = smb username is [%U]
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index bee4315845a..4dc7f753fb5 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -463,6 +463,7 @@ for t in tests:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-40')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_special_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-special-40')
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-41')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/tmpcase -U$USERNAME%$PASSWORD')
     elif t == "smb2.ioctl":
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/fs_specific -U$USERNAME%$PASSWORD', 'fs_specific')
-- 
2.13.6


From 720f948a49eb11a126d455cb42d6ab6a13f641e7 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 23 Oct 2017 14:15:12 +0200
Subject: [PATCH 21/27] vfs_nfs4acl_xattr: do xattr ops as root

This ensures we can always fetch the ACL xattr blob when we wanted,
unrestricted of filesystem permissions or Linux xattr security namespace
restrictions.

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

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 31b85aea13f..2515d0c7987 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -72,12 +72,15 @@ static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
 	}
 
 	do {
+		int saved_errno = 0;
+
 		allocsize *= 4;
 		ok = data_blob_realloc(mem_ctx, blob, allocsize);
 		if (!ok) {
 			return NT_STATUS_NO_MEMORY;
 		}
 
+		become_root();
 		if (fsp != NULL && fsp->fh->fd != -1) {
 			length = SMB_VFS_NEXT_FGETXATTR(handle,
 							fsp,
@@ -91,6 +94,13 @@ static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
 						       blob->data,
 						       blob->length);
 		}
+		if (length == -1) {
+			saved_errno = errno;
+		}
+		unbecome_root();
+		if (saved_errno != 0) {
+			errno = saved_errno;
+		}
 	} while (length == -1 && errno == ERANGE && allocsize <= 65536);
 
 	if (length == -1) {
@@ -243,6 +253,7 @@ static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
 	struct nfs4acl_config *config = NULL;
 	DATA_BLOB blob;
 	NTSTATUS status;
+	int saved_errno = 0;
 	int ret;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
@@ -262,6 +273,7 @@ static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
 		return false;
 	}
 
+	become_root();
 	if (fsp->fh->fd != -1) {
 		ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
 					     blob.data, blob.length, 0);
@@ -270,7 +282,14 @@ static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
 					    config->xattr_name,
 					    blob.data, blob.length, 0);
 	}
+	if (ret != 0) {
+		saved_errno = errno;
+	}
+	unbecome_root();
 	data_blob_free(&blob);
+	if (saved_errno != 0) {
+		errno = saved_errno;
+	}
 	if (ret != 0) {
 		DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
 		return false;
-- 
2.13.6


From ccca7b7eb74ca2c677186d51d7580f5386b289e4 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 18 Oct 2017 20:45:05 +0200
Subject: [PATCH 22/27] vfs_nfs4acl_xattr: add POSIX mode check and reset

The vfs_nfs4acl_xattr VFS module is supposed to work the same as
vfs_acl_xattr|tdb with "ignore system acls" set to true. That is,
filesystem permissions should never restrict access and the actual
access checks are done by smbd in userspace.

To better cope with POSIX mode changes via other protocols (eg NFS) or
local filesystem access, add the following tweaks:

o validate ACL blob: if POSIX mode is not 0777/0666 discard the ACL blob
  from the xattr and synthesize a default ACL based on the POSIX mode

o when setting an ACL, check and reset POSIX mode to 0777/0666

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/vfs_nfs4acl_xattr.c | 118 ++++++++++++++++++++++++++++++++++--
 1 file changed, 112 insertions(+), 6 deletions(-)

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 2515d0c7987..9c0c87f6331 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -29,6 +29,7 @@
 #include "includes.h"
 #include "system/filesys.h"
 #include "smbd/smbd.h"
+#include "libcli/security/security_token.h"
 #include "nfs4_acls.h"
 #include "librpc/gen_ndr/ndr_nfs4acl.h"
 #include "nfs4acl_xattr.h"
@@ -42,6 +43,55 @@ static const struct enum_list nfs4acl_encoding[] = {
 	{NFS4ACL_ENCODING_XDR, "xdr"},
 };
 
+/*
+ * Check if someone changed the POSIX mode, for files we expect 0666, for
+ * directories 0777. Discard the ACL blob if the mode is different.
+ */
+static bool nfs4acl_validate_blob(vfs_handle_struct *handle,
+				  const struct smb_filename *smb_fname)
+{
+	struct nfs4acl_config *config = NULL;
+	mode_t expected_mode;
+	int saved_errno = 0;
+	int ret;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return false);
+
+	if (!VALID_STAT(smb_fname->st)) {
+		/* might be a create */
+		return true;
+	}
+
+	if (S_ISDIR(smb_fname->st.st_ex_mode)) {
+		expected_mode = 0777;
+	} else {
+		expected_mode = 0666;
+	}
+	if ((smb_fname->st.st_ex_mode & expected_mode) == expected_mode) {
+		return true;
+	}
+
+	become_root();
+	ret = SMB_VFS_NEXT_REMOVEXATTR(handle,
+				       smb_fname,
+				       config->xattr_name);
+	if (ret != 0) {
+		saved_errno = errno;
+	}
+	unbecome_root();
+	if (saved_errno != 0) {
+		errno = saved_errno;
+	}
+	if (ret != 0 && errno != ENOATTR) {
+		DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno));
+		return false;
+	}
+
+	return true;
+}
+
 static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
 				 files_struct *fsp,
 				 const struct smb_filename *smb_fname_in,
@@ -71,6 +121,11 @@ static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
+	ok = nfs4acl_validate_blob(handle, smb_fname);
+	if (!ok) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
 	do {
 		int saved_errno = 0;
 
@@ -304,17 +359,68 @@ static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
 			 const struct security_descriptor *psd)
 {
 	struct nfs4acl_config *config = NULL;
+	mode_t existing_mode;
+	mode_t expected_mode;
+	mode_t restored_mode;
+	NTSTATUS status;
+	int ret;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct nfs4acl_config,
 				return NT_STATUS_INTERNAL_ERROR);
 
-	return smb_set_nt_acl_nfs4(handle,
-				   fsp,
-				   &config->nfs4_params,
-				   security_info_sent,
-				   psd,
-				   nfs4acl_smb4acl_set_fn);
+	if (!VALID_STAT(fsp->fsp_name->st)) {
+		DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	existing_mode = fsp->fsp_name->st.st_ex_mode;
+	if (S_ISDIR(existing_mode)) {
+		expected_mode = 0777;
+	} else {
+		expected_mode = 0666;
+	}
+	if ((existing_mode & expected_mode) != expected_mode) {
+		int saved_errno = 0;
+
+		restored_mode = existing_mode | expected_mode;
+
+		become_root();
+		if (fsp->fh->fd != -1) {
+			ret = SMB_VFS_NEXT_FCHMOD(handle,
+						  fsp,
+						  restored_mode);
+		} else {
+			ret = SMB_VFS_NEXT_CHMOD(handle,
+						 fsp->fsp_name,
+						 restored_mode);
+		}
+		if (ret != 0) {
+			saved_errno = errno;
+		}
+		unbecome_root();
+		if (saved_errno != 0) {
+			errno = saved_errno;
+		}
+		if (ret != 0) {
+			DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
+				fsp_str_dbg(fsp), existing_mode,
+				strerror(errno));
+			return map_nt_error_from_unix(errno);
+		}
+	}
+
+	status = smb_set_nt_acl_nfs4(handle,
+				     fsp,
+				     &config->nfs4_params,
+				     security_info_sent,
+				     psd,
+				     nfs4acl_smb4acl_set_fn);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	return NT_STATUS_OK;
 }
 
 static int nfs4acl_connect(struct vfs_handle_struct *handle,
-- 
2.13.6


From b801054087ee28a4c6d506ce0b781ae0a8095745 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 23 Oct 2017 12:46:07 +0200
Subject: [PATCH 23/27] vfs_nfs4acl_xattr: implement take-ownership as in
 vfs_acl_common

This allows take-ownership to work if the user has SEC_STD_WRITE_OWNER.

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

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 9c0c87f6331..d4f4d47635e 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -359,9 +359,11 @@ static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
 			 const struct security_descriptor *psd)
 {
 	struct nfs4acl_config *config = NULL;
+	const struct security_token *token = NULL;
 	mode_t existing_mode;
 	mode_t expected_mode;
 	mode_t restored_mode;
+	bool chown_needed = false;
 	NTSTATUS status;
 	int ret;
 
@@ -416,11 +418,58 @@ static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
 				     security_info_sent,
 				     psd,
 				     nfs4acl_smb4acl_set_fn);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	if (NT_STATUS_IS_OK(status)) {
+		return NT_STATUS_OK;
 	}
 
-	return NT_STATUS_OK;
+	/*
+	 * We got access denied. If we're already root, or we didn't
+	 * need to do a chown, or the fsp isn't open with WRITE_OWNER
+	 * access, just return.
+	 */
+
+	if ((security_info_sent & SECINFO_OWNER) &&
+	    (psd->owner_sid != NULL))
+	{
+		chown_needed = true;
+	}
+	if ((security_info_sent & SECINFO_GROUP) &&
+	    (psd->group_sid != NULL))
+	{
+		chown_needed = true;
+	}
+
+	if (get_current_uid(handle->conn) == 0 ||
+	    chown_needed == false ||
+	    !(fsp->access_mask & SEC_STD_WRITE_OWNER))
+	{
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	/*
+	 * Only allow take-ownership, not give-ownership. That's the way Windows
+	 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
+	 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
+	 * objectstore, as determined in an implementation specific manner, the
+	 * object store MUST return STATUS_INVALID_OWNER.
+	 */
+	token = get_current_nttok(fsp->conn);
+	if (!security_token_is_sid(token, psd->owner_sid)) {
+		return NT_STATUS_INVALID_OWNER;
+	}
+
+	DBG_DEBUG("overriding chown on file %s for sid %s\n",
+		  fsp_str_dbg(fsp), sid_string_tos(psd->owner_sid));
+
+	become_root();
+	status = smb_set_nt_acl_nfs4(handle,
+				     fsp,
+				     &config->nfs4_params,
+				     security_info_sent,
+				     psd,
+				     nfs4acl_smb4acl_set_fn);
+	unbecome_root();
+	return status;
 }
 
 static int nfs4acl_connect(struct vfs_handle_struct *handle,
-- 
2.13.6


From 54812394969518a182b55033eed5418b4e439493 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 18 Oct 2017 20:48:37 +0200
Subject: [PATCH 24/27] vfs_nfs4acl_xattr: add XDR backend

Add a NFS4 ACL backend that stores the ACL blob in an XDR encoded xattr,
by default in "security.nfs4acl_xdr".

This backend is enabled by setting "nfs4acl_xattr:encoding = xdr" in a
share definition.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/nfs41acl.x          |  94 ++++++++
 source3/modules/nfs4acl_xattr_xdr.c | 421 ++++++++++++++++++++++++++++++++++++
 source3/modules/nfs4acl_xattr_xdr.h |  35 +++
 source3/modules/vfs_nfs4acl_xattr.c |  11 +
 source3/modules/wscript_build       |  23 +-
 source3/wscript                     |   2 +
 6 files changed, 585 insertions(+), 1 deletion(-)
 create mode 100644 source3/modules/nfs41acl.x
 create mode 100644 source3/modules/nfs4acl_xattr_xdr.c
 create mode 100644 source3/modules/nfs4acl_xattr_xdr.h

diff --git a/source3/modules/nfs41acl.x b/source3/modules/nfs41acl.x
new file mode 100644
index 00000000000..9cfbd9f3074
--- /dev/null
+++ b/source3/modules/nfs41acl.x
@@ -0,0 +1,94 @@
+typedef opaque utf8string<>;
+typedef utf8string utf8str_mixed;
+
+const ACE4_ACCESS_ALLOWED_ACE_TYPE      = 0x00000000;
+const ACE4_ACCESS_DENIED_ACE_TYPE       = 0x00000001;
+const ACE4_SYSTEM_AUDIT_ACE_TYPE        = 0x00000002;
+const ACE4_SYSTEM_ALARM_ACE_TYPE        = 0x00000003;
+
+typedef u_int acetype4;
+
+const ACE4_FILE_INHERIT_ACE             = 0x00000001;
+const ACE4_DIRECTORY_INHERIT_ACE        = 0x00000002;
+const ACE4_NO_PROPAGATE_INHERIT_ACE     = 0x00000004;
+const ACE4_INHERIT_ONLY_ACE             = 0x00000008;
+const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG   = 0x00000010;
+const ACE4_FAILED_ACCESS_ACE_FLAG       = 0x00000020;
+const ACE4_IDENTIFIER_GROUP             = 0x00000040;
+const ACE4_INHERITED_ACE                = 0x00000080;
+
+typedef u_int aceflag4;
+
+/*
+ * The following aceiflag4 is extensions for RFC 5661 that deals with storing
+ * identifiers as numerical ids instead UTF8 strings in order to avoid wasting
+ * CPU cycles for the costly conversion.
+ *
+ * Placed in a seperate field to avoid ever running into conflicts with newly
+ * defined NFSv4 flags.
+ */
+
+const ACEI4_SPECIAL_WHO                  = 0x00000001;
+
+typedef u_int aceiflag4;
+
+/*
+ * Numerical representation of special identifiers from 6.2.1.5.
+ * ACEI4_SPECIAL_WHO MUST be set in nfsace4.aceiflag4.
+ */
+const ACE4_SPECIAL_OWNER                = 1;
+const ACE4_SPECIAL_GROUP                = 2;
+const ACE4_SPECIAL_EVERYONE             = 3;
+const ACE4_SPECIAL_INTERACTIVE          = 4;
+const ACE4_SPECIAL_NETWORK              = 5;
+const ACE4_SPECIAL_DIALUP               = 6;
+const ACE4_SPECIAL_BATCH                = 7;
+const ACE4_SPECIAL_ANONYMOUS            = 8;
+const ACE4_SPECIAL_AUTHENTICATED        = 9;
+const ACE4_SPECIAL_SERVICE              = 10;
+
+const ACE4_READ_DATA            = 0x00000001;
+const ACE4_LIST_DIRECTORY       = 0x00000001;
+const ACE4_WRITE_DATA           = 0x00000002;
+const ACE4_ADD_FILE             = 0x00000002;
+const ACE4_APPEND_DATA          = 0x00000004;
+const ACE4_ADD_SUBDIRECTORY     = 0x00000004;
+const ACE4_READ_NAMED_ATTRS     = 0x00000008;
+const ACE4_WRITE_NAMED_ATTRS    = 0x00000010;
+const ACE4_EXECUTE              = 0x00000020;
+const ACE4_DELETE_CHILD         = 0x00000040;
+const ACE4_READ_ATTRIBUTES      = 0x00000080;
+const ACE4_WRITE_ATTRIBUTES     = 0x00000100;
+const ACE4_WRITE_RETENTION      = 0x00000200;
+const ACE4_WRITE_RETENTION_HOLD = 0x00000400;
+
+const ACE4_DELETE               = 0x00010000;
+const ACE4_READ_ACL             = 0x00020000;
+const ACE4_WRITE_ACL            = 0x00040000;
+const ACE4_WRITE_OWNER          = 0x00080000;
+const ACE4_SYNCHRONIZE          = 0x00100000;
+
+typedef u_int acemask4;
+
+struct nfsace4 {
+        acetype4        type;
+        aceflag4        flag;
+        aceiflag4       iflag;
+        acemask4        access_mask;
+        u_int           who;
+};
+
+const ACL4_XATTR_VERSION_40      = 0;
+const ACL4_XATTR_VERSION_41      = 1;
+const ACL4_XATTR_VERSION_DEFAULT = ACL4_XATTR_VERSION_40;
+
+const ACL4_AUTO_INHERIT         = 0x00000001;
+const ACL4_PROTECTED            = 0x00000002;
+const ACL4_DEFAULTED            = 0x00000004;
+
+typedef u_int aclflag4;
+
+struct nfsacl41 {
+        aclflag4        na41_flag;
+        nfsace4         na41_aces<>;
+};
diff --git a/source3/modules/nfs4acl_xattr_xdr.c b/source3/modules/nfs4acl_xattr_xdr.c
new file mode 100644
index 00000000000..ae770911dbb
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_xdr.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) Ralph Boehme 2017
+ *
+ * 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/>.
+ *
+ */
+
+#include "includes.h"
+#include "smbd/proto.h"
+#include "libcli/security/security_descriptor.h"
+#include "libcli/security/security_token.h"
+#include "nfs4_acls.h"
+#include "nfs4acl_xattr.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+#ifdef HAVE_RPC_XDR_H
+#include <rpc/xdr.h>
+#include "nfs41acl.h"
+#include "nfs4acl_xattr_xdr.h"
+
+static unsigned nfs4acl_get_naces(nfsacl41 *nacl)
+{
+	return nacl->na41_aces.na41_aces_len;
+}
+
+static void nfs4acl_set_naces(nfsacl41 *nacl, unsigned naces)
+{
+	nacl->na41_aces.na41_aces_len = naces;
+}
+
+static unsigned nfs4acl_get_flags(nfsacl41 *nacl)
+{
+	return nacl->na41_flag;
+}
+
+static void nfs4acl_set_flags(nfsacl41 *nacl, unsigned flags)
+{
+	nacl->na41_flag = flags;
+}
+
+static size_t nfs4acl_get_xdrblob_size(nfsacl41 *nacl)
+{
+	size_t acl_size;
+	size_t aces_size;
+	unsigned naces = nfs4acl_get_naces(nacl);
+
+	acl_size = sizeof(aclflag4) + sizeof(unsigned);
+
+	if (naces > NFS4ACL_XDR_MAX_ACES) {
+		DBG_ERR("Too many ACEs: %u", naces);
+		return 0;
+	}
+
+	aces_size = naces * sizeof(struct nfsace4);
+	if (acl_size + aces_size < acl_size) {
+		return 0;
+	}
+	acl_size += aces_size;
+
+	return acl_size;
+}
+
+static size_t nfs4acl_get_xdrblob_naces(size_t _blobsize)
+{
+	size_t blobsize = _blobsize;
+
+	blobsize -= sizeof(aclflag4);
+	blobsize -= sizeof(unsigned);
+	if (blobsize > _blobsize) {
+		return 0;
+	}
+	return (blobsize / sizeof(struct nfsace4));
+}
+
+static nfsacl41 *nfs4acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
+{
+	size_t acl_size = sizeof(nfsacl41) + (naces * sizeof(struct nfsace4));
+	nfsacl41 *nacl = NULL;
+
+	if (naces > NFS4ACL_XDR_MAX_ACES) {
+		DBG_ERR("Too many ACEs: %d\n", naces);
+		return NULL;
+	}
+
+	nacl = talloc_zero_size(mem_ctx, acl_size);
+	if (nacl == NULL) {
+		DBG_ERR("talloc_zero_size failed\n");
+		return NULL;
+	}
+
+	nfs4acl_set_naces(nacl, naces);
+	nacl->na41_aces.na41_aces_val =
+		(nfsace4 *)((char *)nacl + sizeof(nfsacl41));
+
+	return nacl;
+}
+
+static nfsace4 *nfs4acl_get_ace(nfsacl41 *nacl, size_t n)
+{
+	return &nacl->na41_aces.na41_aces_val[n];
+}
+
+static unsigned smb4acl_to_nfs4acl_flags(uint16_t smb4acl_flags)
+{
+	unsigned nfs4acl_flags = 0;
+
+	if (smb4acl_flags & SEC_DESC_DACL_AUTO_INHERITED) {
+		nfs4acl_flags |= ACL4_AUTO_INHERIT;
+	}
+	if (smb4acl_flags & SEC_DESC_DACL_PROTECTED) {
+		nfs4acl_flags |= ACL4_PROTECTED;
+	}
+	if (smb4acl_flags & SEC_DESC_DACL_DEFAULTED) {
+		nfs4acl_flags |= ACL4_DEFAULTED;
+	}
+
+	return nfs4acl_flags;
+}
+
+static bool smb4acl_to_nfs4acl(vfs_handle_struct *handle,
+			       TALLOC_CTX *mem_ctx,
+			       struct SMB4ACL_T *smb4acl,
+			       nfsacl41 **_nacl)
+{
+	struct nfs4acl_config *config = NULL;
+	struct SMB4ACE_T *smb4ace = NULL;
+	size_t smb4naces;
+	nfsacl41 *nacl = NULL;
+	uint16_t smb4acl_flags;
+	unsigned nacl_flags;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return false);
+
+	smb4naces = smb_get_naces(smb4acl);
+	nacl = nfs4acl_alloc(mem_ctx, smb4naces);
+	nfs4acl_set_naces(nacl, 0);
+
+	if (config->nfs_version > ACL4_XATTR_VERSION_40) {
+		smb4acl_flags = smbacl4_get_controlflags(smb4acl);
+		nacl_flags = smb4acl_to_nfs4acl_flags(smb4acl_flags);
+		nfs4acl_set_flags(nacl, nacl_flags);
+	}
+
+	smb4ace = smb_first_ace4(smb4acl);
+	while (smb4ace != NULL) {
+		SMB_ACE4PROP_T *ace4prop = smb_get_ace4(smb4ace);
+		size_t nace_count = nfs4acl_get_naces(nacl);
+		nfsace4 *nace = nfs4acl_get_ace(nacl, nace_count);
+
+		nace->type = ace4prop->aceType;
+		nace->flag = ace4prop->aceFlags;
+		nace->access_mask = ace4prop->aceMask;
+
+		if (ace4prop->flags & SMB_ACE4_ID_SPECIAL) {
+			nace->iflag |= ACEI4_SPECIAL_WHO;
+
+			switch (ace4prop->who.special_id) {
+			case SMB_ACE4_WHO_OWNER:
+				nace->who = ACE4_SPECIAL_OWNER;
+				break;
+
+			case SMB_ACE4_WHO_GROUP:
+				nace->who = ACE4_SPECIAL_GROUP;
+				break;
+
+			case SMB_ACE4_WHO_EVERYONE:
+				nace->who = ACE4_SPECIAL_EVERYONE;
+				break;
+
+			default:
+				DBG_ERR("Unsupported special id [%d]\n",
+					ace4prop->who.special_id);
+				continue;
+			}
+		} else {
+			if (ace4prop->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
+				nace->flag |= ACE4_IDENTIFIER_GROUP;
+				nace->who = ace4prop->who.gid;
+			} else {
+				nace->who = ace4prop->who.uid;
+			}
+		}
+
+		nace_count++;
+		nfs4acl_set_naces(nacl, nace_count);
+		smb4ace = smb_next_ace4(smb4ace);
+	}
+
+	*_nacl = nacl;
+	return true;
+}
+
+NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
+				     TALLOC_CTX *mem_ctx,
+				     struct SMB4ACL_T *smb4acl,
+				     DATA_BLOB *_blob)
+{
+	nfsacl41 *nacl = NULL;
+	XDR xdr = {0};
+	size_t aclblobsize;
+	DATA_BLOB blob;
+	bool ok;
+
+	ok = smb4acl_to_nfs4acl(handle, talloc_tos(), smb4acl, &nacl);
+	if (!ok) {
+		DBG_ERR("smb4acl_to_nfs4acl failed\n");
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	aclblobsize = nfs4acl_get_xdrblob_size(nacl);
+	if (aclblobsize == 0) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	blob = data_blob_talloc(mem_ctx, NULL, aclblobsize);
+	if (blob.data == NULL) {
+		TALLOC_FREE(nacl);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	xdrmem_create(&xdr, (char *)blob.data, blob.length, XDR_ENCODE);
+
+	ok = xdr_nfsacl41(&xdr, nacl);
+	TALLOC_FREE(nacl);
+	if (!ok) {
+		DBG_ERR("xdr_nfs4acl41 failed\n");
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	*_blob = blob;
+	return NT_STATUS_OK;
+}
+
+static uint16_t nfs4acl_to_smb4acl_flags(unsigned nfsacl41_flags)
+{
+	uint16_t smb4acl_flags = SEC_DESC_SELF_RELATIVE;
+
+	if (nfsacl41_flags & ACL4_AUTO_INHERIT) {
+		smb4acl_flags |= SEC_DESC_DACL_AUTO_INHERITED;
+	}
+	if (nfsacl41_flags & ACL4_PROTECTED) {
+		smb4acl_flags |= SEC_DESC_DACL_PROTECTED;
+	}
+	if (nfsacl41_flags & ACL4_DEFAULTED) {
+		smb4acl_flags |= SEC_DESC_DACL_DEFAULTED;
+	}
+
+	return smb4acl_flags;
+}
+
+static NTSTATUS nfs4acl_xdr_blob_to_nfs4acl(struct vfs_handle_struct *handle,
+					    TALLOC_CTX *mem_ctx,
+					    DATA_BLOB *blob,
+					    nfsacl41 **_nacl)
+{
+	struct nfs4acl_config *config = NULL;
+	nfsacl41 *nacl = NULL;
+	size_t naces;
+	XDR xdr = {0};
+	bool ok;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	naces = nfs4acl_get_xdrblob_naces(blob->length);
+	nacl = nfs4acl_alloc(mem_ctx, naces);
+
+	xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
+
+	ok = xdr_nfsacl41(&xdr, nacl);
+	if (!ok) {
+		DBG_ERR("xdr_nfs4acl41 failed\n");
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	if (config->nfs_version == ACL4_XATTR_VERSION_40) {
+		nacl->na41_flag = 0;
+	}
+
+	*_nacl = nacl;
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS nfs4acl_to_smb4acl(struct vfs_handle_struct *handle,
+				   TALLOC_CTX *mem_ctx,
+				   nfsacl41 *nacl,
+				   struct SMB4ACL_T **_smb4acl)
+{
+	struct nfs4acl_config *config = NULL;
+	struct SMB4ACL_T *smb4acl = NULL;
+	unsigned nfsacl41_flag;
+	uint16_t smb4acl_flags;
+	unsigned naces = nfs4acl_get_naces(nacl);
+	int i;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	smb4acl = smb_create_smb4acl(mem_ctx);
+	if (smb4acl == NULL) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	if (config->nfs_version > ACL4_XATTR_VERSION_40) {
+		nfsacl41_flag = nfs4acl_get_flags(nacl);
+		smb4acl_flags = nfs4acl_to_smb4acl_flags(nfsacl41_flag);
+		smbacl4_set_controlflags(smb4acl, smb4acl_flags);
+	}
+
+	DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces);
+
+	for (i = 0; i < naces; i++) {
+		nfsace4 *nace = nfs4acl_get_ace(nacl, i);
+		SMB_ACE4PROP_T smbace = { 0 };
+
+		DBG_DEBUG("type [%d] iflag [%x] flag [%x] mask [%x] who [%d]\n",
+			  nace->type, nace->iflag, nace->flag,
+			  nace->access_mask, nace->who);
+
+		smbace.aceType = nace->type;
+		smbace.aceFlags = nace->flag;
+		smbace.aceMask = nace->access_mask;
+
+		if (nace->iflag & ACEI4_SPECIAL_WHO) {
+			smbace.flags |= SMB_ACE4_ID_SPECIAL;
+
+			switch (nace->who) {
+			case ACE4_SPECIAL_OWNER:
+				smbace.who.special_id = SMB_ACE4_WHO_OWNER;
+				break;
+
+			case ACE4_SPECIAL_GROUP:
+				smbace.who.special_id = SMB_ACE4_WHO_GROUP;
+				break;
+
+			case ACE4_SPECIAL_EVERYONE:
+				smbace.who.special_id = SMB_ACE4_WHO_EVERYONE;
+				break;
+
+			default:
+				DBG_ERR("Unknown special id [%d]\n", nace->who);
+				continue;
+			}
+		} else {
+			if (nace->flag & ACE4_IDENTIFIER_GROUP) {
+				smbace.who.gid = nace->who;
+			} else {
+				smbace.who.uid = nace->who;
+			}
+		}
+
+		smb_add_ace4(smb4acl, &smbace);
+	}
+
+	*_smb4acl = smb4acl;
+	return NT_STATUS_OK;
+}
+
+NTSTATUS nfs4acl_xdr_blob_to_smb4(struct vfs_handle_struct *handle,
+				  TALLOC_CTX *mem_ctx,
+				  DATA_BLOB *blob,
+				  struct SMB4ACL_T **_smb4acl)
+{
+	struct nfs4acl_config *config = NULL;
+	nfsacl41 *nacl = NULL;
+	struct SMB4ACL_T *smb4acl = NULL;
+	NTSTATUS status;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	status = nfs4acl_xdr_blob_to_nfs4acl(handle, talloc_tos(), blob, &nacl);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	status = nfs4acl_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
+	TALLOC_FREE(nacl);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	*_smb4acl = smb4acl;
+	return NT_STATUS_OK;
+}
+
+#else /* !HAVE_RPC_XDR_H */
+NTSTATUS nfs4acl_xdr_blob_to_smb4(struct vfs_handle_struct *handle,
+				  TALLOC_CTX *mem_ctx,
+				  DATA_BLOB *blob,
+				  struct SMB4ACL_T **_smb4acl)
+{
+	return NT_STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
+				     TALLOC_CTX *mem_ctx,
+				     struct SMB4ACL_T *smbacl,
+				     DATA_BLOB *blob)
+{
+	return NT_STATUS_NOT_SUPPORTED;
+}
+#endif /* HAVE_RPC_XDR_H */
diff --git a/source3/modules/nfs4acl_xattr_xdr.h b/source3/modules/nfs4acl_xattr_xdr.h
new file mode 100644
index 00000000000..8a544349cc8
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_xdr.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Ralph Boehme 2017
+ *
+ * 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 __NFS4ACL_XATTR_XDR_H__
+#define __NFS4ACL_XATTR_XDR_H__
+
+#define NFS4ACL_XDR_XATTR_NAME "security.nfs4acl_xdr"
+#define NFS4ACL_XDR_MAX_ACES 8192
+
+NTSTATUS nfs4acl_xdr_blob_to_smb4(struct vfs_handle_struct *handle,
+				  TALLOC_CTX *mem_ctx,
+				  DATA_BLOB *blob,
+				  struct SMB4ACL_T **_smb4acl);
+
+NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
+				     TALLOC_CTX *mem_ctx,
+				     struct SMB4ACL_T *smbacl,
+				     DATA_BLOB *blob);
+
+#endif /* __NFS4ACL_XATTR_XDR_H__ */
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index d4f4d47635e..d301f25ed31 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -34,6 +34,7 @@
 #include "librpc/gen_ndr/ndr_nfs4acl.h"
 #include "nfs4acl_xattr.h"
 #include "nfs4acl_xattr_ndr.h"
+#include "nfs4acl_xattr_xdr.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -224,6 +225,9 @@ static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
 	case NFS4ACL_ENCODING_NDR:
 		status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
 		break;
+	case NFS4ACL_ENCODING_XDR:
+		status = nfs4acl_xdr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
+		break;
 	default:
 		status = NT_STATUS_INTERNAL_ERROR;
 		break;
@@ -320,6 +324,10 @@ static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
 		status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
 						     smb4acl, &blob);
 		break;
+	case NFS4ACL_ENCODING_XDR:
+		status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
+						     smb4acl, &blob);
+		break;
 	default:
 		status = NT_STATUS_INTERNAL_ERROR;
 		break;
@@ -515,6 +523,9 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 	config->encoding = (enum nfs4acl_encoding)enumval;
 
 	switch (config->encoding) {
+	case NFS4ACL_ENCODING_XDR:
+		default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
+		break;
 	case NFS4ACL_ENCODING_NDR:
 	default:
 		default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
index 6943d474826..ab9be384189 100644
--- a/source3/modules/wscript_build
+++ b/source3/modules/wscript_build
@@ -217,9 +217,30 @@ bld.SAMBA3_MODULE('vfs_zfsacl',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_zfsacl'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_zfsacl'))
 
+xdr_buf_hack = 'sed -e "s@^\([ \t]*register int32_t \*buf\);@\\1 = buf;@"'
+
+bld.SAMBA_GENERATOR('nfs41acl-xdr-c',
+                    source='nfs41acl.x',
+                    target='nfs41acl_xdr.c',
+                    rule='rpcgen -c ${SRC} | ' + xdr_buf_hack + ' > ${TGT}')
+
+bld.SAMBA_GENERATOR('nfs41acl-h',
+                    source='nfs41acl.x',
+                    target='nfs41acl.h',
+                    rule='rpcgen -h ${SRC} > ${TGT}')
+
+vfs_nfs4acl_xattr_source = '''
+                           vfs_nfs4acl_xattr.c
+                           nfs4acl_xattr_ndr.c
+                           nfs4acl_xattr_xdr.c
+                           '''
+
+if bld.CONFIG_SET("HAVE_RPC_XDR_H"):
+    vfs_nfs4acl_xattr_source += ' nfs41acl_xdr.c'
+
 bld.SAMBA3_MODULE('vfs_nfs4acl_xattr',
                   subsystem='vfs',
-                  source='vfs_nfs4acl_xattr.c nfs4acl_xattr_ndr.c',
+                  source=vfs_nfs4acl_xattr_source,
                   deps='NFS4_ACLS sunacl NDR_NFS4ACL',
                   init_function='',
                   internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_nfs4acl_xattr'),
diff --git a/source3/wscript b/source3/wscript
index 3638abab202..814433488e4 100644
--- a/source3/wscript
+++ b/source3/wscript
@@ -1664,6 +1664,8 @@ main() {
         Logs.info("building with Spotlight support")
         default_static_modules.extend(TO_LIST('rpc_mdssvc_module'))
 
+    conf.CHECK_HEADERS('rpc/xdr.h')
+
     forced_static_modules.extend(TO_LIST('auth_builtin auth_sam auth_winbind'))
     default_static_modules.extend(TO_LIST('''pdb_smbpasswd pdb_tdbsam
                                       auth_unix
-- 
2.13.6


From d325e93328de304e219e723cf725210e6868a0ea Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 7 Sep 2017 17:29:03 +0200
Subject: [PATCH 25/27] selftest: run raw.acls tests against a share with XDR
 NFS4 ACLs

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail        | 6 ++++++
 selftest/target/Samba3.pm | 8 ++++++++
 source3/selftest/tests.py | 1 +
 3 files changed, 15 insertions(+)

diff --git a/selftest/knownfail b/selftest/knownfail
index 36c1697f9a4..1791614fc90 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -34,6 +34,12 @@
 ^samba3.raw.acls nfs4acl_xattr-special-40.nulldacl\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special-40.inherit_creator_owner\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-special-40.inherit_creator_group\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-40.INHERITFLAGS\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-40.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-40.create_owner_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-40.nulldacl\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-40.inherit_creator_owner\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-40.inherit_creator_group\(nt4_dc\)
 ^samba3.base.delete.deltest16a
 ^samba3.base.delete.deltest17a
 ^samba3.unix.whoami anonymous connection.whoami\(ad_dc\) # We need to resolve if we should be including SID_NT_WORLD and SID_NT_NETWORK in this token
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 57db4fa1c60..248075ddffa 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1882,6 +1882,14 @@ sub provision($$$$$$$$$)
 	nfs4:mode = simple
 	vfs objects = nfs4acl_xattr xattr_tdb
 
+[nfs4acl_xdr_40]
+	path = $shrdir
+	comment = smb username is [%U]
+	vfs objects = nfs4acl_xattr xattr_tdb
+	nfs4:mode = simple
+	nfs4acl_xattr:encoding = xdr
+	nfs4acl_xattr:version = 40
+
 [xcopy_share]
 	path = $shrdir
 	comment = smb username is [%U]
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 4dc7f753fb5..e2a8b7a4db5 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -464,6 +464,7 @@ for t in tests:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-40')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_special_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-special-40')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-41')
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_xdr_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-xdr-40')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/tmpcase -U$USERNAME%$PASSWORD')
     elif t == "smb2.ioctl":
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/fs_specific -U$USERNAME%$PASSWORD', 'fs_specific')
-- 
2.13.6


From 12e6537b49fb204e1ccc50f1021a7ae01ba11197 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 19 Oct 2017 14:24:03 +0200
Subject: [PATCH 26/27] selftest: run raw.acls test with XDR NFS41 ACLs

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/knownfail        | 3 +++
 selftest/target/Samba3.pm | 8 ++++++++
 source3/selftest/tests.py | 1 +
 3 files changed, 12 insertions(+)

diff --git a/selftest/knownfail b/selftest/knownfail
index 1791614fc90..3c910fb3d6f 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -40,6 +40,9 @@
 ^samba3.raw.acls nfs4acl_xattr-xdr-40.nulldacl\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-xdr-40.inherit_creator_owner\(nt4_dc\)
 ^samba3.raw.acls nfs4acl_xattr-xdr-40.inherit_creator_group\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-41.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-41.create_owner_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-xdr-41.nulldacl\(nt4_dc\)
 ^samba3.base.delete.deltest16a
 ^samba3.base.delete.deltest17a
 ^samba3.unix.whoami anonymous connection.whoami\(ad_dc\) # We need to resolve if we should be including SID_NT_WORLD and SID_NT_NETWORK in this token
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 248075ddffa..688045522af 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1890,6 +1890,14 @@ sub provision($$$$$$$$$)
 	nfs4acl_xattr:encoding = xdr
 	nfs4acl_xattr:version = 40
 
+[nfs4acl_xdr_41]
+	path = $shrdir
+	comment = smb username is [%U]
+	vfs objects = nfs4acl_xattr xattr_tdb
+	nfs4:mode = simple
+	nfs4acl_xattr:encoding = xdr
+	nfs4acl_xattr:version = 41
+
 [xcopy_share]
 	path = $shrdir
 	comment = smb username is [%U]
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index e2a8b7a4db5..186b2235875 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -465,6 +465,7 @@ for t in tests:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_special_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-special-40')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-41')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_xdr_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-xdr-40')
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_xdr_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-xdr-41')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/tmpcase -U$USERNAME%$PASSWORD')
     elif t == "smb2.ioctl":
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/fs_specific -U$USERNAME%$PASSWORD', 'fs_specific')
-- 
2.13.6


From a5c3925e4c428780d1e87810d553608312834efc Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 23 Oct 2017 18:56:37 +0200
Subject: [PATCH 27/27] manpages: add vfs_nfs4acl_xattr.8

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 docs-xml/manpages/vfs_nfs4acl_xattr.8.xml | 134 ++++++++++++++++++++++++++++++
 docs-xml/wscript_build                    |   1 +
 2 files changed, 135 insertions(+)
 create mode 100644 docs-xml/manpages/vfs_nfs4acl_xattr.8.xml

diff --git a/docs-xml/manpages/vfs_nfs4acl_xattr.8.xml b/docs-xml/manpages/vfs_nfs4acl_xattr.8.xml
new file mode 100644
index 00000000000..16737349b71
--- /dev/null
+++ b/docs-xml/manpages/vfs_nfs4acl_xattr.8.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="vfs_nfs4acl_xattr.8">
+
+  <refmeta>
+    <refentrytitle>vfs_nfs4acl_xattr</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo class="source">Samba</refmiscinfo>
+    <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+    <refmiscinfo class="version">4.7</refmiscinfo>
+  </refmeta>
+
+
+  <refnamediv>
+    <refname>vfs_nfs4acl_xattr</refname>
+    <refpurpose>Save NTFS-ACLs as NFS4 encoded blobs in extended
+    attributes</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>vfs objects = nfs4acl_xattr</command>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+
+    <para>This VFS module is part of the
+    <citerefentry><refentrytitle>samba</refentrytitle>
+    <manvolnum>7</manvolnum></citerefentry> suite.</para>
+
+    <para>The <command>vfs_acl_xattr</command> VFS module stores NTFS Access
+    Control Lists (ACLs) in Extended Attributes (EAs/xattrs).  This enables the
+    full mapping of Windows ACLs on Samba servers.
+    </para>
+
+    <para>This module is stackable.</para>
+  </refsect1>
+
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist>
+
+      <varlistentry>
+	<term>nfs4acl_xattr:encoding = [ndr|xdr]</term>
+	<listitem>
+	  <para>This parameter configures the marshaling format used in the ACL
+	  blob and the default extended attribute name used to store the blob.
+	  </para>
+
+	  <para>When set to <emphasis>ndr (default)</emphasis> - store the NT
+	  ACL with POSIX draft NFSv4 compatible NDR encoding. By default this
+	  uses the extended attribute "security.nfs4acl_ndr".</para>
+
+	  <para>When set to <emphasis>xdr</emphasis> - store the NT ACL in a
+	  format similar to NFS 4.1 RFC 5661 in XDR encoding. The main
+	  differences to RFC 5661 are the use of ids instead of strings as users
+	  and group identifiers and an additional attribute per nfsace4. By
+	  default this encoding stores the blob in the extended attribute
+	  "security.nfs4acl_xdr".</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>nfs4acl_xattr:version = [40|41]</term>
+	<listitem>
+	  <para>This parameter configures the NFS4 ACL level. Only
+	  <emphasis>41</emphasis> fully supports mapping NT ACLs and should be
+	  used. The default is <emphasis>41</emphasis>.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>nfs4acl_xattr:default acl style = [posix|windows|everyone]</term>
+	<listitem>
+	  <para>This parameter determines the type of ACL that is synthesized in
+	  case a file or directory lacks an ACL extended attribute.</para>
+
+	  <para>When set to <emphasis>posix</emphasis>, an ACL will be
+	  synthesized based on the POSIX mode permissions for user, group and
+	  others, with an additional ACE for <emphasis>NT
+	  Authority\SYSTEM</emphasis> will full rights.</para>
+
+	  <para>When set to <emphasis>windows</emphasis>, an ACL is synthesized
+	  the same way Windows does it, only including permissions for the owner
+	  and <emphasis>NT Authority\SYSTEM</emphasis>.</para>
+
+	  <para>When set to <emphasis>everyone</emphasis>, an ACL is synthesized
+	  giving full permissions to everyone (S-1-1-0).</para>
+
+	  <para>The default for this option is
+	  <emphasis>everyone</emphasis>.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>nfs4acl_xattr:xattr_name = STRING</term>
+	<listitem>
+	  <para>This parameter configures the extended attribute name used to
+	  store the marshaled ACL.</para>
+	  <para>The default depends on the setting for
+	  <emphasis>nfs4acl_xattr:encoding</emphasis>.</para>
+	</listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>EXAMPLES</title>
+
+    <para>A directory can be exported via Samba using this module as
+    follows:</para>
+
+    <programlisting>
+      <smbconfsection name="[samba_gpfs_share]"/>
+      <smbconfoption name="vfs objects">nfs4acl_xattr</smbconfoption>
+      <smbconfoption name="path">/foo/bar</smbconfoption>
+    </programlisting>
+  </refsect1>
+
+  <refsect1>
+    <title>AUTHOR</title>
+
+    <para>The original Samba software and related utilities
+    were created by Andrew Tridgell. Samba is now developed
+    by the Samba Team as an Open Source project similar
+    to the way the Linux kernel is developed.</para>
+  </refsect1>
+
+</refentry>
diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build
index 5670572167f..afba0b9e841 100644
--- a/docs-xml/wscript_build
+++ b/docs-xml/wscript_build
@@ -74,6 +74,7 @@ manpages='''
          manpages/vfs_linux_xfs_sgid.8
          manpages/vfs_media_harmony.8
          manpages/vfs_netatalk.8
+         manpages/vfs_nfs4acl_xattr.8
          manpages/vfs_offline.8
          manpages/vfs_prealloc.8
          manpages/vfs_preopen.8
-- 
2.13.6



More information about the samba-technical mailing list