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

Ralph Böhme slow at samba.org
Tue Oct 24 08:58:13 UTC 2017


Hi!

I've been recently working on adding support for NFS4.1 ACLs and XDR storage
format for our vfs_nfs4acl_xattr module.

I'm mostly done, WIP patch attached. In fact the only WIP patch without a
signed-off is the new manpage.

What I'm trying to achieve is the following:

- modularize the exisiting module so choosing between existing IDL/NDR and a new
  XRD based encoding is feasible (done)

- add support for RFC 5661 NFS 4.1 based ACLs in both backends (done)

- rework how ACL inheritance is achieved and how files/directories without an
  ACL xattr get a default ACL, this now just works much the same as in
  vfs_acl_xattr (done)

- add options to choose between NFS 4.0 and 4.1 ACLs, the storage format, the
  xattr name and the default ACLA (done)

- add tests for both encodings and both NFS4 ACL levels (done)

- fix various issues along the way (done)

I've left the default behaviour as is, ie NDR marshalled blob in an xattr
"system.nfs4acl", NFS 4.0 ACLs, "everyone everything" default ACL but would like
to take the opportunity to discuss changing some of those defaults.

Is this module actually used anywhere besides for testing in autobuild? As the
module uses the system xattr namespace, the module will only work when stacked
with xattr_tdb. Any attempt to use it directly on a Linux filesystem that
supports xattrs will result in ENOTSUP from the xattr library functions, even as
root. So I doubt this is used anywhere in production, but who knows.

For the new XDR based backend I've set the default to "security.nfs4acl", so
with this backend the module is fully NT ACL compatible out-of-the-box and could
be used as a direct replacement for vfs_acl_xattr (if someone wishes).

Note that the latest NFS4 ACL patches by Andreas Gruenbacher already had a ACL
flags member in the ACL struct and ACL flags defines.

Question 1: do we want to change the default for the existing NDR backend to
"security.nfs4acl" as well?

Question 2: do we want to raise the default level to 4.1?

WIP patch attached, including the generated manpage for your convenience.

Thoughts?

Thanks!
-slow

-- 
Ralph Boehme, Samba Team       https://samba.org/samba/team/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/
-------------- next part --------------
From 649f5ef977ef96685c9ea131504b3d75645dd07a 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/25] 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.5


From 4b1bf14b6e25e77139a0906a17997de6e9f318fb 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/25] 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.5


From f8dd60486c5b5e848798903bc738f54a8f905fca 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/25] 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.5


From fd892bb6d3ba33cfe2fe4d01a5582234fbca9f5a 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/25] 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.5


From 70b5d92f600b4e8f97295b37c59584d0cc427cf6 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/25] 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.5


From cfc56cdcfc4482d1d03f49b3acec27c0c53b620d 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/25] 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.5


From adcaac11fb0acbfbec60b38272ca9e26082466fa 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/25] 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.5


From 91fecbc5c035f14c39b2ad2d3fa1ce51f3bf619a 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 08/25] 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 3d6894a604c..b5c9f2c7dfa 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.5


From 91d27cf4c194715763576eb2bf6d96c6c1ed2582 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 09/25] 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 | 84 +++++++++++++++++++++++++++++++++++++
 2 files changed, 116 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..3ec4910c719 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,82 @@ 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) {
+	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) {
+	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 +726,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.5


From 2b0bb8aacd5a5b3d6c9e44d9519c72bd95583c99 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 10/25] 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 3ec4910c719..59d9583686c 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;
 	}
@@ -662,6 +481,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.5


From b8a9061e2e14e6f9d46413d137a1ddddc4da8434 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 11/25] 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 59d9583686c..0bc605dbf7e 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.5


From f26375ff4a9c57c650ffa82957328ac37ca1da09 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 12/25] 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 0bc605dbf7e..c9a7392078a 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.5


From 910bfb7e4fb19c29f7e189d72658e7d352fd69e9 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 13/25] 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 c9a7392078a..7fa2df5ffc6 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.5


From 77f10bb9eb2f7334bbd73c85b62d8b17940fb3f6 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 14/25] 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 7fa2df5ffc6..57fab5d7f83 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.5


From f6cf010a43f4c3b04337de48e3ddda3614f5078a 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 15/25] 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 b5c9f2c7dfa..fade50c99a0 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.5


From 804394470112cee742ae30670fb46e78f406f66d 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 16/25] 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 57fab5d7f83..5c00cc4cfc2 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -351,6 +351,9 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 					    "version",
 					    40);
 	switch (nfs_version) {
+	case 41:
+		config->nfs_version = ACL4_XATTR_VERSION_41;
+		break;
 	default:
 		config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
 		break;
-- 
2.13.5


From 1d005e1e05dffb7c1b3bb35b8bd0003a6fcc108f 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 17/25] selftest: add explicit default NFS4 acl version

This is the default, just make it explicit.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 selftest/target/Samba3.pm | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index f4d033d0c7a..e47aa594c14 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1866,12 +1866,14 @@ sub provision($$$$$$$$$)
 	path = $shrdir
 	comment = smb username is [%U]
 	nfs4:mode = simple
+	nfs4acl_xattr:version = 40
 	vfs objects = nfs4acl_xattr xattr_tdb
 
 [nfs4acl_special]
 	path = $shrdir
 	comment = smb username is [%U]
 	nfs4:mode = special
+	nfs4acl_xattr:version = 40
 	vfs objects = nfs4acl_xattr xattr_tdb
 
 [xcopy_share]
-- 
2.13.5


From 9f40d860a77390f69e59e64464e68376c2ee6435 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 18/25] 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 | 7 +++++++
 source3/selftest/tests.py | 1 +
 3 files changed, 11 insertions(+)

