[PATCH] Fix for XDR Backend of NFS4ACL_XATTR module to get it working with NFS4.0 ACL Spec

Ralph Böhme slow at samba.org
Tue Nov 27 21:07:12 UTC 2018


On Mon, Nov 26, 2018 at 04:48:03PM +0100, Ralph Böhme wrote:
>On Wed, Nov 21, 2018 at 06:21:28PM +0100, Ralph Böhme via samba-technical wrote:
>>On Tue, Oct 30, 2018 at 03:57:06PM +0000, Sandeep Nashikkar via samba-technical wrote:
>>>It's been couple of months my XDR patch for NFS4ACL_XATTR module 
>>>is pending for review.  Can we please expedite this?
>>
>>sorry, please bear with me, I've had customers sitting on my back 
>>all the time. This is now next on my list, so there's light at the 
>>end of the tunnel. :)
>
>ok, so what about this one?

attached is an updated patchset with a bunch of fixes above the previous 
version.

This one passes make test TESTS=raw.acls against shares with the new module 
format "nfs" for versions 4.0 and 4.1.

Currently running full CI: https://gitlab.com/samba-team/devel/samba/pipelines/38130330

To get make test working I had to fix an older bug
https://bugzilla.samba.org/show_bug.cgi?id=12164

The fix for this bug is part of the attached patchset.

-slow

-- 
Ralph Boehme, Samba Team                https://samba.org/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/
GPG-Fingerprint   FAE2C6088A24252051C559E4AA1E9B7126399E46
-------------- next part --------------
From 57be8340e45c8d356d376eb98660ab58af09cc54 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 27 Nov 2018 17:32:09 +0100
Subject: [PATCH 01/12] winbindd: add some braces

Bug: https://bugzilla.samba.org/show_bug.cgi?id=12164

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

diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 9bc25d98c4e..090a90574ce 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -1527,7 +1527,9 @@ struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
 
 	if (strequal(domain_name, "BUILTIN") ||
 	    strequal(domain_name, get_global_sam_name()))