diff --git a/selftest/knownfail b/selftest/knownfail
index f3c605ba582..be697e04d6a 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -25,6 +25,9 @@
 ^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-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.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\)
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index e47aa594c14..88df7e91d9d 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1876,6 +1876,13 @@ 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
+	nfs4acl_xattr:version = 41
+	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 c1e08d56731..f87d2e37d17 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -462,6 +462,7 @@ for t in tests:
     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_simple_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-41')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_special -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-special')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/tmpcase -U$USERNAME%$PASSWORD')
     elif t == "smb2.ioctl":
-- 
2.13.5


From 4b24fe97a64bda5ef3d24dd87ea362c3ed39c951 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 19/25] 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 | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 5c00cc4cfc2..1e968bc8bb5 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -78,6 +78,7 @@ static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
 			return NT_STATUS_NO_MEMORY;
 		}
 
+		become_root();
 		if (fsp != NULL && fsp->fh->fd != -1) {
 			length = SMB_VFS_NEXT_FGETXATTR(handle,
 							fsp,
@@ -91,6 +92,7 @@ static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
 						       blob->data,
 						       blob->length);
 		}
+		unbecome_root();
 	} while (length == -1 && errno == ERANGE && allocsize <= 65536);
 
 	if (length == -1) {
@@ -262,6 +264,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,6 +273,7 @@ static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
 					    config->xattr_name,
 					    blob.data, blob.length, 0);
 	}
+	unbecome_root();
 	data_blob_free(&blob);
 	if (ret != 0) {
 		DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
-- 
2.13.5


From 940c83a4ae15d4b51a436c6e54c5a213caad4239 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 20/25] 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 | 103 +++++++++++++++++++++++++++++++++---
 1 file changed, 97 insertions(+), 6 deletions(-)

diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 1e968bc8bb5..8f7f0f8ed1c 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,48 @@ 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 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);
+	unbecome_root();
+	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 +114,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 {
 		allocsize *= 4;
 		ok = data_blob_realloc(mem_ctx, blob, allocsize);
@@ -289,17 +337,60 @@ 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) {
+		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);
+		}
+		unbecome_root();
+		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.5


From 9ad99c5ad7e871bf388dad55b28ebc9f11fe05e8 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 21/25] 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 8f7f0f8ed1c..3fff30d97e2 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -337,9 +337,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;
 
@@ -386,11 +388,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.5


From d983ed4cb63ac307f7c39b04a8fb8a70d37c6245 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 22/25] 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".

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 | 398 ++++++++++++++++++++++++++++++++++++
 source3/modules/nfs4acl_xattr_xdr.h |  34 +++
 source3/modules/vfs_nfs4acl_xattr.c |  11 +
 source3/modules/wscript_build       |  23 ++-
 source3/wscript                     |   2 +
 6 files changed, 561 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..5685f2bce4b
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_xdr.c
@@ -0,0 +1,398 @@
+/*
+ * 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 size_t nfs4acl_get_xdrblob_size(nfsacl41 *nacl)
+{
+	size_t size = 0;
+
+	size += sizeof(aclflag4);
+	size += sizeof(unsigned);
+	size += nacl->na41_aces.na41_aces_len * sizeof(struct nfsace4);
+
+	return size;
+}
+
+static size_t nfs4acl_get_xdrblob_naces(size_t blobsize)
+{
+	blobsize -= sizeof(aclflag4);
+	blobsize -= sizeof(unsigned);
+
+	return (blobsize / sizeof(struct nfsace4));
+}
+
+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 nfsacl41 *nfs4acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
+{
+	size_t acl_size = sizeof(nfsacl41) + (naces * sizeof(struct nfsace4));
+	nfsacl41 *nacl = 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);
+
+	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..8769f98a001
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_xdr.h
@@ -0,0 +1,34 @@
+/*
+ * 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"
+
+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 3fff30d97e2..0d5138d6414 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
@@ -209,6 +210,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;
@@ -304,6 +308,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;
@@ -485,6 +493,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;
 	default:
 		default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
 		break;
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.5


From c60890a9d42017e6c6cfa67fb6c87d867d37c934 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 23/25] 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 be697e04d6a..16b7dc8d5fd 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -34,6 +34,12 @@
 ^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-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 88df7e91d9d..df2ab17ad6c 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1883,6 +1883,14 @@ sub provision($$$$$$$$$)
 	nfs4acl_xattr:version = 41
 	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 f87d2e37d17..4bbcee2796b 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 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-41')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_special -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-special')
+        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.5


From da8460239dde1ed3bc76606bc92c4b2d1cebd7af 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 24/25] 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 16b7dc8d5fd..dd81ce35478 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 df2ab17ad6c..2d218e428f3 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1891,6 +1891,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 4bbcee2796b..6ebcfc7b26b 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_simple_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-41')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_special -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-special')
         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.5


From 5fc4288e09eafd0faf6660e55222f7c36fa51a61 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 25/25] WIP manpages: add vfs_nfs4acl_xattr.8

---
 docs-xml/manpages/vfs_nfs4acl_xattr.8.xml | 136 ++++++++++++++++++++++++++++++
 docs-xml/wscript_build                    |   1 +
 2 files changed, 137 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..ce7a8f71e6b
--- /dev/null
+++ b/docs-xml/manpages/vfs_nfs4acl_xattr.8.xml
@@ -0,0 +1,136 @@
+<?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).
+    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 marshalling 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 "system.nfs4acl".</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".</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>40</emphasis> for backwards
+	  compatibility.</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 marshalled 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.5

-------------- next part --------------
A non-text attachment was scrubbed...
Name: vfs_nfs4acl_xattr.8
Type: application/x-troff-man
Size: 2981 bytes
Desc: not available
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20171024/b477f089/vfs_nfs4acl_xattr-0001.man>


More information about the samba-technical mailing list