+	{
 		return find_domain_from_name_noinit(domain_name);
+	}
 
 	if (IS_DC) {
 		struct winbindd_domain *domain = NULL;
-- 
2.17.2


From f58cf41134a12a56b814418e0e381334d1a56a5d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 27 Nov 2018 20:32:09 +0100
Subject: [PATCH 02/12] selftest: test wbinfo -n and --gid-info with "NT
 Authority"

Bug: https://bugzilla.samba.org/show_bug.cgi?id=12164
---
 nsswitch/tests/test_wbinfo.sh              | 18 ++++++++++++++++++
 selftest/knownfail.d/samba.blackbox.wbinfo |  2 ++
 2 files changed, 20 insertions(+)
 create mode 100644 selftest/knownfail.d/samba.blackbox.wbinfo

diff --git a/nsswitch/tests/test_wbinfo.sh b/nsswitch/tests/test_wbinfo.sh
index 67660e50fc8..2ac83828a0e 100755
--- a/nsswitch/tests/test_wbinfo.sh
+++ b/nsswitch/tests/test_wbinfo.sh
@@ -125,6 +125,24 @@ else
 	echo "success: wbinfo -n check for sane mapping"
 fi
 
+echo "test: wbinfo -n NT Authority/Authenticated Users"
+$wbinfo -n "NT Authority/Authenticated Users"
+if [ $? -ne 0 ] ; then
+    echo "failure: wbinfo -n NT Authority/Authenticated Users"
+    failed=`expr $failed + 1`
+else
+    echo "success: wbinfo -n NT Authority/Authenticated Users"
+fi
+
+echo "test: wbinfo --group-info NT Authority/Authenticated Users"
+$wbinfo --group-info "NT Authority/Authenticated Users"
+if [ $? -ne 0 ] ; then
+    echo "failure: wbinfo --group-info NT Authority/Authenticated Users"
+    failed=`expr $failed + 1`
+else
+    echo "success: wbinfo --group-info NT Authority/Authenticated Users"
+fi
+
 testit "wbinfo -U against $TARGET" $wbinfo -U 30000 || failed=`expr $failed + 1`
 
 echo "test: wbinfo -U check for sane mapping"
diff --git a/selftest/knownfail.d/samba.blackbox.wbinfo b/selftest/knownfail.d/samba.blackbox.wbinfo
new file mode 100644
index 00000000000..e294c2d3c15
--- /dev/null
+++ b/selftest/knownfail.d/samba.blackbox.wbinfo
@@ -0,0 +1,2 @@
+^samba.blackbox.wbinfo\(.*\).wbinfo -n NT Authority/Authenticated Users\(.*\)
+^samba.blackbox.wbinfo\(.*\).wbinfo --group-info NT Authority/Authenticated Users\(.*\)
-- 
2.17.2


From 9e82aef3311defa51053367812a0d1a94beb1cb6 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Tue, 27 Nov 2018 17:05:58 +0100
Subject: [PATCH 03/12] WIP: winbindd: handle "NT Authority"

Without this:

  $ bin/wbinfo -n "NT Authority/Authenticated Users"
  failed to call wbcLookupName: WBC_ERR_DOMAIN_NOT_FOUND
  Could not lookup name NT Authority/Authenticated Users

  $ bin/wbinfo --group-info="NT Authority/Authenticated Users"
  failed to call wbcGetgrnam: WBC_ERR_DOMAIN_NOT_FOUND
  Could not get info for group NT Authority/Authenticated Users

With the patch:

  $ bin/wbinfo -n "NT Authority/Authenticated Users"
  S-1-5-11 SID_WKN_GROUP (5)

  $ bin/wbinfo --group-info="NT Authority/Authenticated Users"
  NT AUTHORITY\authenticated users:x:10002:

Bug: https://bugzilla.samba.org/show_bug.cgi?id=12164
---
 selftest/knownfail.d/samba.blackbox.wbinfo | 2 --
 source3/winbindd/winbindd_util.c           | 7 ++++---
 2 files changed, 4 insertions(+), 5 deletions(-)
 delete mode 100644 selftest/knownfail.d/samba.blackbox.wbinfo

diff --git a/selftest/knownfail.d/samba.blackbox.wbinfo b/selftest/knownfail.d/samba.blackbox.wbinfo
deleted file mode 100644
index e294c2d3c15..00000000000
--- a/selftest/knownfail.d/samba.blackbox.wbinfo
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba.blackbox.wbinfo\(.*\).wbinfo -n NT Authority/Authenticated Users\(.*\)
-^samba.blackbox.wbinfo\(.*\).wbinfo --group-info NT Authority/Authenticated Users\(.*\)
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 090a90574ce..82ec004436a 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -1516,11 +1516,12 @@ struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
 {
 	if ( strequal(domain_name, unix_users_domain_name() ) ||
-	     strequal(domain_name, unix_groups_domain_name() ) )
+	     strequal(domain_name, unix_groups_domain_name() ) ||
+	     strequal(domain_name, "NT Authority"))
 	{
 		/*
-		 * The "Unix User" and "Unix Group" domain our handled by
-		 * passdb
+		 * The "Unix User", "Unix Group" and "NT Authority" domains are
+		 * handled by passdb
 		 */
 		return find_domain_from_name_noinit( get_global_sam_name() );
 	}
-- 
2.17.2


From 9f094ca75f997859b9faf25189544443f06088ec Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 22 Nov 2018 18:27:47 +0100
Subject: [PATCH 04/12] nfs4acl_xattr: identifiers are XDR encoded as integers

The struct are no RFC 3530 compliant, rename the nfs4 structs, the
trailing i indicates that the struct stores identifiers as integers.

Rename

  struct nfsace4

to

  struct nfsace4i

add

  struct nfsacl41

to

  struct nfsacl41i
---
 source3/modules/nfs41acl.x          |  6 ++--
 source3/modules/nfs4acl_xattr_xdr.c | 46 ++++++++++++++---------------
 2 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/source3/modules/nfs41acl.x b/source3/modules/nfs41acl.x
index 9cfbd9f3074..1a2e1d639e5 100644
--- a/source3/modules/nfs41acl.x
+++ b/source3/modules/nfs41acl.x
@@ -70,7 +70,7 @@ const ACE4_SYNCHRONIZE          = 0x00100000;
 
 typedef u_int acemask4;
 
-struct nfsace4 {
+struct nfsace4i {
         acetype4        type;
         aceflag4        flag;
         aceiflag4       iflag;
@@ -88,7 +88,7 @@ const ACL4_DEFAULTED            = 0x00000004;
 
 typedef u_int aclflag4;
 
-struct nfsacl41 {
+struct nfsacl41i {
         aclflag4        na41_flag;
-        nfsace4         na41_aces<>;
+        nfsace4i        na41_aces<>;
 };
diff --git a/source3/modules/nfs4acl_xattr_xdr.c b/source3/modules/nfs4acl_xattr_xdr.c
index 399c104faa4..5afeb5bc2e5 100644
--- a/source3/modules/nfs4acl_xattr_xdr.c
+++ b/source3/modules/nfs4acl_xattr_xdr.c
@@ -40,27 +40,27 @@
 #include "nfs41acl.h"
 #include "nfs4acl_xattr_xdr.h"
 
-static unsigned nfs4acl_get_naces(nfsacl41 *nacl)
+static unsigned nfs4acl_get_naces(nfsacl41i *nacl)
 {
 	return nacl->na41_aces.na41_aces_len;
 }
 
-static void nfs4acl_set_naces(nfsacl41 *nacl, unsigned naces)
+static void nfs4acl_set_naces(nfsacl41i *nacl, unsigned naces)
 {
 	nacl->na41_aces.na41_aces_len = naces;
 }
 
-static unsigned nfs4acl_get_flags(nfsacl41 *nacl)
+static unsigned nfs4acl_get_flags(nfsacl41i *nacl)
 {
 	return nacl->na41_flag;
 }
 
-static void nfs4acl_set_flags(nfsacl41 *nacl, unsigned flags)
+static void nfs4acl_set_flags(nfsacl41i *nacl, unsigned flags)
 {
 	nacl->na41_flag = flags;
 }
 
-static size_t nfs4acl_get_xdrblob_size(nfsacl41 *nacl)
+static size_t nfs4acl_get_xdrblob_size(nfsacl41i *nacl)
 {
 	size_t acl_size;
 	size_t aces_size;
@@ -73,7 +73,7 @@ static size_t nfs4acl_get_xdrblob_size(nfsacl41 *nacl)
 		return 0;
 	}
 
-	aces_size = naces * sizeof(struct nfsace4);
+	aces_size = naces * sizeof(struct nfsace4i);
 	if (acl_size + aces_size < acl_size) {
 		return 0;
 	}
@@ -91,13 +91,13 @@ static size_t nfs4acl_get_xdrblob_naces(size_t _blobsize)
 	if (blobsize > _blobsize) {
 		return 0;
 	}
-	return (blobsize / sizeof(struct nfsace4));
+	return (blobsize / sizeof(struct nfsace4i));
 }
 
-static nfsacl41 *nfs4acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
+static nfsacl41i *nfs4acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
 {
-	size_t acl_size = sizeof(nfsacl41) + (naces * sizeof(struct nfsace4));
-	nfsacl41 *nacl = NULL;
+	size_t acl_size = sizeof(nfsacl41i) + (naces * sizeof(struct nfsace4i));
+	nfsacl41i *nacl = NULL;
 
 	if (naces > NFS4ACL_XDR_MAX_ACES) {
 		DBG_ERR("Too many ACEs: %d\n", naces);
@@ -112,12 +112,12 @@ static nfsacl41 *nfs4acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
 
 	nfs4acl_set_naces(nacl, naces);
 	nacl->na41_aces.na41_aces_val =
-		(nfsace4 *)((char *)nacl + sizeof(nfsacl41));
+		(nfsace4i *)((char *)nacl + sizeof(nfsacl41i));
 
 	return nacl;
 }
 
-static nfsace4 *nfs4acl_get_ace(nfsacl41 *nacl, size_t n)
+static nfsace4i *nfs4acl_get_ace(nfsacl41i *nacl, size_t n)
 {
 	return &nacl->na41_aces.na41_aces_val[n];
 }
@@ -142,12 +142,12 @@ static unsigned smb4acl_to_nfs4acl_flags(uint16_t smb4acl_flags)
 static bool smb4acl_to_nfs4acl(vfs_handle_struct *handle,
 			       TALLOC_CTX *mem_ctx,
 			       struct SMB4ACL_T *smb4acl,
-			       nfsacl41 **_nacl)
+			       nfsacl41i **_nacl)
 {
 	struct nfs4acl_config *config = NULL;
 	struct SMB4ACE_T *smb4ace = NULL;
 	size_t smb4naces = 0;
-	nfsacl41 *nacl = NULL;
+	nfsacl41i *nacl = NULL;
 	uint16_t smb4acl_flags = 0;
 	unsigned nacl_flags = 0;
 
@@ -169,7 +169,7 @@ static bool smb4acl_to_nfs4acl(vfs_handle_struct *handle,
 	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);
+		nfsace4i *nace = nfs4acl_get_ace(nacl, nace_count);
 
 		nace->type = ace4prop->aceType;
 		nace->flag = ace4prop->aceFlags;
@@ -219,7 +219,7 @@ NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
 				     struct SMB4ACL_T *smb4acl,
 				     DATA_BLOB *_blob)
 {
-	nfsacl41 *nacl = NULL;
+	nfsacl41i *nacl = NULL;
 	XDR xdr = {0};
 	size_t aclblobsize;
 	DATA_BLOB blob;
@@ -244,7 +244,7 @@ NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
 
 	xdrmem_create(&xdr, (char *)blob.data, blob.length, XDR_ENCODE);
 
-	ok = xdr_nfsacl41(&xdr, nacl);
+	ok = xdr_nfsacl41i(&xdr, nacl);
 	TALLOC_FREE(nacl);
 	if (!ok) {
 		DBG_ERR("xdr_nfs4acl41 failed\n");
@@ -275,10 +275,10 @@ static uint16_t nfs4acl_to_smb4acl_flags(unsigned nfsacl41_flags)
 static NTSTATUS nfs4acl_xdr_blob_to_nfs4acl(struct vfs_handle_struct *handle,
 					    TALLOC_CTX *mem_ctx,
 					    DATA_BLOB *blob,
-					    nfsacl41 **_nacl)
+					    nfsacl41i **_nacl)
 {
 	struct nfs4acl_config *config = NULL;
-	nfsacl41 *nacl = NULL;
+	nfsacl41i *nacl = NULL;
 	size_t naces;
 	XDR xdr = {0};
 	bool ok;
@@ -292,7 +292,7 @@ static NTSTATUS nfs4acl_xdr_blob_to_nfs4acl(struct vfs_handle_struct *handle,
 
 	xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
 
-	ok = xdr_nfsacl41(&xdr, nacl);
+	ok = xdr_nfsacl41i(&xdr, nacl);
 	if (!ok) {
 		DBG_ERR("xdr_nfs4acl41 failed\n");
 		return NT_STATUS_INTERNAL_ERROR;
@@ -308,7 +308,7 @@ static NTSTATUS nfs4acl_xdr_blob_to_nfs4acl(struct vfs_handle_struct *handle,
 
 static NTSTATUS nfs4acl_to_smb4acl(struct vfs_handle_struct *handle,
 				   TALLOC_CTX *mem_ctx,
-				   nfsacl41 *nacl,
+				   nfsacl41i *nacl,
 				   struct SMB4ACL_T **_smb4acl)
 {
 	struct nfs4acl_config *config = NULL;
@@ -336,7 +336,7 @@ static NTSTATUS nfs4acl_to_smb4acl(struct vfs_handle_struct *handle,
 	DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces);
 
 	for (i = 0; i < naces; i++) {
-		nfsace4 *nace = nfs4acl_get_ace(nacl, i);
+		nfsace4i *nace = nfs4acl_get_ace(nacl, i);
 		SMB_ACE4PROP_T smbace = { 0 };
 
 		DBG_DEBUG("type [%d] iflag [%x] flag [%x] mask [%x] who [%d]\n",
@@ -388,7 +388,7 @@ NTSTATUS nfs4acl_xdr_blob_to_smb4(struct vfs_handle_struct *handle,
 				  struct SMB4ACL_T **_smb4acl)
 {
 	struct nfs4acl_config *config = NULL;
-	nfsacl41 *nacl = NULL;
+	nfsacl41i *nacl = NULL;
 	struct SMB4ACL_T *smb4acl = NULL;
 	NTSTATUS status;
 
-- 
2.17.2


From 44527372a0fe6e22b0b11d60dbeb7ac9d347b88d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 25 Nov 2018 11:47:48 +0100
Subject: [PATCH 05/12] nfs4acl_xattr: append 'i' to nfs4acl functions

This reflect the new struct names we're working on.
---
 source3/modules/nfs4acl_xattr_xdr.c | 74 ++++++++++++++---------------
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/source3/modules/nfs4acl_xattr_xdr.c b/source3/modules/nfs4acl_xattr_xdr.c
index 5afeb5bc2e5..ebe990215fa 100644
--- a/source3/modules/nfs4acl_xattr_xdr.c
+++ b/source3/modules/nfs4acl_xattr_xdr.c
@@ -40,31 +40,31 @@
 #include "nfs41acl.h"
 #include "nfs4acl_xattr_xdr.h"
 
-static unsigned nfs4acl_get_naces(nfsacl41i *nacl)
+static unsigned nfs4acli_get_naces(nfsacl41i *nacl)
 {
 	return nacl->na41_aces.na41_aces_len;
 }
 
-static void nfs4acl_set_naces(nfsacl41i *nacl, unsigned naces)
+static void nfs4acli_set_naces(nfsacl41i *nacl, unsigned naces)
 {
 	nacl->na41_aces.na41_aces_len = naces;
 }
 
-static unsigned nfs4acl_get_flags(nfsacl41i *nacl)
+static unsigned nfs4acli_get_flags(nfsacl41i *nacl)
 {
 	return nacl->na41_flag;
 }
 
-static void nfs4acl_set_flags(nfsacl41i *nacl, unsigned flags)
+static void nfs4acli_set_flags(nfsacl41i *nacl, unsigned flags)
 {
 	nacl->na41_flag = flags;
 }
 
-static size_t nfs4acl_get_xdrblob_size(nfsacl41i *nacl)
+static size_t nfs4acli_get_xdrblob_size(nfsacl41i *nacl)
 {
 	size_t acl_size;
 	size_t aces_size;
-	unsigned naces = nfs4acl_get_naces(nacl);
+	unsigned naces = nfs4acli_get_naces(nacl);
 
 	acl_size = sizeof(aclflag4) + sizeof(unsigned);
 
@@ -82,7 +82,7 @@ static size_t nfs4acl_get_xdrblob_size(nfsacl41i *nacl)
 	return acl_size;
 }
 
-static size_t nfs4acl_get_xdrblob_naces(size_t _blobsize)
+static size_t nfs4acli_get_xdrblob_naces(size_t _blobsize)
 {
 	size_t blobsize = _blobsize;
 
@@ -94,7 +94,7 @@ static size_t nfs4acl_get_xdrblob_naces(size_t _blobsize)
 	return (blobsize / sizeof(struct nfsace4i));
 }
 
-static nfsacl41i *nfs4acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
+static nfsacl41i *nfs4acli_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
 {
 	size_t acl_size = sizeof(nfsacl41i) + (naces * sizeof(struct nfsace4i));
 	nfsacl41i *nacl = NULL;
@@ -110,14 +110,14 @@ static nfsacl41i *nfs4acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
 		return NULL;
 	}
 
-	nfs4acl_set_naces(nacl, naces);
+	nfs4acli_set_naces(nacl, naces);
 	nacl->na41_aces.na41_aces_val =
 		(nfsace4i *)((char *)nacl + sizeof(nfsacl41i));
 
 	return nacl;
 }
 
-static nfsace4i *nfs4acl_get_ace(nfsacl41i *nacl, size_t n)
+static nfsace4i *nfs4acli_get_ace(nfsacl41i *nacl, size_t n)
 {
 	return &nacl->na41_aces.na41_aces_val[n];
 }
@@ -139,10 +139,10 @@ static unsigned smb4acl_to_nfs4acl_flags(uint16_t smb4acl_flags)
 	return nfs4acl_flags;
 }
 
-static bool smb4acl_to_nfs4acl(vfs_handle_struct *handle,
-			       TALLOC_CTX *mem_ctx,
-			       struct SMB4ACL_T *smb4acl,
-			       nfsacl41i **_nacl)
+static bool smb4acl_to_nfs4acli(vfs_handle_struct *handle,
+				TALLOC_CTX *mem_ctx,
+				struct SMB4ACL_T *smb4acl,
+				nfsacl41i **_nacl)
 {
 	struct nfs4acl_config *config = NULL;
 	struct SMB4ACE_T *smb4ace = NULL;
@@ -156,20 +156,20 @@ static bool smb4acl_to_nfs4acl(vfs_handle_struct *handle,
 				return false);
 
 	smb4naces = smb_get_naces(smb4acl);
-	nacl = nfs4acl_alloc(mem_ctx, smb4naces);
-	nfs4acl_set_naces(nacl, 0);
+	nacl = nfs4acli_alloc(mem_ctx, smb4naces);
+	nfs4acli_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);
+		nfs4acli_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);
-		nfsace4i *nace = nfs4acl_get_ace(nacl, nace_count);
+		size_t nace_count = nfs4acli_get_naces(nacl);
+		nfsace4i *nace = nfs4acli_get_ace(nacl, nace_count);
 
 		nace->type = ace4prop->aceType;
 		nace->flag = ace4prop->aceFlags;
@@ -206,7 +206,7 @@ static bool smb4acl_to_nfs4acl(vfs_handle_struct *handle,
 		}
 
 		nace_count++;
-		nfs4acl_set_naces(nacl, nace_count);
+		nfs4acli_set_naces(nacl, nace_count);
 		smb4ace = smb_next_ace4(smb4ace);
 	}
 
@@ -225,13 +225,13 @@ NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
 	DATA_BLOB blob;
 	bool ok;
 
-	ok = smb4acl_to_nfs4acl(handle, talloc_tos(), smb4acl, &nacl);
+	ok = smb4acl_to_nfs4acli(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);
+	aclblobsize = nfs4acli_get_xdrblob_size(nacl);
 	if (aclblobsize == 0) {
 		return NT_STATUS_INTERNAL_ERROR;
 	}
@@ -272,10 +272,10 @@ static uint16_t nfs4acl_to_smb4acl_flags(unsigned nfsacl41_flags)
 	return smb4acl_flags;
 }
 
-static NTSTATUS nfs4acl_xdr_blob_to_nfs4acl(struct vfs_handle_struct *handle,
-					    TALLOC_CTX *mem_ctx,
-					    DATA_BLOB *blob,
-					    nfsacl41i **_nacl)
+static NTSTATUS nfs4acl_xdr_blob_to_nfs4acli(struct vfs_handle_struct *handle,
+					     TALLOC_CTX *mem_ctx,
+					     DATA_BLOB *blob,
+					     nfsacl41i **_nacl)
 {
 	struct nfs4acl_config *config = NULL;
 	nfsacl41i *nacl = NULL;
@@ -287,8 +287,8 @@ static NTSTATUS nfs4acl_xdr_blob_to_nfs4acl(struct vfs_handle_struct *handle,
 				struct nfs4acl_config,
 				return NT_STATUS_INTERNAL_ERROR);
 
-	naces = nfs4acl_get_xdrblob_naces(blob->length);
-	nacl = nfs4acl_alloc(mem_ctx, naces);
+	naces = nfs4acli_get_xdrblob_naces(blob->length);
+	nacl = nfs4acli_alloc(mem_ctx, naces);
 
 	xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
 
@@ -306,16 +306,16 @@ static NTSTATUS nfs4acl_xdr_blob_to_nfs4acl(struct vfs_handle_struct *handle,
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS nfs4acl_to_smb4acl(struct vfs_handle_struct *handle,
-				   TALLOC_CTX *mem_ctx,
-				   nfsacl41i *nacl,
-				   struct SMB4ACL_T **_smb4acl)
+static NTSTATUS nfs4acli_to_smb4acl(struct vfs_handle_struct *handle,
+				    TALLOC_CTX *mem_ctx,
+				    nfsacl41i *nacl,
+				    struct SMB4ACL_T **_smb4acl)
 {
 	struct nfs4acl_config *config = NULL;
 	struct SMB4ACL_T *smb4acl = NULL;
 	unsigned nfsacl41_flag = 0;
 	uint16_t smb4acl_flags = 0;
-	unsigned naces = nfs4acl_get_naces(nacl);
+	unsigned naces = nfs4acli_get_naces(nacl);
 	int i;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
@@ -328,7 +328,7 @@ static NTSTATUS nfs4acl_to_smb4acl(struct vfs_handle_struct *handle,
 	}
 
 	if (config->nfs_version > ACL4_XATTR_VERSION_40) {
-		nfsacl41_flag = nfs4acl_get_flags(nacl);
+		nfsacl41_flag = nfs4acli_get_flags(nacl);
 		smb4acl_flags = nfs4acl_to_smb4acl_flags(nfsacl41_flag);
 		smbacl4_set_controlflags(smb4acl, smb4acl_flags);
 	}
@@ -336,7 +336,7 @@ static NTSTATUS nfs4acl_to_smb4acl(struct vfs_handle_struct *handle,
 	DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces);
 
 	for (i = 0; i < naces; i++) {
-		nfsace4i *nace = nfs4acl_get_ace(nacl, i);
+		nfsace4i *nace = nfs4acli_get_ace(nacl, i);
 		SMB_ACE4PROP_T smbace = { 0 };
 
 		DBG_DEBUG("type [%d] iflag [%x] flag [%x] mask [%x] who [%d]\n",
@@ -396,12 +396,12 @@ NTSTATUS nfs4acl_xdr_blob_to_smb4(struct vfs_handle_struct *handle,
 				struct nfs4acl_config,
 				return NT_STATUS_INTERNAL_ERROR);
 
-	status = nfs4acl_xdr_blob_to_nfs4acl(handle, talloc_tos(), blob, &nacl);
+	status = nfs4acl_xdr_blob_to_nfs4acli(handle, talloc_tos(), blob, &nacl);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
 
-	status = nfs4acl_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
+	status = nfs4acli_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
 	TALLOC_FREE(nacl);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
-- 
2.17.2


From 84e437e5b98d7dee56946e49704a05aaed96365c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sun, 25 Nov 2018 12:07:26 +0100
Subject: [PATCH 06/12] nfs4acl_xattr: move some functions to a seperate file

These functions will be called from another translation unit in a
subsequent commit.
---
 source3/modules/nfs4acl_xattr_util.c | 73 ++++++++++++++++++++++++++++
 source3/modules/nfs4acl_xattr_util.h | 25 ++++++++++
 source3/modules/nfs4acl_xattr_xdr.c  | 35 +------------
 source3/modules/wscript_build        |  1 +
 4 files changed, 100 insertions(+), 34 deletions(-)
 create mode 100644 source3/modules/nfs4acl_xattr_util.c
 create mode 100644 source3/modules/nfs4acl_xattr_util.h

diff --git a/source3/modules/nfs4acl_xattr_util.c b/source3/modules/nfs4acl_xattr_util.c
new file mode 100644
index 00000000000..8ea1e76ad17
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_util.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) Ralph Boehme 2018
+ *
+ * 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"
+
+#ifdef HAVE_RPC_XDR_H
+/* <rpc/xdr.h> uses TRUE and FALSE */
+#ifdef TRUE
+#undef TRUE
+#endif
+
+#ifdef FALSE
+#undef FALSE
+#endif
+#endif
+
+#include "nfs4_acls.h"
+#include "nfs41acl.h"
+#include "nfs4acl_xattr_util.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+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;
+}
+
+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;
+}
diff --git a/source3/modules/nfs4acl_xattr_util.h b/source3/modules/nfs4acl_xattr_util.h
new file mode 100644
index 00000000000..2d2c6a158ba
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_util.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) Ralph Boehme 2018
+ *
+ * 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_UTIL_H_
+#define _NFS4ACL_XATTR_UTIL_H_
+
+unsigned smb4acl_to_nfs4acl_flags(uint16_t smb4acl_flags);
+uint16_t nfs4acl_to_smb4acl_flags(unsigned nfsacl41_flags);
+
+#endif /* _NFS4ACL_XATTR_UTIL_H_ */
diff --git a/source3/modules/nfs4acl_xattr_xdr.c b/source3/modules/nfs4acl_xattr_xdr.c
index ebe990215fa..1db36e96769 100644
--- a/source3/modules/nfs4acl_xattr_xdr.c
+++ b/source3/modules/nfs4acl_xattr_xdr.c
@@ -39,6 +39,7 @@
 #include <rpc/xdr.h>
 #include "nfs41acl.h"
 #include "nfs4acl_xattr_xdr.h"
+#include "nfs4acl_xattr_util.h"
 
 static unsigned nfs4acli_get_naces(nfsacl41i *nacl)
 {
@@ -122,23 +123,6 @@ static nfsace4i *nfs4acli_get_ace(nfsacl41i *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_nfs4acli(vfs_handle_struct *handle,
 				TALLOC_CTX *mem_ctx,
 				struct SMB4ACL_T *smb4acl,
@@ -255,23 +239,6 @@ NTSTATUS nfs4acl_smb4acl_to_xdr_blob(vfs_handle_struct *handle,
 	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_nfs4acli(struct vfs_handle_struct *handle,
 					     TALLOC_CTX *mem_ctx,
 					     DATA_BLOB *blob,
diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
index db083f50646..3c593bab7f3 100644
--- a/source3/modules/wscript_build
+++ b/source3/modules/wscript_build
@@ -259,6 +259,7 @@ vfs_nfs4acl_xattr_source = '''
                            vfs_nfs4acl_xattr.c
                            nfs4acl_xattr_ndr.c
                            nfs4acl_xattr_xdr.c
+                           nfs4acl_xattr_util.c
                            '''
 
 if bld.CONFIG_SET("HAVE_RPC_XDR_H"):
-- 
2.17.2


From 31a0f128302d5053b7ce19bc991adbce21f25a01 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 26 Nov 2018 16:27:28 +0100
Subject: [PATCH 07/12] s3:build: add tirpc to vfs_nfs4acl_xattr

This is needed on modern Linux distros.

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

diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
index 3c593bab7f3..a14a370777f 100644
--- a/source3/modules/wscript_build
+++ b/source3/modules/wscript_build
@@ -268,7 +268,7 @@ vfs_nfs4acl_xattr_source = '''
 bld.SAMBA3_MODULE('vfs_nfs4acl_xattr',
                   subsystem='vfs',
                   source=vfs_nfs4acl_xattr_source,
-                  deps='NFS4_ACLS sunacl NDR_NFS4ACL',
+                  deps='NFS4_ACLS sunacl NDR_NFS4ACL tirpc',
                   init_function='',
                   internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_nfs4acl_xattr'),
                   enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_nfs4acl_xattr'))
-- 
2.17.2


From e486d2c351be49b8cce3b4c5681c4336a3b6e61b Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 26 Nov 2018 16:29:43 +0100
Subject: [PATCH 08/12] nfs4acl_xattr: move a define to a common header file

In preperation of a adding real NFS backend.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/nfs4acl_xattr.h     | 2 ++
 source3/modules/nfs4acl_xattr_xdr.h | 1 -
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/source3/modules/nfs4acl_xattr.h b/source3/modules/nfs4acl_xattr.h
index 3eeb4703bc8..86416063bf4 100644
--- a/source3/modules/nfs4acl_xattr.h
+++ b/source3/modules/nfs4acl_xattr.h
@@ -19,6 +19,8 @@
 #ifndef __NFS4ACL_XATTR_H__
 #define __NFS4ACL_XATTR_H__
 
+#define NFS4ACL_XDR_MAX_ACES 8192
+
 enum nfs4acl_encoding {NFS4ACL_ENCODING_NDR, NFS4ACL_ENCODING_XDR};
 
 struct nfs4acl_config {
diff --git a/source3/modules/nfs4acl_xattr_xdr.h b/source3/modules/nfs4acl_xattr_xdr.h
index 8a544349cc8..4a79a0da93f 100644
--- a/source3/modules/nfs4acl_xattr_xdr.h
+++ b/source3/modules/nfs4acl_xattr_xdr.h
@@ -20,7 +20,6 @@
 #define __NFS4ACL_XATTR_XDR_H__
 
 #define NFS4ACL_XDR_XATTR_NAME "security.nfs4acl_xdr"
-#define NFS4ACL_XDR_MAX_ACES 8192
 
 NTSTATUS nfs4acl_xdr_blob_to_smb4(struct vfs_handle_struct *handle,
 				  TALLOC_CTX *mem_ctx,
-- 
2.17.2


From 1543fa22259b5b27518b5d1b1aacf51bb97de47e Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 26 Nov 2018 16:30:38 +0100
Subject: [PATCH 09/12] nfs4acl_xattr: add RFC compliant NFS 4.0 and 4.1 ACL
 defintions

---
 source3/modules/nfs41acl.x | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/source3/modules/nfs41acl.x b/source3/modules/nfs41acl.x
index 1a2e1d639e5..51ac89a0791 100644
--- a/source3/modules/nfs41acl.x
+++ b/source3/modules/nfs41acl.x
@@ -70,6 +70,14 @@ const ACE4_SYNCHRONIZE          = 0x00100000;
 
 typedef u_int acemask4;
 
+/* ACL structure definition as per RFC 7530 Section-6.2.1 */
+struct nfsace4 {
+        acetype4        type;
+        aceflag4        flag;
+        acemask4        access_mask;
+        utf8str_mixed   who;
+};
+
 struct nfsace4i {
         acetype4        type;
         aceflag4        flag;
@@ -88,6 +96,15 @@ const ACL4_DEFAULTED            = 0x00000004;
 
 typedef u_int aclflag4;
 
+struct nfsacl40 {
+        nfsace4         na40_aces<>;
+};
+
+struct nfsacl41 {
+        aclflag4        na41_flag;
+        nfsace4         na41_aces<>;
+};
+
 struct nfsacl41i {
         aclflag4        na41_flag;
         nfsace4i        na41_aces<>;
-- 
2.17.2


From add728337fb9772d3dc2fd76513910bf8d93a30e Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 26 Nov 2018 16:31:42 +0100
Subject: [PATCH 10/12] nfs4acl_xattr: reformat enum nfs4acl_encoding to one
 per line

In preperation of adding another enum value.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/nfs4acl_xattr.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/source3/modules/nfs4acl_xattr.h b/source3/modules/nfs4acl_xattr.h
index 86416063bf4..d0c0b81fbd1 100644
--- a/source3/modules/nfs4acl_xattr.h
+++ b/source3/modules/nfs4acl_xattr.h
@@ -21,7 +21,10 @@
 
 #define NFS4ACL_XDR_MAX_ACES 8192
 
-enum nfs4acl_encoding {NFS4ACL_ENCODING_NDR, NFS4ACL_ENCODING_XDR};
+enum nfs4acl_encoding {
+	NFS4ACL_ENCODING_NDR,
+	NFS4ACL_ENCODING_XDR,
+};
 
 struct nfs4acl_config {
 	unsigned nfs_version;
-- 
2.17.2


From a9ad4d47e019d8bc501f903db8b34b79e6108dab Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 26 Nov 2018 20:51:14 +0100
Subject: [PATCH 11/12] selftest: test vfs_nfs4acl_xattr in nfs mode

---
 selftest/knownfail                  |  9 +++++++++
 selftest/target/Samba3.pm           | 18 ++++++++++++++++++
 source3/modules/vfs_nfs4acl_xattr.c |  4 ++++
 source3/selftest/tests.py           |  2 ++
 4 files changed, 33 insertions(+)

diff --git a/selftest/knownfail b/selftest/knownfail
index 16c2274daec..4ad5af03e3b 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -44,6 +44,15 @@
 ^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.raw.acls nfs4acl_xattr-nfs-40.INHERITFLAGS\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-nfs-40.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-nfs-40.create_owner_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-nfs-40.nulldacl\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-nfs-40.inherit_creator_owner\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-nfs-40.inherit_creator_group\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-nfs-41.create_owner_file\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-nfs-41.create_owner_dir\(nt4_dc\)
+^samba3.raw.acls nfs4acl_xattr-nfs-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 363840e4521..1709762e219 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1943,6 +1943,24 @@ sub provision($$$$$$$$$)
 	nfs4acl_xattr:encoding = xdr
 	nfs4acl_xattr:version = 41
 
+[nfs4acl_nfs_40]
+	path = $shrdir
+	comment = smb username is [%U]
+	vfs objects = nfs4acl_xattr xattr_tdb
+	nfs4:mode = simple
+	nfs4acl_xattr:encoding = nfs
+	nfs4acl_xattr:version = 40
+	nfs4acl_xattr:xattr_name = security.nfs4acl_xdr
+
+[nfs4acl_nfs_41]
+	path = $shrdir
+	comment = smb username is [%U]
+	vfs objects = nfs4acl_xattr xattr_tdb
+	nfs4:mode = simple
+	nfs4acl_xattr:encoding = nfs
+	nfs4acl_xattr:version = 41
+	nfs4acl_xattr:xattr_name = security.nfs4acl_xdr
+
 [xcopy_share]
 	path = $shrdir
 	comment = smb username is [%U]
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 0e52782075b..9803d8e4d57 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -328,6 +328,10 @@ static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
 		status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
 						     smb4acl, &blob);
 		break;
+	case NFS4ACL_ENCODING_NFS:
+		status = nfs4acl_smb4acl_to_nfs_blob(handle, talloc_tos(),
+						     smb4acl, &blob);
+		break;
 	default:
 		status = NT_STATUS_INTERNAL_ERROR;
 		break;
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index f3c5c39664b..e9f5f504ee8 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -555,6 +555,8 @@ tests = base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idma
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_simple_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-simple-41')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_xdr_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-xdr-40')
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_xdr_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-xdr-41')
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_nfs_40 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-nfs-40')
+        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/nfs4acl_nfs_41 -U$USERNAME%$PASSWORD', description='nfs4acl_xattr-nfs-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.17.2


From 0f2496e15ed5d00d89b7a307c265fe58c12f4318 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 26 Nov 2018 16:33:04 +0100
Subject: [PATCH 12/12] WIP: nfs4acl_xattr: support for NFS 4.0 and 4.1 ACLs
 from NFS4 mount

---
 docs-xml/manpages/vfs_nfs4acl_xattr.8.xml |  34 +-
 source3/modules/nfs4acl_xattr.h           |   3 +
 source3/modules/nfs4acl_xattr_nfs.c       | 894 ++++++++++++++++++++++
 source3/modules/nfs4acl_xattr_nfs.h       |  34 +
 source3/modules/vfs_nfs4acl_xattr.c       |  29 +
 source3/modules/wscript_build             |   1 +
 6 files changed, 994 insertions(+), 1 deletion(-)
 create mode 100644 source3/modules/nfs4acl_xattr_nfs.c
 create mode 100644 source3/modules/nfs4acl_xattr_nfs.h

diff --git a/docs-xml/manpages/vfs_nfs4acl_xattr.8.xml b/docs-xml/manpages/vfs_nfs4acl_xattr.8.xml
index c8780388184..c0fcee86b8c 100644
--- a/docs-xml/manpages/vfs_nfs4acl_xattr.8.xml
+++ b/docs-xml/manpages/vfs_nfs4acl_xattr.8.xml
@@ -45,12 +45,17 @@
     <variablelist>
 
       <varlistentry>
-	<term>nfs4acl_xattr:encoding = [ndr|xdr]</term>
+	<term>nfs4acl_xattr:encoding = [nfs|ndr|xdr]</term>
 	<listitem>
 	  <para>This parameter configures the marshaling format used in the ACL
 	  blob and the default extended attribute name used to store the blob.
 	  </para>
 
+	  <para>When set to <emphasis>nfs</emphasis> - fetch and store the NT
+	  ACL in NFS 4.0 or 4.1 compatible XDR encoding. By default this uses
+	  the extended attribute "system.nfs4_acl". This setting also
+	  disables <emphasis>validate_mode</emphasis>.</para>
+
 	  <para>When set to <emphasis>ndr (default)</emphasis> - store the NT
 	  ACL with POSIX draft NFSv4 compatible NDR encoding. By default this
 	  uses the extended attribute "security.nfs4acl_ndr".</para>
@@ -106,6 +111,33 @@
 	</listitem>
       </varlistentry>
 
+      <varlistentry>
+	<term>nfs4acl_xattr:nfs4_id_numeric = yes|no (default: no)</term>
+	<listitem>
+	  <para>This parameter tells the module how the NFS4 server encodes user
+	  and group identifiers on the network. With the default setting the
+	  module expects identifiers encoded as per the NFS4 RFC as
+	  user at domain.</para>
+	  <para>When set to <emphasis>yes</emphasis>, the module expects the
+	  identifiers as numeric string.</para>
+	  <para>The default for this options<emphasis>no</emphasis>.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>nfs4acl_xattr:validate_mode = yes|no</term>
+	<listitem>
+	  <para>This parameter configures whether the module enforces the POSIX
+	  mode is set to 0777 for directores and 0666 for files. If this
+	  constrained is not met, the xattr with the ACL blob is
+	  discarded.</para>
+	  <para>The default depends on the setting for
+	  <emphasis>nfs4acl_xattr:encoding</emphasis>: when set to
+	  <emphasis>nfs</emphasis> this setting is disabled by default,
+	  otherwise it is enabled.</para>
+	</listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
diff --git a/source3/modules/nfs4acl_xattr.h b/source3/modules/nfs4acl_xattr.h
index d0c0b81fbd1..0adede156ba 100644
--- a/source3/modules/nfs4acl_xattr.h
+++ b/source3/modules/nfs4acl_xattr.h
@@ -24,6 +24,7 @@
 enum nfs4acl_encoding {
 	NFS4ACL_ENCODING_NDR,
 	NFS4ACL_ENCODING_XDR,
+	NFS4ACL_ENCODING_NFS
 };
 
 struct nfs4acl_config {
@@ -32,6 +33,8 @@ struct nfs4acl_config {
 	char *xattr_name;
 	struct smbacl4_vfs_params nfs4_params;
 	enum default_acl_style default_acl_style;
+	bool nfs4_id_numeric;
+	bool validate_mode;
 };
 
 #endif /* __NFS4ACL_XATTR_H__ */
diff --git a/source3/modules/nfs4acl_xattr_nfs.c b/source3/modules/nfs4acl_xattr_nfs.c
new file mode 100644
index 00000000000..fe6c67a613e
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_nfs.c
@@ -0,0 +1,894 @@
+/*
+ * Copyright (C) Ralph Boehme 2018
+ *
+ * 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 "system/passwd.h"
+#include "libcli/security/security_descriptor.h"
+#include "libcli/security/security_token.h"
+
+#ifdef HAVE_RPC_XDR_H
+/* <rpc/xdr.h> uses TRUE and FALSE */
+#ifdef TRUE
+#undef TRUE
+#endif
+
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#include <rpc/xdr.h>
+
+#include "nfs4_acls.h"
+#include "nfs41acl.h"
+#include "nfs4acl_xattr.h"
+#include "nfs4acl_xattr_nfs.h"
+#include "nfs4acl_xattr_util.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+#define OVERFLOW_CHECK(val1, val2) ((val1) + (val2) < (val1))
+#define XDR_UTF8STR_ALIGNMENT 4
+#define XDR_UTF8STR_ALIGN(l) \
+	(l + (XDR_UTF8STR_ALIGNMENT - (l % XDR_UTF8STR_ALIGNMENT)))
+
+static struct nfs4_to_smb4_id_map {
+	const char *nfs4_id;
+	uint32_t smb4_id;
+} nfs4_to_smb4_id_map[] = {
+	{"OWNER@",		SMB_ACE4_WHO_OWNER},
+	{"GROUP@",		SMB_ACE4_WHO_GROUP},
+	{"EVERYONE@",		SMB_ACE4_WHO_EVERYONE},
+	{"INTERACTIVE@",	SMB_ACE4_WHO_INTERACTIVE},
+	{"NETWORK@",		SMB_ACE4_WHO_NETWORK},
+	{"DIALUP@",		SMB_ACE4_WHO_DIALUP},
+	{"BATCH@",		SMB_ACE4_WHO_BATCH},
+	{"ANONYMOUS@",		SMB_ACE4_WHO_ANONYMOUS},
+	{"AUTHENTICATED@",	SMB_ACE4_WHO_AUTHENTICATED},
+	{"SERVICE@",		SMB_ACE4_WHO_SERVICE},
+};
+
+static bool is_special_nfs4_id(const char *nfs4_id)
+{
+	char *at = NULL;
+
+	at = strchr(nfs4_id, '@');
+	if (at != NULL && at[1] == '\0') {
+		return true;
+	}
+	return false;
+}
+
+static bool map_special_nfs4_to_smb4_id(const char *nfs4_id, uint32_t *smb4_id)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(nfs4_to_smb4_id_map); i++) {
+		int cmp;
+
+		cmp = strcmp(nfs4_to_smb4_id_map[i].nfs4_id, nfs4_id);
+		if (cmp != 0) {
+			continue;
+		}
+		*smb4_id = nfs4_to_smb4_id_map[i].smb4_id;
+		return true;
+	}
+	return false;
+}
+
+static bool map_special_smb4_to_nfs4_id(uint32_t smb4_id, const char **nfs4_id)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(nfs4_to_smb4_id_map); i++) {
+		if (nfs4_to_smb4_id_map[i].smb4_id != smb4_id) {
+			continue;
+		}
+		*nfs4_id = nfs4_to_smb4_id_map[i].nfs4_id;
+		return true;
+	}
+	return false;
+}
+
+static unsigned nfs40acl_get_naces(nfsacl40 *nacl)
+{
+	return nacl->na40_aces.na40_aces_len;
+}
+
+static unsigned nfs41acl_get_naces(nfsacl41 *nacl)
+{
+	return nacl->na41_aces.na41_aces_len;
+}
+
+static void nfs40acl_set_naces(nfsacl40 *nacl, unsigned naces)
+{
+	nacl->na40_aces.na40_aces_len = naces;
+}
+
+static void nfs41acl_set_naces(nfsacl41 *nacl, unsigned naces)
+{
+	nacl->na41_aces.na41_aces_len = naces;
+}
+
+static unsigned nfs41acl_get_flags(nfsacl41 *nacl)
+{
+	return nacl->na41_flag;
+}
+
+static void nfs41acl_set_flags(nfsacl41 *nacl, unsigned flags)
+{
+	nacl->na41_flag = flags;
+}
+
+static nfsace4 *nfs40acl_get_ace(nfsacl40 *nacl, size_t n)
+{
+	return &nacl->na40_aces.na40_aces_val[n];
+}
+
+static nfsace4 *nfs41acl_get_ace(nfsacl41 *nacl, size_t n)
+{
+	return &nacl->na41_aces.na41_aces_val[n];
+}
+
+static size_t nfs40acl_get_xdrblob_size(nfsacl40 *nacl)
+{
+	size_t acl_size;
+	size_t aces_size;
+	size_t identifier_size;
+	unsigned i;
+	unsigned naces = nfs40acl_get_naces(nacl);
+
+	/* ACE structure minus actual identifier strings */
+	struct nfsace4_size {
+		acetype4 type;
+		aceflag4 flag;
+		acemask4 access_mask;
+		u_int who_length;
+	};
+
+	/*
+	 * acl_size =
+	 *   sizeof(ace_count) +
+	 *   (ace_count * (sizeof(nfsace4_size)) +
+	 *   length of all identifiers strings
+	 */
+
+	acl_size = sizeof(unsigned);
+
+	if (naces > NFS4ACL_XDR_MAX_ACES) {
+		DBG_ERR("Too many ACEs: %u", naces);
+		return 0;
+	}
+
+	aces_size = naces * sizeof(struct nfsace4_size);
+
+	if (OVERFLOW_CHECK(acl_size, aces_size)) {
+		DBG_ERR("Integer Overflow error\n");
+		return 0;
+	}
+	acl_size += aces_size;
+
+	DBG_DEBUG("aces_size: %zd\n", aces_size);
+
+	identifier_size = 0;
+
+	for (i = 0;  i < naces; i++) {
+		nfsace4 *nace = nfs40acl_get_ace(nacl, i);
+		size_t string_size = nace->who.utf8string_len;
+		size_t id_size;
+
+		id_size = XDR_UTF8STR_ALIGN(string_size);
+		if (id_size < string_size) {
+			DBG_ERR("Integer Overflow error\n");
+			return 0;
+		}
+
+		DBG_DEBUG("identifier[%u] size: %zd\n", i, id_size);
+		identifier_size += id_size;
+	}
+
+	DBG_DEBUG("identifier_size: %zd\n", identifier_size);
+
+	if (OVERFLOW_CHECK(acl_size, identifier_size)) {
+		DBG_ERR("Integer Overflow error\n");
+		return 0;
+	}
+	acl_size += identifier_size;
+
+	DBG_DEBUG("acl_size: %zd\n", acl_size);
+	return acl_size;
+}
+
+static size_t nfs41acl_get_xdrblob_size(nfsacl41 *nacl)
+{
+	size_t acl_size;
+	size_t aces_size;
+	size_t identifier_size;
+	unsigned i;
+	unsigned naces = nfs41acl_get_naces(nacl);
+
+	/* ACE structure minus actual identifier strings */
+	struct nfsace4_size {
+		acetype4 type;
+		aceflag4 flag;
+		acemask4 access_mask;
+		u_int who_length;
+	};
+
+	/*
+	 * acl_size =
+	 *   sizeof(acl_flag) +
+	 *   sizeof(ace_count) +
+	 *   (ace_count * (sizeof(nfsace4_size)) +
+	 *   length of all identifiers strings
+	 */
+
+	acl_size = 2 * sizeof(unsigned);
+
+	if (naces > NFS4ACL_XDR_MAX_ACES) {
+		DBG_ERR("Too many ACEs: %u", naces);
+		return 0;
+	}
+
+	aces_size = naces * sizeof(struct nfsace4_size);
+
+	if (OVERFLOW_CHECK(acl_size, aces_size)) {
+		DBG_ERR("Integer Overflow error\n");
+		return 0;
+	}
+	acl_size += aces_size;
+
+	DBG_DEBUG("aces_size: %zd\n", aces_size);
+
+	identifier_size = 0;
+
+	for (i = 0;  i < naces; i++) {
+		nfsace4 *nace = nfs41acl_get_ace(nacl, i);
+		size_t string_size = nace->who.utf8string_len;
+		size_t id_size;
+
+		id_size = XDR_UTF8STR_ALIGN(string_size);
+		if (id_size < string_size) {
+			DBG_ERR("Integer Overflow error\n");
+			return 0;
+		}
+
+		DBG_DEBUG("identifier[%u] size: %zd\n", i, id_size);
+		identifier_size += id_size;
+	}
+
+	DBG_DEBUG("identifier_size: %zd\n", identifier_size);
+
+	if (OVERFLOW_CHECK(acl_size, identifier_size)) {
+		DBG_ERR("Integer Overflow error\n");
+		return 0;
+	}
+	acl_size += identifier_size;
+
+	DBG_DEBUG("acl_size: %zd\n", acl_size);
+	return acl_size;
+}
+
+static nfsacl40 *nfs40acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
+{
+
+	size_t acl_size;
+	size_t aces_size;
+	nfsacl40 *nacl = NULL;
+
+	if (naces > NFS4ACL_XDR_MAX_ACES) {
+		DBG_ERR("Too many ACEs: %d\n", naces);
+		return NULL;
+	}
+
+	acl_size = sizeof(nfsacl40);
+	aces_size = (naces * sizeof(struct nfsace4));
+
+	if (OVERFLOW_CHECK(acl_size, aces_size)) {
+		DBG_ERR("Integer Overflow error\n");
+		return NULL;
+	}
+	acl_size += aces_size;
+
+	nacl = talloc_zero_size(mem_ctx, acl_size);
+	if (nacl == NULL) {
+		DBG_ERR("talloc_zero_size failed\n");
+		return NULL;
+	}
+
+	nfs40acl_set_naces(nacl, naces);
+	nacl->na40_aces.na40_aces_val =
+		(nfsace4 *)((uint8_t *)nacl + sizeof(nfsacl40));
+
+	return nacl;
+}
+
+static nfsacl41 *nfs41acl_alloc(TALLOC_CTX *mem_ctx, unsigned naces)
+{
+
+	size_t acl_size;
+	size_t aces_size;
+	nfsacl41 *nacl = NULL;
+
+	if (naces > NFS4ACL_XDR_MAX_ACES) {
+		DBG_ERR("Too many ACEs: %d\n", naces);
+		return NULL;
+	}
+
+	acl_size = sizeof(nfsacl41);
+	aces_size = (naces * sizeof(struct nfsace4));
+
+	if (OVERFLOW_CHECK(acl_size, aces_size)) {
+		DBG_ERR("Integer Overflow error\n");
+		return NULL;
+	}
+	acl_size += aces_size;
+
+	nacl = talloc_zero_size(mem_ctx, acl_size);
+	if (nacl == NULL) {
+		DBG_ERR("talloc_zero_size failed\n");
+		return NULL;
+	}
+
+	nfs41acl_set_naces(nacl, naces);
+	nacl->na41_aces.na41_aces_val =
+		(nfsace4 *)((uint8_t *)nacl + sizeof(nfsacl41));
+
+	return nacl;
+}
+
+static bool create_special_id(TALLOC_CTX *mem_ctx,
+			      nfsace4 *nace,
+			      const char *id)
+{
+	nace->who.utf8string_val = talloc_strdup(mem_ctx, id);
+	if (nace->who.utf8string_val == NULL) {
+		DBG_ERR("talloc_memdup failed\n");
+		return false;
+	}
+	nace->who.utf8string_len = talloc_get_size(nace->who.utf8string_val) - 1;
+	return true;
+}
+
+static bool map_smb4_to_nfs4_id(TALLOC_CTX *mem_ctx,
+				struct nfs4acl_config *config,
+				nfsace4 *nace,
+				SMB_ACE4PROP_T *sace)
+{
+	const char *nfs4_id = NULL;
+	const char *name = NULL;
+	uid_t id;
+	bool ok;
+
+	if (sace->flags & SMB_ACE4_ID_SPECIAL) {
+		ok = map_special_smb4_to_nfs4_id(sace->who.special_id,
+						 &nfs4_id);
+		if (!ok) {
+			DBG_ERR("Unsupported special id [%"PRIu32"]\n",
+				sace->who.special_id);
+			return false;
+		}
+
+		ok = create_special_id(mem_ctx, nace, nfs4_id);
+		if (!ok) {
+			return false;
+		}
+		DBG_DEBUG("Special id [%s]\n", nace->who.utf8string_val);
+		return true;
+	}
+
+	if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
+		nace->flag |= ACE4_IDENTIFIER_GROUP;
+	}
+
+	if (config->nfs4_id_numeric) {
+		char *strid = NULL;
+
+		if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
+			id = sace->who.gid;
+		} else {
+			id = sace->who.uid;
+		}
+
+		strid = talloc_asprintf(mem_ctx, "%jd", (intmax_t)id);
+		if (strid == NULL) {
+			DBG_ERR("talloc_asprintf failed\n");
+			return false;
+		}
+		nace->who.utf8string_val = strid;
+		nace->who.utf8string_len = talloc_get_size(strid) - 1;
+		DBG_DEBUG("Numeric id [%s]\n", nace->who.utf8string_val);
+		return true;
+	}
+
+	if (sace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
+		struct group *grp = NULL;
+
+		grp = getgrgid(sace->who.gid);
+		if (grp == NULL) {
+			DBG_ERR("Unknown gid [%jd]\n", (intmax_t)sace->who.gid);
+			return false;
+		}
+		name = grp->gr_name;
+	} else {
+		struct passwd *pwd = NULL;
+
+		pwd = getpwuid(sace->who.uid);
+		if (pwd == NULL) {
+			DBG_ERR("Unknown uid [%jd]\n", (intmax_t)sace->who.uid);
+			return false;
+		}
+		name = pwd->pw_name;
+	}
+
+	nace->who.utf8string_val = talloc_strdup(mem_ctx, name);
+	if (nace->who.utf8string_val == NULL) {
+		DBG_ERR("talloc_asprintf failed\n");
+		return false;
+	}
+	nace->who.utf8string_len = talloc_get_size(nace->who.utf8string_val) - 1;
+
+	DBG_DEBUG("id [%s]\n", nace->who.utf8string_val);
+	return true;
+}
+
+static bool smb4acl_to_nfs40acl(vfs_handle_struct *handle,
+			       TALLOC_CTX *mem_ctx,
+			       struct SMB4ACL_T *smb4acl,
+			       nfsacl40 **_nacl)
+{
+	struct nfs4acl_config *config = NULL;
+	struct SMB4ACE_T *smb4ace = NULL;
+	nfsacl40 *nacl = NULL;
+	size_t naces = smb_get_naces(smb4acl);
+	bool ok;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return false);
+
+	nacl = nfs40acl_alloc(mem_ctx, naces);
+	nfs40acl_set_naces(nacl, 0);
+
+	smb4ace = smb_first_ace4(smb4acl);
+	while (smb4ace != NULL) {
+		SMB_ACE4PROP_T *ace4prop = smb_get_ace4(smb4ace);
+		size_t nace_count = nfs40acl_get_naces(nacl);
+		nfsace4 *nace = nfs40acl_get_ace(nacl, nace_count);
+
+		nace->type = ace4prop->aceType;
+		nace->flag = ace4prop->aceFlags;
+		nace->access_mask = ace4prop->aceMask;
+
+		ok = map_smb4_to_nfs4_id(nacl, config, nace, ace4prop);
+		if (!ok) {
+			smb4ace = smb_next_ace4(smb4ace);
+			continue;
+		}
+
+		nace_count++;
+		nfs40acl_set_naces(nacl, nace_count);
+		smb4ace = smb_next_ace4(smb4ace);
+	}
+
+	*_nacl = nacl;
+	return true;
+}
+
+static bool smb4acl_to_nfs41acl(vfs_handle_struct *handle,
+			       TALLOC_CTX *mem_ctx,
+			       struct SMB4ACL_T *smb4acl,
+			       nfsacl41 **_nacl)
+{
+	struct nfs4acl_config *config = NULL;
+	struct SMB4ACE_T *smb4ace = NULL;
+	nfsacl41 *nacl = NULL;
+	size_t naces = smb_get_naces(smb4acl);
+	uint16_t smb4acl_flags;
+	unsigned nacl_flags;
+	bool ok;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return false);
+
+	nacl = nfs41acl_alloc(mem_ctx, naces);
+	nfs41acl_set_naces(nacl, 0);
+
+	smb4acl_flags = smbacl4_get_controlflags(smb4acl);
+	nacl_flags = smb4acl_to_nfs4acl_flags(smb4acl_flags);
+	nfs41acl_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 = nfs41acl_get_naces(nacl);
+		nfsace4 *nace = nfs41acl_get_ace(nacl, nace_count);
+
+		nace->type = ace4prop->aceType;
+		nace->flag = ace4prop->aceFlags;
+		nace->access_mask = ace4prop->aceMask;
+
+		ok = map_smb4_to_nfs4_id(nacl, config, nace, ace4prop);
+		if (!ok) {
+			smb4ace = smb_next_ace4(smb4ace);
+			continue;
+		}
+
+		nace_count++;
+		nfs41acl_set_naces(nacl, nace_count);
+		smb4ace = smb_next_ace4(smb4ace);
+	}
+
+	*_nacl = nacl;
+	return true;
+}
+
+NTSTATUS nfs4acl_smb4acl_to_nfs_blob(vfs_handle_struct *handle,
+				     TALLOC_CTX *mem_ctx,
+				     struct SMB4ACL_T *smb4acl,
+				     DATA_BLOB *_blob)
+{
+	struct nfs4acl_config *config = NULL;
+	nfsacl40 *nacl40 = NULL;
+	nfsacl41 *nacl41 = NULL;
+	XDR xdr = {0};
+	size_t aclblobsize;
+	DATA_BLOB blob;
+	bool ok;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	if (config->nfs_version == ACL4_XATTR_VERSION_40) {
+		ok = smb4acl_to_nfs40acl(handle, mem_ctx, smb4acl, &nacl40);
+		if (!ok) {
+			DBG_ERR("smb4acl_to_nfs4acl failed\n");
+			return NT_STATUS_INTERNAL_ERROR;
+		}
+
+		aclblobsize = nfs40acl_get_xdrblob_size(nacl40);
+		if (aclblobsize == 0) {
+			DBG_ERR("Error calculating XDR blob size\n");
+			return NT_STATUS_INTERNAL_ERROR;
+		}
+	} else {
+		ok = smb4acl_to_nfs41acl(handle, mem_ctx, smb4acl, &nacl41);
+		if (!ok) {
+			DBG_ERR("smb4acl_to_nfs4acl failed\n");
+			return NT_STATUS_INTERNAL_ERROR;
+		}
+
+		aclblobsize = nfs41acl_get_xdrblob_size(nacl41);
+		if (aclblobsize == 0) {
+			DBG_ERR("Error calculating XDR blob size\n");
+			return NT_STATUS_INTERNAL_ERROR;
+		}
+	}
+
+	blob = data_blob_talloc(mem_ctx, NULL, aclblobsize);
+	if (blob.data == NULL) {
+		TALLOC_FREE(nacl40);
+		TALLOC_FREE(nacl41);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	xdrmem_create(&xdr, (char *)blob.data, blob.length, XDR_ENCODE);
+
+	if (config->nfs_version == ACL4_XATTR_VERSION_40) {
+		ok = xdr_nfsacl40(&xdr, nacl40);
+		TALLOC_FREE(nacl40);
+		if (!ok) {
+			DBG_ERR("xdr_nfs4acl40 failed\n");
+			return NT_STATUS_NO_MEMORY;
+		}
+	} else {
+		ok = xdr_nfsacl41(&xdr, nacl41);
+		TALLOC_FREE(nacl41);
+		if (!ok) {
+			DBG_ERR("xdr_nfs4acl40 failed\n");
+			return NT_STATUS_NO_MEMORY;
+		}
+	}
+
+	*_blob = blob;
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS nfs4acl_nfs_blob_to_nfs40acl(struct vfs_handle_struct *handle,
+					     TALLOC_CTX *mem_ctx,
+					     DATA_BLOB *blob,
+					     nfsacl40 **_nacl)
+{
+	nfsacl40 *nacl = NULL;
+	XDR xdr = {0};
+	bool ok;
+
+	nacl = talloc_zero_size(mem_ctx, sizeof(nfsacl40));
+	if (nacl == NULL) {
+		DBG_ERR("talloc_zero_size failed\n");
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
+
+	ok = xdr_nfsacl40(&xdr, nacl);
+	if (!ok) {
+		DBG_ERR("xdr_nfsacl40 failed\n");
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	DBG_DEBUG("naces = %d \n", nacl->na40_aces.na40_aces_len);
+
+	*_nacl = nacl;
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS nfs4acl_nfs_blob_to_nfs41acl(struct vfs_handle_struct *handle,
+					     TALLOC_CTX *mem_ctx,
+					     DATA_BLOB *blob,
+					     nfsacl41 **_nacl)
+{
+	nfsacl41 *nacl = NULL;
+	XDR xdr = {0};
+	bool ok;
+
+	nacl = talloc_zero_size(mem_ctx, sizeof(nfsacl41));
+	if (nacl == NULL) {
+		DBG_ERR("talloc_zero_size failed\n");
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	xdrmem_create(&xdr, (char *)blob->data, blob->length, XDR_DECODE);
+
+	ok = xdr_nfsacl41(&xdr, nacl);
+	if (!ok) {
+		DBG_ERR("xdr_nfsacl40 failed\n");
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	DBG_DEBUG("naces = %d \n", nacl->na41_aces.na41_aces_len);
+
+	*_nacl = nacl;
+	return NT_STATUS_OK;
+}
+
+static bool map_ace_nfs4_to_smb4(struct nfs4acl_config *config,
+				 const nfsace4 *nace,
+				 SMB_ACE4PROP_T *sace)
+{
+	char *name = NULL;
+	char *p = NULL;
+	uint32_t smb4_id;
+	bool ok;
+
+	name = talloc_strndup(talloc_tos(),
+			      nace->who.utf8string_val,
+			      nace->who.utf8string_len);
+	if (name == NULL) {
+		return false;
+	}
+
+	sace->aceType = nace->type;
+	sace->aceFlags = nace->flag;
+	sace->aceMask = nace->access_mask;
+
+	if (is_special_nfs4_id(name)) {
+		ok = map_special_nfs4_to_smb4_id(name, &smb4_id);
+		if (!ok) {
+			DBG_WARNING("Unknown special id [%s]\n", name);
+			return false;
+		}
+		sace->flags |= SMB_ACE4_ID_SPECIAL;
+		sace->who.special_id = smb4_id;
+		return true;
+	}
+
+	p = strtok(name, "@");
+	if (p == NULL && !config->nfs4_id_numeric) {
+		DBG_ERR("Unqualified name [%s]\n", name);
+		TALLOC_FREE(name);
+		return false;
+	}
+
+	if (nace->flag & ACE4_IDENTIFIER_GROUP) {
+		sace->who.gid = nametogid(name);
+		if (sace->who.gid == (gid_t)-1) {
+			DBG_ERR("converting id [%s] failed\n", name);
+			TALLOC_FREE(name);
+			return false;
+		}
+		TALLOC_FREE(name);
+		return true;
+	}
+
+	sace->who.uid = nametouid(name);
+	if (sace->who.uid == (gid_t)-1) {
+		DBG_ERR("converting id [%s] failed\n", name);
+		TALLOC_FREE(name);
+		return false;
+	}
+	TALLOC_FREE(name);
+	return true;
+}
+
+static NTSTATUS nfs40acl_to_smb4acl(struct vfs_handle_struct *handle,
+				   TALLOC_CTX *mem_ctx,
+				   nfsacl40 *nacl,
+				   struct SMB4ACL_T **_smb4acl)
+{
+	struct nfs4acl_config *config = NULL;
+	struct SMB4ACL_T *smb4acl = NULL;
+	unsigned naces = nfs40acl_get_naces(nacl);
+	unsigned int i;
+	bool ok;
+
+	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;
+	}
+
+	DBG_DEBUG("nace [%u]\n", naces);
+
+	for (i = 0; i < naces; i++) {
+		nfsace4 *nace = nfs40acl_get_ace(nacl, i);
+		SMB_ACE4PROP_T sace = { 0 };
+
+		DBG_DEBUG("type [%d] flag [%x] mask [%x] who [%*s]\n",
+			  nace->type, nace->flag,
+			  nace->access_mask,
+			  nace->who.utf8string_len,
+			  nace->who.utf8string_val);
+
+		ok = map_ace_nfs4_to_smb4(config, nace, &sace);
+		if (!ok) {
+			continue;
+		}
+
+		smb_add_ace4(smb4acl, &sace);
+	}
+
+	*_smb4acl = smb4acl;
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS nfs41acl_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 = 0;
+	uint16_t smb4acl_flags = 0;
+	unsigned naces = nfs41acl_get_naces(nacl);
+	unsigned int i;
+	bool ok;
+
+	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;
+	}
+
+	nfsacl41_flag = nfs41acl_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 = nfs41acl_get_ace(nacl, i);
+		SMB_ACE4PROP_T sace = { 0 };
+
+		DBG_DEBUG("type [%d] flag [%x] mask [%x] who [%*s]\n",
+			  nace->type, nace->flag,
+			  nace->access_mask,
+			  nace->who.utf8string_len,
+			  nace->who.utf8string_val);
+
+		ok = map_ace_nfs4_to_smb4(config, nace, &sace);
+		if (!ok) {
+			continue;
+		}
+
+		smb_add_ace4(smb4acl, &sace);
+	}
+
+	*_smb4acl = smb4acl;
+	return NT_STATUS_OK;
+}
+
+NTSTATUS nfs4acl_nfs_blob_to_smb4(struct vfs_handle_struct *handle,
+				  TALLOC_CTX *mem_ctx,
+				  DATA_BLOB *blob,
+				  struct SMB4ACL_T **_smb4acl)
+{
+	struct nfs4acl_config *config = NULL;
+	struct SMB4ACL_T *smb4acl = NULL;
+	NTSTATUS status;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct nfs4acl_config,
+				return NT_STATUS_INTERNAL_ERROR);
+
+	if (config->nfs_version == ACL4_XATTR_VERSION_40) {
+		nfsacl40 *nacl = NULL;
+
+		status = nfs4acl_nfs_blob_to_nfs40acl(handle,
+						      talloc_tos(),
+						      blob,
+						      &nacl);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		status = nfs40acl_to_smb4acl(handle, mem_ctx, nacl, &smb4acl);
+		TALLOC_FREE(nacl);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+	} else {
+		nfsacl41 *nacl = NULL;
+
+		status = nfs4acl_nfs_blob_to_nfs41acl(handle,
+						      talloc_tos(),
+						      blob,
+						      &nacl);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		status = nfs41acl_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 */
+#include "nfs4acl_xattr_nfs.h"
+NTSTATUS nfs4acl_nfs_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_nfs_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_nfs.h b/source3/modules/nfs4acl_xattr_nfs.h
new file mode 100644
index 00000000000..47e5b1a48c1
--- /dev/null
+++ b/source3/modules/nfs4acl_xattr_nfs.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Ralph Boehme 2018
+ *
+ * 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_NFS_H__
+#define __NFS4ACL_XATTR_NFS_H__
+
+#define NFS4ACL_NFS_XATTR_NAME "system.nfs4_acl"
+
+NTSTATUS nfs4acl_nfs_blob_to_smb4(struct vfs_handle_struct *handle,
+				  TALLOC_CTX *mem_ctx,
+				  DATA_BLOB *blob,
+				  struct SMB4ACL_T **_smb4acl);
+
+NTSTATUS nfs4acl_smb4acl_to_nfs_blob(vfs_handle_struct *handle,
+				     TALLOC_CTX *mem_ctx,
+				     struct SMB4ACL_T *smbacl,
+				     DATA_BLOB *blob);
+
+#endif /* __NFS4ACL_XATTR_NFS_H__ */
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index 9803d8e4d57..851cc60d27f 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -35,6 +35,7 @@
 #include "nfs4acl_xattr.h"
 #include "nfs4acl_xattr_ndr.h"
 #include "nfs4acl_xattr_xdr.h"
+#include "nfs4acl_xattr_nfs.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -42,6 +43,7 @@
 static const struct enum_list nfs4acl_encoding[] = {
 	{NFS4ACL_ENCODING_NDR, "ndr"},
 	{NFS4ACL_ENCODING_XDR, "xdr"},
+	{NFS4ACL_ENCODING_NFS, "nfs"},
 };
 
 /*
@@ -60,6 +62,10 @@ static bool nfs4acl_validate_blob(vfs_handle_struct *handle,
 				struct nfs4acl_config,
 				return false);
 
+	if (!config->validate_mode) {
+		return true;
+	}
+
 	if (!VALID_STAT(smb_fname->st)) {
 		/* might be a create */
 		return true;
@@ -228,6 +234,9 @@ static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
 	case NFS4ACL_ENCODING_XDR:
 		status = nfs4acl_xdr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
 		break;
+	case NFS4ACL_ENCODING_NFS:
+		status = nfs4acl_nfs_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
+		break;
 	default:
 		status = NT_STATUS_INTERNAL_ERROR;
 		break;
@@ -394,6 +403,10 @@ static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
 	} else {
 		expected_mode = 0666;
 	}
+	if (!config->validate_mode) {
+		existing_mode = 0;
+		expected_mode = 0;
+	}
 	if ((existing_mode & expected_mode) != expected_mode) {
 		int saved_errno = 0;
 
@@ -491,6 +504,7 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 	struct nfs4acl_config *config = NULL;
 	const struct enum_list *default_acl_style_list = NULL;
 	const char *default_xattr_name = NULL;
+	bool default_validate_mode = true;
 	int enumval;
 	unsigned nfs_version;
 	int ret;
@@ -530,6 +544,10 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 	case NFS4ACL_ENCODING_XDR:
 		default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
 		break;
+	case NFS4ACL_ENCODING_NFS:
+		default_xattr_name = NFS4ACL_NFS_XATTR_NAME;
+		default_validate_mode = false;
+		break;
 	case NFS4ACL_ENCODING_NDR:
 	default:
 		default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
@@ -564,6 +582,17 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
 						   "xattr_name",
 						   default_xattr_name);
 
+	config->nfs4_id_numeric = lp_parm_bool(SNUM(handle->conn),
+					       "nfs4acl_xattr",
+					       "nfs4_id_numeric",
+					       false);
+
+
+	config->validate_mode = lp_parm_bool(SNUM(handle->conn),
+					     "nfs4acl_xattr",
+					     "validate_mode",
+					     default_validate_mode);
+
 	SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
 				return -1);
 
diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
index a14a370777f..aae6e0aa19d 100644
--- a/source3/modules/wscript_build
+++ b/source3/modules/wscript_build
@@ -259,6 +259,7 @@ vfs_nfs4acl_xattr_source = '''
                            vfs_nfs4acl_xattr.c
                            nfs4acl_xattr_ndr.c
                            nfs4acl_xattr_xdr.c
+                           nfs4acl_xattr_nfs.c
                            nfs4acl_xattr_util.c
                            '''
 
-- 
2.17.2



More information about the samba-technical mailing list