[PATCH] SMB2 AAPL create context

Ralph Böhme rb at sernet.de
Tue Dec 2 11:09:44 MST 2014


Hi Volker,

thanks for looking into this!

On Tue, Dec 02, 2014 at 05:18:15PM +0100, Volker Lendecke wrote:
> Ok, this looks really nice. If I see it correctly, all the core logic
> is in vfs_fruit where it belongs IMHO.
> 
> I've added a few patches in between. Feel free to squash for the next
> round.

done. Updated patchset attached.

> I would like Jeremy to comment on ignoring the NFS-specific SIDs
> (S-1-5-88-) when setting ACLs and implicitly changing the semantics.

As described in an earlier mail: this tries to address the *POSIX* ACL
roundtripping issue where a client that wants to change the UNIX mode
by means of the MS NFS ACEs (ie a Mac where eg the user did a chmod
MODE in terminal), would cause the mode to explode into a set of POSIX
ACLs.

As such, set ACL request containing NFS ACEs are completely ignored in
the default POSIX ACL code, but in the NFSv4/ZFS VFS code I merely
ignore the NFS *ACE*s (so just suppressing a diagnostic here).

Then again the code in vfs_acl_common.c filters out the complete NFS
ACL, I just couldn't wind my head down into the full semantics of both
VFS modules acl_xattr and acl_tdb.

> I don't see another way to do it, but I'd like Mr. Jeremy
> 'Posix_acl' Allison to take a look.
> 
> I'm not sure if it makes sense to further complicate things, and I don't
> know if it's actually easily possible, but is there a way to make the
> "s3:smbd: ignore dacls with MS NFS ACEs" behaviour AAPL-negotiated
> only?

I guess I should adjust the commit message reflecting in detail what I
described above (ie completely ignoring the dacl in the case of POSIX
ACLs, only ignoring the NFS ACEs in the case of NFSv4 and ZFS ACL
backends).

> I don't event want to think about dirty global variables (Jeremy,
> shut up! :-)), but it might make it a bit safer. On the other hand --
> do we really have a problem when we just return NT_STATUS_OK for a pure
> acl set when such a SID is around? Any normal client won't do it anyway.

That was my take. :)

-Ralph

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de,mailto:kontakt@sernet.de
-------------- next part --------------
From 092057dad4661d1badee3e544a901fe45772c571 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 26 Nov 2014 14:30:37 +0100
Subject: [PATCH 01/12] s3:vfs: add SMB_VFS_READDIR_ATTR()

SMB_VFS_READDIR_ATTR is a last minute hook to fetch additional metadata
for a directory entry when we're already marshalling the SMB reply
buffer.

This would we used, when there's a need to repurpose some fields in the
the reply, like it's done with Apple's SMB2 extension "AAPL".

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 examples/VFS/skel_opaque.c       |  9 +++++++++
 examples/VFS/skel_transparent.c  |  9 +++++++++
 source3/include/smb.h            |  1 +
 source3/include/vfs.h            | 10 ++++++++++
 source3/include/vfs_macros.h     |  5 +++++
 source3/lib/readdir_attr.h       | 37 +++++++++++++++++++++++++++++++++++++
 source3/modules/vfs_default.c    |  9 +++++++++
 source3/modules/vfs_full_audit.c | 18 ++++++++++++++++++
 source3/modules/vfs_time_audit.c | 22 ++++++++++++++++++++++
 source3/smbd/vfs.c               |  9 +++++++++
 10 files changed, 129 insertions(+)
 create mode 100644 source3/lib/readdir_attr.h

diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c
index 47b46a4..6e15a06 100644
--- a/examples/VFS/skel_opaque.c
+++ b/examples/VFS/skel_opaque.c
@@ -633,6 +633,14 @@ static NTSTATUS skel_fsctl(struct vfs_handle_struct *handle,
 	return NT_STATUS_NOT_IMPLEMENTED;
 }
 
+static NTSTATUS skel_readdir_attr(struct vfs_handle_struct *handle,
+				  const struct smb_filename *fname,
+				  TALLOC_CTX *mem_ctx,
+				  struct readdir_attr_data **pattr_data)
+{
+	return NT_STATUS_NOT_IMPLEMENTED;
+}
+
 static NTSTATUS skel_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
 				 uint32 security_info,
 				 TALLOC_CTX *mem_ctx,
@@ -896,6 +904,7 @@ struct vfs_fn_pointers skel_opaque_fns = {
 	.strict_unlock_fn = skel_strict_unlock,
 	.translate_name_fn = skel_translate_name,
 	.fsctl_fn = skel_fsctl,
+	.readdir_attr_fn = skel_readdir_attr,
 
 	/* NT ACL operations. */
 
diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c
index fbb1323..b11e29c 100644
--- a/examples/VFS/skel_transparent.c
+++ b/examples/VFS/skel_transparent.c
@@ -759,6 +759,14 @@ static NTSTATUS skel_fsctl(struct vfs_handle_struct *handle,
 				  in_len, _out_data, max_out_len, out_len);
 }
 
+static NTSTATUS skel_readdir_attr(struct vfs_handle_struct *handle,
+				  const struct smb_filename *fname,
+				  TALLOC_CTX *mem_ctx,
+				  struct readdir_attr_data **pattr_data)
+{
+	return SMB_VFS_NEXT_READDIR_ATTR(handle, fname, mem_ctx, pattr_data);
+}
+
 static NTSTATUS skel_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
 				 uint32 security_info,
 				 TALLOC_CTX *mem_ctx,
@@ -1005,6 +1013,7 @@ struct vfs_fn_pointers skel_transparent_fns = {
 	.strict_unlock_fn = skel_strict_unlock,
 	.translate_name_fn = skel_translate_name,
 	.fsctl_fn = skel_fsctl,
+	.readdir_attr_fn = skel_readdir_attr,
 
 	/* NT ACL operations. */
 
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 53d3edc..108b59d 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -152,6 +152,7 @@ struct sys_notify_context {
 /* Include VFS stuff */
 
 #include "smb_acls.h"
+#include "lib/readdir_attr.h"
 #include "vfs.h"
 
 struct current_user {
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index b0f00e8..e443b96 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -159,6 +159,7 @@
 /* Bump to version 32 - Samba 4.2 will ship with that. */
 /* Version 32 - Add "lease" to CREATE_FILE operation */
 /* Version 32 - Add "lease" to struct files_struct */
+/* Version 32 - Add SMB_VFS_READDIR_ATTR() */
 
 #define SMB_VFS_INTERFACE_VERSION 32
 
@@ -787,6 +788,11 @@ struct vfs_fn_pointers {
 					 TALLOC_CTX *mem_ctx,
 					 struct files_struct **fsp,
 					 DATA_BLOB *new_cookie);
+
+	NTSTATUS (*readdir_attr_fn)(struct vfs_handle_struct *handle,
+				    const struct smb_filename *fname,
+				    TALLOC_CTX *mem_ctx,
+				    struct readdir_attr_data **attr_data);
 };
 
 /*
@@ -1232,6 +1238,10 @@ NTSTATUS smb_vfs_call_durable_reconnect(struct vfs_handle_struct *handle,
 					TALLOC_CTX *mem_ctx,
 					struct files_struct **fsp,
 					DATA_BLOB *new_cookie);
+NTSTATUS smb_vfs_call_readdir_attr(struct vfs_handle_struct *handle,
+				   const struct smb_filename *fname,
+				   TALLOC_CTX *mem_ctx,
+				   struct readdir_attr_data **attr_data);
 
 NTSTATUS smb_register_vfs(int version, const char *name,
 			  const struct vfs_fn_pointers *fns);
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index e2d494d..df676ad 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -565,4 +565,9 @@
 					(smb1req), (op), (old_cookie), \
 					(mem_ctx), (fsp), (new_cookie))
 
+#define SMB_VFS_READDIR_ATTR(conn, fname, mem_ctx, attr_data) \
+	smb_vfs_call_readdir_attr((conn)->vfs_handles, (fname), (mem_ctx), (attr_data))
+#define SMB_VFS_NEXT_READDIR_ATTR(conn, fname, mem_ctx, attr_data) \
+	smb_vfs_call_readdir_attr((handle)->next, (fname), (mem_ctx), (attr_data))
+
 #endif /* _VFS_MACROS_H */
diff --git a/source3/lib/readdir_attr.h b/source3/lib/readdir_attr.h
new file mode 100644
index 0000000..d2a814d
--- /dev/null
+++ b/source3/lib/readdir_attr.h
@@ -0,0 +1,37 @@
+/*
+ * Fetch filesystem metadata in readdir/marshall context
+ *
+ * Copyright (C) Ralph Boehme 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _READDIR_ATTR_H
+#define _READDIR_ATTR_H
+
+enum readdir_attr_type {RDATTR_NONE, RDATTR_AAPL};
+
+struct readdir_attr_data {
+	enum readdir_attr_type type;
+	union attr_data {
+		struct aapl {
+			uint64_t rfork_size;
+			char finder_info[16];
+			uint32_t max_access;
+			mode_t unix_mode;
+		} aapl;
+	} attr_data;
+};
+
+#endif	/* _READDIR_ATTR_H */
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 2ac7100..7610e65 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -403,6 +403,14 @@ static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
 	return result;
 }
 
+static NTSTATUS vfswrap_readdir_attr(struct vfs_handle_struct *handle,
+				     const struct smb_filename *fname,
+				     TALLOC_CTX *mem_ctx,
+				     struct readdir_attr_data **attr_data)
+{
+	return NT_STATUS_NOT_SUPPORTED;
+}
+
 static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
 {
 	START_PROFILE(syscall_seekdir);
@@ -2521,6 +2529,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
 	.opendir_fn = vfswrap_opendir,
 	.fdopendir_fn = vfswrap_fdopendir,
 	.readdir_fn = vfswrap_readdir,
+	.readdir_attr_fn = vfswrap_readdir_attr,
 	.seekdir_fn = vfswrap_seekdir,
 	.telldir_fn = vfswrap_telldir,
 	.rewind_dir_fn = vfswrap_rewinddir,
diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
index a51ab75..489a28c 100644
--- a/source3/modules/vfs_full_audit.c
+++ b/source3/modules/vfs_full_audit.c
@@ -171,6 +171,7 @@ typedef enum _vfs_op_type {
 	SMB_VFS_OP_COPY_CHUNK_RECV,
 	SMB_VFS_OP_GET_COMPRESSION,
 	SMB_VFS_OP_SET_COMPRESSION,
+	SMB_VFS_OP_READDIR_ATTR,
 
 	/* NT ACL operations. */
 
@@ -295,6 +296,7 @@ static struct {
 	{ SMB_VFS_OP_COPY_CHUNK_RECV,	"copy_chunk_recv" },
 	{ SMB_VFS_OP_GET_COMPRESSION,	"get_compression" },
 	{ SMB_VFS_OP_SET_COMPRESSION,	"set_compression" },
+	{ SMB_VFS_OP_READDIR_ATTR,      "readdir_attr" },
 	{ SMB_VFS_OP_FGET_NT_ACL,	"fget_nt_acl" },
 	{ SMB_VFS_OP_GET_NT_ACL,	"get_nt_acl" },
 	{ SMB_VFS_OP_FSET_NT_ACL,	"fset_nt_acl" },
@@ -1834,6 +1836,21 @@ static NTSTATUS smb_full_audit_set_compression(vfs_handle_struct *handle,
 	return result;
 }
 
+static NTSTATUS smb_full_audit_readdir_attr(struct vfs_handle_struct *handle,
+					    const struct smb_filename *fname,
+					    TALLOC_CTX *mem_ctx,
+					    struct readdir_attr_data **pattr_data)
+{
+	NTSTATUS status;
+
+	status = SMB_VFS_NEXT_READDIR_ATTR(handle, fname, mem_ctx, pattr_data);
+
+	do_log(SMB_VFS_OP_READDIR_ATTR, NT_STATUS_IS_OK(status), handle, "%s",
+	       smb_fname_str_do_log(fname));
+
+	return status;
+}
+
 static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
 					   uint32 security_info,
 					   TALLOC_CTX *mem_ctx,
@@ -2249,6 +2266,7 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
 	.copy_chunk_recv_fn = smb_full_audit_copy_chunk_recv,
 	.get_compression_fn = smb_full_audit_get_compression,
 	.set_compression_fn = smb_full_audit_set_compression,
+	.readdir_attr_fn = smb_full_audit_readdir_attr,
 	.fget_nt_acl_fn = smb_full_audit_fget_nt_acl,
 	.get_nt_acl_fn = smb_full_audit_get_nt_acl,
 	.fset_nt_acl_fn = smb_full_audit_fset_nt_acl,
diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c
index 9dbbf8b..243238a 100644
--- a/source3/modules/vfs_time_audit.c
+++ b/source3/modules/vfs_time_audit.c
@@ -1802,6 +1802,27 @@ static NTSTATUS smb_time_audit_set_compression(vfs_handle_struct *handle,
 	return result;
 }
 
+static NTSTATUS smb_time_audit_readdir_attr(struct vfs_handle_struct *handle,
+					    const struct smb_filename *fname,
+					    TALLOC_CTX *mem_ctx,
+					    struct readdir_attr_data **pattr_data)
+{
+	NTSTATUS status;
+	struct timespec ts1,ts2;
+	double timediff;
+
+	clock_gettime_mono(&ts1);
+	status = SMB_VFS_NEXT_READDIR_ATTR(handle, fname, mem_ctx, pattr_data);
+	clock_gettime_mono(&ts2);
+	timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9;
+
+	if (timediff > audit_timeout) {
+		smb_time_audit_log_smb_fname("readdir_attr", timediff, fname);
+	}
+
+	return status;
+}
+
 static NTSTATUS smb_time_audit_fget_nt_acl(vfs_handle_struct *handle,
 					   files_struct *fsp,
 					   uint32 security_info,
@@ -2423,6 +2444,7 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
 	.copy_chunk_recv_fn = smb_time_audit_copy_chunk_recv,
 	.get_compression_fn = smb_time_audit_get_compression,
 	.set_compression_fn = smb_time_audit_set_compression,
+	.readdir_attr_fn = smb_time_audit_readdir_attr,
 	.fget_nt_acl_fn = smb_time_audit_fget_nt_acl,
 	.get_nt_acl_fn = smb_time_audit_get_nt_acl,
 	.fset_nt_acl_fn = smb_time_audit_fset_nt_acl,
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 8e33f2d..4b96963 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -2461,3 +2461,12 @@ NTSTATUS smb_vfs_call_durable_reconnect(struct vfs_handle_struct *handle,
 					         old_cookie, mem_ctx, fsp,
 					         new_cookie);
 }
+
+NTSTATUS smb_vfs_call_readdir_attr(struct vfs_handle_struct *handle,
+				   const struct smb_filename *fname,
+				   TALLOC_CTX *mem_ctx,
+				   struct readdir_attr_data **attr_data)
+{
+	VFS_FIND(readdir_attr);
+	return handle->fns->readdir_attr_fn(handle, fname, mem_ctx, attr_data);
+}
-- 
1.9.3


From c8d4e529491afaddd83cc9f6bf7ae3c0798f2811 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 28 Nov 2014 11:44:09 +0100
Subject: [PATCH 02/12] s3:smbd: allocate out_context_blobs with talloc

By tallocing the out_context_blobs instead of using an automatic stack
variable, we can use out_context_blobs as talloc parent for individual
create tag that we add via smb2_create_blob_add().

This is in preperation of a SMB_VFS_CREATE_FILE modification where I add
the in and out_context_blobs as additional args. With this change in
place we can add create tags to out_context_blobs from there too.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 35 ++++++++++++++++++++---------------
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 1e31cbf..052025b 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -388,7 +388,7 @@ struct smbd_smb2_create_state {
 	uint32_t out_file_attributes;
 	uint64_t out_file_id_persistent;
 	uint64_t out_file_id_volatile;
-	struct smb2_create_blobs out_context_blobs;
+	struct smb2_create_blobs *out_context_blobs;
 };
 
 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
@@ -410,7 +410,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smb_request *smb1req = NULL;
 	files_struct *result = NULL;
 	int info;
-	struct smb2_create_blobs out_context_blobs;
 	int requested_oplock_level;
 	struct smb2_create_blob *dhnc = NULL;
 	struct smb2_create_blob *dh2c = NULL;
@@ -418,8 +417,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smb2_create_blob *dh2q = NULL;
 	struct smbXsrv_open *op = NULL;
 
-	ZERO_STRUCT(out_context_blobs);
-
 	if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
 		requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 	} else {
@@ -450,10 +447,16 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		state = tevent_req_data(req,
 				struct smbd_smb2_create_state);
 		smb1req = state->smb1req;
+		TALLOC_FREE(state->out_context_blobs);
 		DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
 			in_name ));
 	}
 
+	state->out_context_blobs = talloc_zero(state, struct smb2_create_blobs);
+	if (tevent_req_nomem(state->out_context_blobs, req)) {
+		return tevent_req_post(req, ev);
+	}
+
 	dhnq = smb2_create_blob_find(&in_context_blobs,
 				     SMB2_CREATE_TAG_DHNQ);
 	dhnc = smb2_create_blob_find(&in_context_blobs,
@@ -986,10 +989,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				SIVAL(p, 0, NT_STATUS_V(status));
 				SIVAL(p, 4, max_access_granted);
 
-				status = smb2_create_blob_add(state,
-							&out_context_blobs,
-							SMB2_CREATE_TAG_MXAC,
-							blob);
+				status = smb2_create_blob_add(
+				    state->out_context_blobs,
+				    state->out_context_blobs,
+				    SMB2_CREATE_TAG_MXAC,
+				    blob);
 				if (!NT_STATUS_IS_OK(status)) {
 					tevent_req_nterror(req, status);
 					return tevent_req_post(req, ev);
@@ -1031,8 +1035,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			uint8_t p[8] = { 0, };
 			DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
-			status = smb2_create_blob_add(state,
-						      &out_context_blobs,
+			status = smb2_create_blob_add(state->out_context_blobs,
+						      state->out_context_blobs,
 						      SMB2_CREATE_TAG_DHNQ,
 						      blob);
 			if (!NT_STATUS_IS_OK(status)) {
@@ -1049,7 +1053,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			SIVAL(p, 0, op->global->durable_timeout_msec);
 			SIVAL(p, 4, durable_v2_response_flags);
 
-			status = smb2_create_blob_add(state, &out_context_blobs,
+			status = smb2_create_blob_add(state->out_context_blobs,
+						      state->out_context_blobs,
 						      SMB2_CREATE_TAG_DH2Q,
 						      blob);
 			if (!NT_STATUS_IS_OK(status)) {
@@ -1073,7 +1078,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			SBVAL(p, 0, file_index);
 			SIVAL(p, 8, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
 
-			status = smb2_create_blob_add(state, &out_context_blobs,
+			status = smb2_create_blob_add(state->out_context_blobs,
+						      state->out_context_blobs,
 						      SMB2_CREATE_TAG_QFID,
 						      blob);
 			if (!NT_STATUS_IS_OK(status)) {
@@ -1115,7 +1121,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	}
 	state->out_file_id_persistent = result->op->global->open_persistent_id;
 	state->out_file_id_volatile = result->op->global->open_volatile_id;
-	state->out_context_blobs = out_context_blobs;
 
 	DEBUG(10,("smbd_smb2_create_send: %s - %s\n",
 		  fsp_str_dbg(result), fsp_fnum_dbg(result)));
@@ -1159,9 +1164,9 @@ static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
 	*out_file_attributes	= state->out_file_attributes;
 	*out_file_id_persistent	= state->out_file_id_persistent;
 	*out_file_id_volatile	= state->out_file_id_volatile;
-	*out_context_blobs	= state->out_context_blobs;
+	*out_context_blobs	= *(state->out_context_blobs);
 
-	talloc_steal(mem_ctx, state->out_context_blobs.blobs);
+	talloc_steal(mem_ctx, state->out_context_blobs->blobs);
 
 	tevent_req_received(req);
 	return NT_STATUS_OK;
-- 
1.9.3


From b428a4488eee7730372ba6fbf8b351ad8344217e Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 26 Nov 2014 14:12:51 +0100
Subject: [PATCH 03/12] s3:vfs: add create tags to SMB_VFS_CREATEFILE

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 examples/VFS/skel_opaque.c                |  4 +++-
 examples/VFS/skel_transparent.c           |  7 +++++--
 source3/include/vfs.h                     |  9 +++++++--
 source3/include/vfs_macros.h              | 12 +++++++-----
 source3/modules/vfs_default.c             |  6 ++++--
 source3/modules/vfs_fruit.c               |  7 +++++--
 source3/modules/vfs_full_audit.c          |  7 +++++--
 source3/modules/vfs_media_harmony.c       | 12 +++++++++---
 source3/modules/vfs_time_audit.c          |  7 +++++--
 source3/modules/vfs_worm.c                |  7 +++++--
 source3/printing/nt_printing.c            |  9 ++++++---
 source3/rpc_server/srvsvc/srv_srvsvc_nt.c |  6 ++++--
 source3/smbd/dosmode.c                    |  3 ++-
 source3/smbd/nttrans.c                    | 12 ++++++++----
 source3/smbd/open.c                       | 10 +++++++---
 source3/smbd/proto.h                      |  6 ++++--
 source3/smbd/reply.c                      | 30 ++++++++++++++++++++----------
 source3/smbd/smb2_create.c                |  4 +++-
 source3/smbd/trans2.c                     | 18 ++++++++++++------
 source3/smbd/vfs.c                        |  6 ++++--
 20 files changed, 125 insertions(+), 57 deletions(-)

diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c
index 6e15a06..b52c381 100644
--- a/examples/VFS/skel_opaque.c
+++ b/examples/VFS/skel_opaque.c
@@ -174,7 +174,9 @@ static NTSTATUS skel_create_file(struct vfs_handle_struct *handle,
 				 uint32_t private_flags,
 				 struct security_descriptor *sd,
 				 struct ea_list *ea_list,
-				 files_struct **result, int *pinfo)
+				 files_struct **result, int *pinfo,
+				 const struct smb2_create_blobs *in_context_blobs,
+				 struct smb2_create_blobs *out_context_blobs)
 {
 	return NT_STATUS_NOT_IMPLEMENTED;
 }
diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c
index b11e29c..925e520 100644
--- a/examples/VFS/skel_transparent.c
+++ b/examples/VFS/skel_transparent.c
@@ -169,7 +169,9 @@ static NTSTATUS skel_create_file(struct vfs_handle_struct *handle,
 				 uint32_t private_flags,
 				 struct security_descriptor *sd,
 				 struct ea_list *ea_list,
-				 files_struct ** result, int *pinfo)
+				 files_struct ** result, int *pinfo,
+				 const struct smb2_create_blobs *in_context_blobs,
+				 struct smb2_create_blobs *out_context_blobs)
 {
 	return SMB_VFS_NEXT_CREATE_FILE(handle,
 					req,
@@ -184,7 +186,8 @@ static NTSTATUS skel_create_file(struct vfs_handle_struct *handle,
 					lease,
 					allocation_size,
 					private_flags,
-					sd, ea_list, result, pinfo);
+					sd, ea_list, result, pinfo,
+					in_context_blobs, out_context_blobs);
 }
 
 static int skel_close_fn(vfs_handle_struct *handle, files_struct *fsp)
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index e443b96..2f31655 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -160,6 +160,7 @@
 /* Version 32 - Add "lease" to CREATE_FILE operation */
 /* Version 32 - Add "lease" to struct files_struct */
 /* Version 32 - Add SMB_VFS_READDIR_ATTR() */
+/* Version 32 - Add in and our create context blobs to create_file */
 
 #define SMB_VFS_INTERFACE_VERSION 32
 
@@ -551,7 +552,9 @@ struct vfs_fn_pointers {
 				   struct security_descriptor *sd,
 				   struct ea_list *ea_list,
 				   files_struct **result,
-				   int *pinfo);
+				   int *pinfo,
+				   const struct smb2_create_blobs *in_context_blobs,
+				   struct smb2_create_blobs *out_context_blobs);
 	int (*close_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp);
 	ssize_t (*read_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, void *data, size_t n);
 	ssize_t (*pread_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, void *data, size_t n, off_t offset);
@@ -962,7 +965,9 @@ NTSTATUS smb_vfs_call_create_file(struct vfs_handle_struct *handle,
 				  struct security_descriptor *sd,
 				  struct ea_list *ea_list,
 				  files_struct **result,
-				  int *pinfo);
+				  int *pinfo,
+				  const struct smb2_create_blobs *in_context_blobs,
+				  struct smb2_create_blobs *out_context_blobs);
 int smb_vfs_call_close(struct vfs_handle_struct *handle,
 		       struct files_struct *fsp);
 ssize_t smb_vfs_call_read(struct vfs_handle_struct *handle,
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index df676ad..ef97b49 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -136,13 +136,15 @@
 	smb_vfs_call_open((handle)->next, (fname), (fsp), (flags), (mode))
 
 #define SMB_VFS_CREATE_FILE(conn, req, root_dir_fid, smb_fname, access_mask, share_access, create_disposition, \
-	create_options, file_attributes, oplock_request, lease, allocation_size, private_flags, sd, ea_list, result, pinfo) \
-	smb_vfs_call_create_file((conn)->vfs_handles, (req), (root_dir_fid), (smb_fname), (access_mask), (share_access), (create_disposition), \
-	(create_options), (file_attributes), (oplock_request), (lease), (allocation_size), (private_flags), (sd), (ea_list), (result), (pinfo))
+        create_options, file_attributes, oplock_request, lease, allocation_size, private_flags, sd, ea_list, result, pinfo, in_context_blobs, out_context_blobs) \
+        smb_vfs_call_create_file((conn)->vfs_handles, (req), (root_dir_fid), (smb_fname), (access_mask), (share_access), (create_disposition), \
+        (create_options), (file_attributes), (oplock_request), (lease), (allocation_size), (private_flags), (sd), (ea_list), (result), (pinfo), \
+	(in_context_blobs), (out_context_blobs))
 #define SMB_VFS_NEXT_CREATE_FILE(handle, req, root_dir_fid, smb_fname, access_mask, share_access, create_disposition, \
-	create_options, file_attributes, oplock_request, lease, allocation_size, private_flags, sd, ea_list, result, pinfo) \
+	create_options, file_attributes, oplock_request, lease, allocation_size, private_flags, sd, ea_list, result, pinfo, in_context_blobs, out_context_blobs) \
 	smb_vfs_call_create_file((handle)->next, (req), (root_dir_fid), (smb_fname), (access_mask), (share_access), (create_disposition), \
-	(create_options), (file_attributes), (oplock_request), (lease), (allocation_size), (private_flags), (sd), (ea_list), (result), (pinfo))
+        (create_options), (file_attributes), (oplock_request), (lease), (allocation_size), (private_flags), (sd), (ea_list), (result), (pinfo), \
+	(in_context_blobs), (out_context_blobs))
 
 #define SMB_VFS_CLOSE(fsp) \
 	smb_vfs_call_close((fsp)->conn->vfs_handles, (fsp))
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 7610e65..613101a 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -531,7 +531,9 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
 				    struct security_descriptor *sd,
 				    struct ea_list *ea_list,
 				    files_struct **result,
-				    int *pinfo)
+				    int *pinfo,
+				    const struct smb2_create_blobs *in_context_blobs,
+				    struct smb2_create_blobs *out_context_blobs)
 {
 	return create_file_default(handle->conn, req, root_dir_fid, smb_fname,
 				   access_mask, share_access,
@@ -539,7 +541,7 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
 				   file_attributes, oplock_request, lease,
 				   allocation_size, private_flags,
 				   sd, ea_list, result,
-				   pinfo);
+				   pinfo, in_context_blobs, out_context_blobs);
 }
 
 static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp)
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index da1ec7f..9af2043 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -2874,7 +2874,9 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
 				  struct security_descriptor *sd,
 				  struct ea_list *ea_list,
 				  files_struct **result,
-				  int *pinfo)
+				  int *pinfo,
+				  const struct smb2_create_blobs *in_context_blobs,
+				  struct smb2_create_blobs *out_context_blobs)
 {
 	NTSTATUS status;
 	struct fruit_config_data *config = NULL;
@@ -2887,7 +2889,8 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
 		lease,
 		allocation_size, private_flags,
 		sd, ea_list, result,
-		pinfo);
+		pinfo,
+		in_context_blobs, out_context_blobs);
 
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
index 489a28c..c5a9c0d 100644
--- a/source3/modules/vfs_full_audit.c
+++ b/source3/modules/vfs_full_audit.c
@@ -871,7 +871,9 @@ static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle,
 				      struct security_descriptor *sd,
 				      struct ea_list *ea_list,
 				      files_struct **result_fsp,
-				      int *pinfo)
+				      int *pinfo,
+				      const struct smb2_create_blobs *in_context_blobs,
+				      struct smb2_create_blobs *out_context_blobs)
 {
 	NTSTATUS result;
 	const char* str_create_disposition;
@@ -916,7 +918,8 @@ static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle,
 		sd,					/* sd */
 		ea_list,				/* ea_list */
 		result_fsp,				/* result */
-		pinfo);					/* pinfo */
+		pinfo,					/* pinfo */
+		in_context_blobs, out_context_blobs);	/* create context */
 
 	do_log(SMB_VFS_OP_CREATE_FILE, (NT_STATUS_IS_OK(result)), handle,
 	       "0x%x|%s|%s|%s", access_mask,
diff --git a/source3/modules/vfs_media_harmony.c b/source3/modules/vfs_media_harmony.c
index 2418349..f1264c7 100644
--- a/source3/modules/vfs_media_harmony.c
+++ b/source3/modules/vfs_media_harmony.c
@@ -1210,7 +1210,9 @@ static NTSTATUS mh_create_file(vfs_handle_struct *handle,
 		struct security_descriptor *sd,
 		struct ea_list *ea_list,
 		files_struct **result_fsp,
-		int *pinfo)
+		int *pinfo,
+		const struct smb2_create_blobs *in_context_blobs,
+		struct smb2_create_blobs *out_context_blobs)
 {
 	NTSTATUS status;
 	struct smb_filename *clientFname;
@@ -1238,7 +1240,9 @@ static NTSTATUS mh_create_file(vfs_handle_struct *handle,
 			sd,
 			ea_list,
 			result_fsp,
-			pinfo);
+			pinfo,
+			in_context_blobs,
+			out_context_blobs);
 		goto out;
 	}
 
@@ -1275,7 +1279,9 @@ static NTSTATUS mh_create_file(vfs_handle_struct *handle,
 		sd,
 		ea_list,
 		result_fsp,
-		pinfo);
+		pinfo,
+		in_context_blobs,
+		out_context_blobs);
 err:
 	TALLOC_FREE(clientFname);
 out:
diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c
index 243238a..4ce9238 100644
--- a/source3/modules/vfs_time_audit.c
+++ b/source3/modules/vfs_time_audit.c
@@ -502,7 +502,9 @@ static NTSTATUS smb_time_audit_create_file(vfs_handle_struct *handle,
 					   struct security_descriptor *sd,
 					   struct ea_list *ea_list,
 					   files_struct **result_fsp,
-					   int *pinfo)
+					   int *pinfo,
+					   const struct smb2_create_blobs *in_context_blobs,
+					   struct smb2_create_blobs *out_context_blobs)
 {
 	NTSTATUS result;
 	struct timespec ts1,ts2;
@@ -526,7 +528,8 @@ static NTSTATUS smb_time_audit_create_file(vfs_handle_struct *handle,
 		sd,					/* sd */
 		ea_list,				/* ea_list */
 		result_fsp,				/* result */
-		pinfo);
+		pinfo,
+		in_context_blobs, out_context_blobs);   /* create context */
 	clock_gettime_mono(&ts2);
 	timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9;
 
diff --git a/source3/modules/vfs_worm.c b/source3/modules/vfs_worm.c
index 3097419..9638d96 100644
--- a/source3/modules/vfs_worm.c
+++ b/source3/modules/vfs_worm.c
@@ -38,7 +38,9 @@ static NTSTATUS vfs_worm_create_file(vfs_handle_struct *handle,
 				     struct security_descriptor *sd,
 				     struct ea_list *ea_list,
 				     files_struct **result,
-				     int *pinfo)
+				     int *pinfo,
+				     const struct smb2_create_blobs *in_context_blobs,
+				     struct smb2_create_blobs *out_context_blobs)
 {
 	bool readonly = false;
 	const uint32_t write_access_flags =
@@ -64,7 +66,8 @@ static NTSTATUS vfs_worm_create_file(vfs_handle_struct *handle,
 		handle, req, root_dir_fid, smb_fname, access_mask,
 		share_access, create_disposition, create_options,
 		file_attributes, oplock_request, lease, allocation_size,
-		private_flags, sd, ea_list, result, pinfo);
+		private_flags, sd, ea_list, result, pinfo,
+		in_context_blobs, out_context_blobs);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index 3a3a339..137df16 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -537,7 +537,8 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);                            /* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		/* Old file not found, so by definition new file is in fact newer */
@@ -591,7 +592,8 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		/* New file not found, this shouldn't occur if the caller did its job */
@@ -770,7 +772,8 @@ static uint32 get_correct_cversion(struct auth_session_info *session_info,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
index 5c26f15..7e42272 100644
--- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
@@ -2364,7 +2364,8 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		DEBUG(3,("_srvsvc_NetGetFileSecurity: can't open %s\n",
@@ -2512,7 +2513,8 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		DEBUG(3,("_srvsvc_NetSetFileSecurity: can't open %s\n",
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 162684b..6fd5d69 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -1147,7 +1147,8 @@ static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
 		NULL,                                   /* sd */
 		NULL,                                   /* ea_list */
 		ret_fsp,                                /* result */
-		NULL);                                  /* pinfo */
+		NULL,                                   /* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (NT_STATUS_IS_OK(status)) {
 		*need_close = true;
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index edad3e4..4423a44 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -579,7 +579,8 @@ void reply_ntcreate_and_X(struct smb_request *req)
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		&info);					/* pinfo */
+		&info,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
@@ -1186,7 +1187,8 @@ static void call_nt_transact_create(connection_struct *conn,
 		sd,					/* sd */
 		ea_list,				/* ea_list */
 		&fsp,					/* result */
-		&info);					/* pinfo */
+		&info,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if(!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
@@ -1430,7 +1432,8 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp1,					/* result */
-		&info);					/* pinfo */
+		&info,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		goto out;
@@ -1455,7 +1458,8 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp2,					/* result */
-		&info);					/* pinfo */
+		&info,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		close_file(NULL, fsp1, ERROR_CLOSE);
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 1952823..40c6108 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -3408,7 +3408,8 @@ NTSTATUS create_directory(connection_struct *conn, struct smb_request *req,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (NT_STATUS_IS_OK(status)) {
 		close_file(req, fsp, NORMAL_CLOSE);
@@ -3587,7 +3588,8 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
 			 NULL,			/* sd */
 			 NULL,			/* ea_list */
 			 &streams[i],		/* result */
-			 NULL);			/* pinfo */
+			 NULL,			/* pinfo */
+			 NULL, NULL);		/* create context */
 
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(10, ("Could not open stream %s: %s\n",
@@ -4344,7 +4346,9 @@ NTSTATUS create_file_default(connection_struct *conn,
 			     struct security_descriptor *sd,
 			     struct ea_list *ea_list,
 			     files_struct **result,
-			     int *pinfo)
+			     int *pinfo,
+			     const struct smb2_create_blobs *in_context_blobs,
+			     struct smb2_create_blobs *out_context_blobs)
 {
 	int info = FILE_WAS_OPENED;
 	files_struct *fsp = NULL;
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 1080895..ec2e01b9 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -636,9 +636,11 @@ NTSTATUS create_file_default(connection_struct *conn,
 			     uint32_t private_flags,
 			     struct security_descriptor *sd,
 			     struct ea_list *ea_list,
-
 			     files_struct **result,
-			     int *pinfo);
+			     int *pinfo,
+			     const struct smb2_create_blobs *in_context_blobs,
+			     struct smb2_create_blobs *out_context_blobs);
+
 NTSTATUS get_relative_fid_filename(connection_struct *conn,
 				   struct smb_request *req,
 				   uint16_t root_dir_fid,
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 9b3ed65..fd4ec53 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -2009,7 +2009,8 @@ void reply_open(struct smb_request *req)
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		&info);					/* pinfo */
+		&info,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
@@ -2178,7 +2179,8 @@ void reply_open_and_X(struct smb_request *req)
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		&smb_action);				/* pinfo */
+		&smb_action,				/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
@@ -2426,7 +2428,8 @@ void reply_mknew(struct smb_request *req)
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
@@ -2554,7 +2557,8 @@ void reply_ctemp(struct smb_request *req)
 			NULL,					/* sd */
 			NULL,					/* ea_list */
 			&fsp,					/* result */
-			NULL);					/* pinfo */
+			NULL,					/* pinfo */
+			NULL, NULL);				/* create context */
 
 		if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
 			TALLOC_FREE(fname);
@@ -2772,7 +2776,8 @@ static NTSTATUS do_unlink(connection_struct *conn,
 		 NULL,			/* sd */
 		 NULL,			/* ea_list */
 		 &fsp,			/* result */
-		 NULL);			/* pinfo */
+		 NULL,			/* pinfo */
+		 NULL, NULL);		/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n",
@@ -6039,7 +6044,8 @@ void reply_rmdir(struct smb_request *req)
 		NULL,                                   /* sd */
 		NULL,                                   /* ea_list */
 		&fsp,                                   /* result */
-		&info);                                 /* pinfo */
+		&info,                                  /* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
@@ -6807,7 +6813,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 			NULL,				/* sd */
 			NULL,				/* ea_list */
 			&fsp,				/* result */
-			NULL);				/* pinfo */
+			NULL,				/* pinfo */
+			NULL, NULL);			/* create context */
 
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(3, ("Could not open rename source %s: %s\n",
@@ -6954,7 +6961,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 			NULL,				/* sd */
 			NULL,				/* ea_list */
 			&fsp,				/* result */
-			NULL);				/* pinfo */
+			NULL,				/* pinfo */
+			NULL, NULL);			/* create context */
 
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
@@ -7224,7 +7232,8 @@ NTSTATUS copy_file(TALLOC_CTX *ctx,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp1,					/* result */
-		NULL);					/* psbuf */
+		NULL,					/* psbuf */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		goto out;
@@ -7254,7 +7263,8 @@ NTSTATUS copy_file(TALLOC_CTX *ctx,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp2,					/* result */
-		NULL);					/* psbuf */
+		NULL,					/* psbuf */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		close_file(NULL, fsp1, ERROR_CLOSE);
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 052025b..3fba3db 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -951,7 +951,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 						     sec_desc,
 						     ea_list,
 						     &result,
-						     &info);
+						     &info,
+						     &in_context_blobs,
+						     state->out_context_blobs);
 			if (!NT_STATUS_IS_OK(status)) {
 				if (open_was_deferred(smb1req->xconn, smb1req->mid)) {
 					SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 60128ef..e2640e4 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1227,7 +1227,8 @@ static void call_trans2open(connection_struct *conn,
 		NULL,					/* sd */
 		ea_list,				/* ea_list */
 		&fsp,					/* result */
-		&smb_action);				/* psbuf */
+		&smb_action,				/* psbuf */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		if (open_was_deferred(req->xconn, req->mid)) {
@@ -5995,7 +5996,8 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&new_fsp,				/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	TALLOC_FREE(smb_fname_tmp);
 
@@ -6981,7 +6983,8 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&new_fsp,				/* result */
-		NULL);					/* pinfo */
+		NULL,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		/* NB. We check for open_was_deferred in the caller. */
@@ -7497,7 +7500,8 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		&info);					/* pinfo */
+		&info,					/* pinfo */
+		NULL, NULL);				/* create context */
 
         if (NT_STATUS_IS_OK(status)) {
                 close_file(req, fsp, NORMAL_CLOSE);
@@ -7730,7 +7734,8 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		&info);					/* pinfo */
+		&info,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
@@ -7861,7 +7866,8 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
 		NULL,					/* sd */
 		NULL,					/* ea_list */
 		&fsp,					/* result */
-		&info);					/* pinfo */
+		&info,					/* pinfo */
+		NULL, NULL);				/* create context */
 
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 4b96963..51362c3 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -1545,7 +1545,9 @@ NTSTATUS smb_vfs_call_create_file(struct vfs_handle_struct *handle,
 				  struct security_descriptor *sd,
 				  struct ea_list *ea_list,
 				  files_struct **result,
-				  int *pinfo)
+				  int *pinfo,
+				  const struct smb2_create_blobs *in_context_blobs,
+				  struct smb2_create_blobs *out_context_blobs)
 {
 	VFS_FIND(create_file);
 	return handle->fns->create_file_fn(
@@ -1553,7 +1555,7 @@ NTSTATUS smb_vfs_call_create_file(struct vfs_handle_struct *handle,
 		share_access, create_disposition, create_options,
 		file_attributes, oplock_request, lease, allocation_size,
 		private_flags, sd, ea_list,
-		result, pinfo);
+		result, pinfo, in_context_blobs, out_context_blobs);
 }
 
 int smb_vfs_call_close(struct vfs_handle_struct *handle,
-- 
1.9.3


From f39a292454c4103fe657cad082a7f12799194a39 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Fri, 22 Aug 2014 03:48:50 +0200
Subject: [PATCH 04/12] s3:smbd: add SMB2 AAPL create context defines

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 libcli/smb/smb2_constants.h  |  1 +
 libcli/smb/smb2_create_ctx.h | 46 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)
 create mode 100644 libcli/smb/smb2_create_ctx.h

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


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

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

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


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

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

diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
index 8304b20..a75942c 100644
--- a/libcli/security/security_descriptor.c
+++ b/libcli/security/security_descriptor.c
@@ -595,3 +595,25 @@ struct security_ace *security_ace_create(TALLOC_CTX *mem_ctx,
 
 	return ace;
 }
+
+/*******************************************************************
+ Check for MS NFS ACEs in a sd
+*******************************************************************/
+bool security_descriptor_with_ms_nfs(const struct security_descriptor *psd)
+{
+	int i;
+
+	if (psd->dacl == NULL) {
+		return false;
+	}
+
+	for (i = 0; i < psd->dacl->num_aces; i++) {
+		if (dom_sid_compare_domain(
+			    &global_sid_Unix_NFS,
+			    &psd->dacl->aces[i].trustee) == 0) {
+			return true;
+		}
+	}
+
+	return false;
+}
diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h
index 1c7f893..87643bc 100644
--- a/libcli/security/security_descriptor.h
+++ b/libcli/security/security_descriptor.h
@@ -81,4 +81,6 @@ struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx,
 						       struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */
 						       uint32_t (*generic_map)(uint32_t access_mask));
 
+bool security_descriptor_with_ms_nfs(const struct security_descriptor *psd);
+
 #endif /* __SECURITY_DESCRIPTOR_H__ */
-- 
1.9.3


From 9f3e3033e90156078df457ae3e1e533387e56aee Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 26 Nov 2014 18:01:37 +0100
Subject: [PATCH 07/12] s3:smbd: ignore dacls with MS NFS ACEs

Ignore NFS ACEs in code the modifies
* default POSIX ACLs
* VFS: NFSv4 ACLs
* VFS: xattr and tdb ACLs

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/modules/nfs4_acls.c      |  3 +++
 source3/modules/vfs_acl_common.c |  9 +++++++++
 source3/smbd/posix_acls.c        | 10 ++++++++++
 3 files changed, 22 insertions(+)

diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c
index cf61af9..1aa819a 100644
--- a/source3/modules/nfs4_acls.c
+++ b/source3/modules/nfs4_acls.c
@@ -778,6 +778,9 @@ static bool smbacl4_fill_ace4(
 			ace_v4->who.gid = gid;
 		} else if (sid_to_uid(&ace_nt->trustee, &uid)) {
 			ace_v4->who.uid = uid;
+		} else if (dom_sid_compare_domain(&ace_nt->trustee,
+						  &global_sid_Unix_NFS) == 0) {
+			return false;
 		} else {
 			DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
 				  "convert %s to uid or gid\n",
diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index b749157..920c811 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -775,6 +775,15 @@ static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
 		psd->group_sid = orig_psd->group_sid;
 	}
 	if (security_info_sent & SECINFO_DACL) {
+		if (security_descriptor_with_ms_nfs(orig_psd)) {
+			/*
+			 * If the sd contains a MS NFS SID, do
+			 * nothing, it's a chmod() request from OS X
+			 * with AAPL context.
+			 */
+			TALLOC_FREE(frame);
+			return NT_STATUS_OK;
+		}
 		psd->dacl = orig_psd->dacl;
 		psd->type |= SEC_DESC_DACL_PRESENT;
 	}
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 126b822..6a5ec85 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -3666,6 +3666,16 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
+	/*
+	 * MS NFS mode, here's the deal: the client merely wants to
+	 * modify the mode, but roundtripping get_acl/set/acl would
+	 * add additional POSIX ACEs.  So in case we get a request
+	 * containing a MS NFS mode SID, we do nothing here.
+	 */
+	if (security_descriptor_with_ms_nfs(psd_orig)) {
+		return NT_STATUS_OK;
+	}
+
 	psd = security_descriptor_copy(talloc_tos(), psd_orig);
 	if (psd == NULL) {
 		return NT_STATUS_NO_MEMORY;
-- 
1.9.3


From 619056c0096054cb56db54d5a35fe680698a2ff3 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 26 Nov 2014 18:11:17 +0100
Subject: [PATCH 08/12] vfs_fruit: AAPL support

* readdir_attr VFS functions, used in trans2 when marshalling
  metadata associated with a directory entry

* support for reading and writing UNIX mode via MS NFS ACEs in NT ACL

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

diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 9af2043..f8ea33f 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -28,6 +28,7 @@
 #include "smbd/globals.h"
 #include "messages.h"
 #include "libcli/security/security.h"
+#include "../libcli/smb/smb2_create_ctx.h"
 
 /*
  * Enhanced OS X and Netatalk compatibility
@@ -121,6 +122,20 @@ struct fruit_config_data {
 	enum fruit_meta meta;
 	enum fruit_locking locking;
 	enum fruit_encoding encoding;
+	bool use_aapl;
+	bool readdir_attr_enabled;
+	bool unix_info_enabled;
+
+	/*
+	 * Additional undocumented options, all enabled by default,
+	 * possibly useful for analyzing performance. The associated
+	 * operations with each of them may be expensive, so having
+	 * the chance to disable them individually gives a chance
+	 * tweaking the setup for the particular usecase.
+	 */
+	bool readdir_attr_rsize;
+	bool readdir_attr_finder_info;
+	bool readdir_attr_max_access;
 };
 
 static const struct enum_list fruit_rsrc[] = {
@@ -1250,6 +1265,25 @@ static int init_fruit_config(vfs_handle_struct *handle)
 	}
 	config->encoding = (enum fruit_encoding)enumval;
 
+	if (lp_parm_bool(-1, FRUIT_PARAM_TYPE_NAME, "aapl", true)) {
+		config->use_aapl = true;
+	}
+
+	if (lp_parm_bool(SNUM(handle->conn),
+			 "readdir_attr", "aapl_rsize", true)) {
+		config->readdir_attr_rsize = true;
+	}
+
+	if (lp_parm_bool(SNUM(handle->conn),
+			 "readdir_attr", "aapl_finder_info", true)) {
+		config->readdir_attr_finder_info = true;
+	}
+
+	if (lp_parm_bool(SNUM(handle->conn),
+			 "readdir_attr", "aapl_max_access", true)) {
+		config->readdir_attr_max_access = true;
+	}
+
 	SMB_VFS_HANDLE_SET_DATA(handle, config,
 				NULL, struct fruit_config_data,
 				return -1);
@@ -1662,6 +1696,232 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
 	return status;
 }
 
+static NTSTATUS check_aapl(vfs_handle_struct *handle,
+			   struct smb_request *req,
+			   const struct smb2_create_blobs *in_context_blobs,
+			   struct smb2_create_blobs *out_context_blobs)
+{
+	struct fruit_config_data *config;
+	NTSTATUS status;
+	struct smb2_create_blob *aapl = NULL;
+	uint32_t cmd;
+	bool ok;
+	uint8_t p[16];
+	DATA_BLOB blob = data_blob_talloc(req, NULL, 0);
+	uint64_t req_bitmap, client_caps;
+	uint64_t server_caps = SMB2_CRTCTX_AAPL_UNIX_BASED;
+	smb_ucs2_t *model;
+	size_t modellen;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
+				return NT_STATUS_UNSUCCESSFUL);
+
+	if (!config->use_aapl
+	    || in_context_blobs == NULL
+	    || out_context_blobs == NULL) {
+		return NT_STATUS_OK;
+	}
+
+	aapl = smb2_create_blob_find(in_context_blobs,
+				     SMB2_CREATE_TAG_AAPL);
+	if (aapl == NULL) {
+		return NT_STATUS_OK;
+	}
+
+	if (aapl->data.length != 24) {
+		DEBUG(1, ("unexpected AAPL ctxt legnth: %ju\n",
+			  (uintmax_t)aapl->data.length));
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	cmd = IVAL(aapl->data.data, 0);
+	if (cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) {
+		DEBUG(1, ("unsupported AAPL cmd: %d\n", cmd));
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	req_bitmap = BVAL(aapl->data.data, 8);
+	client_caps = BVAL(aapl->data.data, 16);
+
+	SIVAL(p, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY);
+	SIVAL(p, 4, 0);
+	SBVAL(p, 8, req_bitmap);
+	ok = data_blob_append(req, &blob, p, 16);
+	if (!ok) {
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+
+	if (req_bitmap & SMB2_CRTCTX_AAPL_SERVER_CAPS) {
+		if ((client_caps & SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR) &&
+		    (handle->conn->tcon->compat->fs_capabilities & FILE_NAMED_STREAMS)) {
+			server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR;
+			config->readdir_attr_enabled = true;
+		}
+
+		/*
+		 * The client doesn't set the flag, so we can't check
+		 * for it and just set it unconditionally
+		 */
+		server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE;
+		config->unix_info_enabled = true;
+
+		SBVAL(p, 0, server_caps);
+		ok = data_blob_append(req, &blob, p, 8);
+		if (!ok) {
+			return NT_STATUS_UNSUCCESSFUL;
+		}
+	}
+
+	if (req_bitmap & SMB2_CRTCTX_AAPL_VOLUME_CAPS) {
+		SBVAL(p, 0,
+		      lp_case_sensitive(SNUM(handle->conn->tcon->compat)) ?
+		      SMB2_CRTCTX_AAPL_CASE_SENSITIVE : 0);
+		ok = data_blob_append(req, &blob, p, 8);
+		if (!ok) {
+			return NT_STATUS_UNSUCCESSFUL;
+		}
+	}
+
+	if (req_bitmap & SMB2_CRTCTX_AAPL_MODEL_INFO) {
+		ok = convert_string_talloc(req,
+					   CH_UNIX, CH_UTF16LE,
+					   "Samba", strlen("Samba"),
+					   &model, &modellen);
+		if (!ok) {
+			return NT_STATUS_UNSUCCESSFUL;
+		}
+
+		SIVAL(p, 0, 0);
+		SIVAL(p + 4, 0, modellen);
+		ok = data_blob_append(req, &blob, p, 8);
+		if (!ok) {
+			talloc_free(model);
+			return NT_STATUS_UNSUCCESSFUL;
+		}
+
+		ok = data_blob_append(req, &blob, model, modellen);
+		talloc_free(model);
+		if (!ok) {
+			return NT_STATUS_UNSUCCESSFUL;
+		}
+	}
+
+	status = smb2_create_blob_add(out_context_blobs,
+				      out_context_blobs,
+				      SMB2_CREATE_TAG_AAPL,
+				      blob);
+
+	return status;
+}
+
+static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle,
+				     const struct smb_filename *smb_fname,
+				     struct readdir_attr_data *attr_data)
+{
+	NTSTATUS status = NT_STATUS_OK;
+	uint32_t date_added;
+	struct adouble *ad = NULL;
+	struct fruit_config_data *config = NULL;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data,
+				return NT_STATUS_UNSUCCESSFUL);
+
+
+	/* Ensure we return a default value in the creation_date field */
+	RSIVAL(&attr_data->attr_data.aapl.finder_info, 12, AD_DATE_START);
+
+	/*
+	 * Resource fork length
+	 */
+
+	if (config->readdir_attr_rsize) {
+		ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
+			    ADOUBLE_RSRC);
+		if (ad) {
+			attr_data->attr_data.aapl.rfork_size = ad_getentrylen(
+				ad, ADEID_RFORK);
+			TALLOC_FREE(ad);
+		}
+	}
+
+	/*
+	 * FinderInfo
+	 */
+
+	if (config->readdir_attr_finder_info) {
+		ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
+			    ADOUBLE_META);
+		if (ad) {
+			if (S_ISREG(smb_fname->st.st_ex_mode)) {
+				/* finder_type */
+				memcpy(&attr_data->attr_data.aapl.finder_info[0],
+				       ad_entry(ad, ADEID_FINDERI), 4);
+
+				/* finder_creator */
+				memcpy(&attr_data->attr_data.aapl.finder_info[0] + 4,
+				       ad_entry(ad, ADEID_FINDERI) + 4, 4);
+			}
+
+			/* finder_flags */
+			memcpy(&attr_data->attr_data.aapl.finder_info[0] + 8,
+			       ad_entry(ad, ADEID_FINDERI) + 8, 2);
+
+			/* finder_ext_flags */
+			memcpy(&attr_data->attr_data.aapl.finder_info[0] + 10,
+			       ad_entry(ad, ADEID_FINDERI) + 24, 2);
+
+			/* creation date */
+			date_added = convert_time_t_to_uint32_t(
+				smb_fname->st.st_ex_btime.tv_sec - AD_DATE_DELTA);
+			RSIVAL(&attr_data->attr_data.aapl.finder_info[0], 12, date_added);
+
+			TALLOC_FREE(ad);
+		}
+	}
+
+error:
+	talloc_free(ad);
+	return status;
+}
+
+/* Search MS NFS style ACE with UNIX mode */
+static NTSTATUS check_ms_nfs(vfs_handle_struct *handle,
+			     files_struct *fsp,
+			     const struct security_descriptor *psd,
+			     mode_t *pmode,
+			     bool *pdo_chmod)
+{
+	int i;
+	struct fruit_config_data *config = NULL;
+
+	*pdo_chmod = false;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data,
+				return NT_STATUS_UNSUCCESSFUL);
+
+	if (psd->dacl == NULL || !config->unix_info_enabled) {
+		return NT_STATUS_OK;
+	}
+
+	for (i = 0; i < psd->dacl->num_aces; i++) {
+		if (dom_sid_compare_domain(
+			    &global_sid_Unix_NFS_Mode,
+			    &psd->dacl->aces[i].trustee) == 0) {
+			*pmode = (mode_t)psd->dacl->aces[i].trustee.sub_auths[2];
+			*pmode &= (S_IRWXU | S_IRWXG | S_IRWXO);
+			*pdo_chmod = true;
+
+			DEBUG(10, ("MS NFS chmod request %s, %04o\n",
+				   fsp_str_dbg(fsp), *pmode));
+			break;
+		}
+	}
+
+	return NT_STATUS_OK;
+}
+
 /****************************************************************************
  * VFS ops
  ****************************************************************************/
@@ -2881,6 +3141,14 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
 	NTSTATUS status;
 	struct fruit_config_data *config = NULL;
 
+	status = check_aapl(handle, req, in_context_blobs, out_context_blobs);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
+				return NT_STATUS_UNSUCCESSFUL);
+
 	status = SMB_VFS_NEXT_CREATE_FILE(
 		handle, req, root_dir_fid, smb_fname,
 		access_mask, share_access,
@@ -2889,9 +3157,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
 		lease,
 		allocation_size, private_flags,
 		sd, ea_list, result,
-		pinfo,
-		in_context_blobs, out_context_blobs);
-
+		pinfo, in_context_blobs, out_context_blobs);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -2902,9 +3168,6 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
 		return status;
 	}
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
-				return NT_STATUS_UNSUCCESSFUL);
-
 	if (config->locking == FRUIT_LOCKING_NETATALK) {
 		status = fruit_check_access(
 			handle, *result,
@@ -2928,6 +3191,186 @@ fail:
 	return status;
 }
 
+static NTSTATUS fruit_readdir_attr(struct vfs_handle_struct *handle,
+				   const struct smb_filename *fname,
+				   TALLOC_CTX *mem_ctx,
+				   struct readdir_attr_data **pattr_data)
+{
+	struct fruit_config_data *config = NULL;
+	struct readdir_attr_data *attr_data;
+	NTSTATUS status;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data,
+				return NT_STATUS_UNSUCCESSFUL);
+
+	if (!config->use_aapl) {
+		return SMB_VFS_NEXT_READDIR_ATTR(handle, fname, mem_ctx, pattr_data);
+	}
+
+	DEBUG(10, ("fruit_readdir_attr %s\n", fname->base_name));
+
+	*pattr_data = talloc_zero(mem_ctx, struct readdir_attr_data);
+	if (*pattr_data == NULL) {
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+	attr_data = *pattr_data;
+	attr_data->type = RDATTR_AAPL;
+
+	/*
+	 * Mac metadata: compressed FinderInfo, resource fork length
+	 * and creation date
+	 */
+	status = readdir_attr_macmeta(handle, fname, attr_data);
+	if (!NT_STATUS_IS_OK(status)) {
+		/*
+		 * Error handling is tricky: if we return failure from
+		 * this function, the corresponding directory entry
+		 * will to be passed to the client, so we really just
+		 * want to error out on fatal errors.
+		 */
+		if  (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+			goto fail;
+		}
+	}
+
+	/*
+	 * UNIX mode
+	 */
+	if (config->unix_info_enabled) {
+		attr_data->attr_data.aapl.unix_mode = fname->st.st_ex_mode;
+	}
+
+	/*
+	 * max_access
+	 */
+	if (!config->readdir_attr_max_access) {
+		attr_data->attr_data.aapl.max_access = FILE_GENERIC_ALL;
+	} else {
+		status = smbd_calculate_access_mask(
+			handle->conn,
+			fname,
+			false,
+			SEC_FLAG_MAXIMUM_ALLOWED,
+			&attr_data->attr_data.aapl.max_access);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto fail;
+		}
+	}
+
+	return NT_STATUS_OK;
+
+fail:
+	DEBUG(1, ("fruit_readdir_attr %s, error: %s\n",
+		  fname->base_name, nt_errstr(status)));
+	TALLOC_FREE(*pattr_data);
+	return status;
+}
+
+static NTSTATUS fruit_fget_nt_acl(vfs_handle_struct *handle,
+				  files_struct *fsp,
+				  uint32 security_info,
+				  TALLOC_CTX *mem_ctx,
+				  struct security_descriptor **ppdesc)
+{
+	NTSTATUS status;
+	struct security_ace ace;
+	struct dom_sid sid;
+	struct fruit_config_data *config;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data,
+				return NT_STATUS_UNSUCCESSFUL);
+
+	status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
+					  mem_ctx, ppdesc);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	/*
+	 * Add MS NFS style ACEs with uid, gid and mode
+	 */
+	if (!config->unix_info_enabled) {
+		return NT_STATUS_OK;
+	}
+
+	/* MS NFS style mode */
+	sid_compose(&sid, &global_sid_Unix_NFS_Mode, fsp->fsp_name->st.st_ex_mode);
+	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+	status = security_descriptor_dacl_add(*ppdesc, &ace);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1,("failed to add MS NFS style ACE\n"));
+		return status;
+	}
+
+	/* MS NFS style uid */
+	sid_compose(&sid, &global_sid_Unix_NFS_Users, fsp->fsp_name->st.st_ex_uid);
+	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+	status = security_descriptor_dacl_add(*ppdesc, &ace);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1,("failed to add MS NFS style ACE\n"));
+		return status;
+	}
+
+	/* MS NFS style gid */
+	sid_compose(&sid, &global_sid_Unix_NFS_Groups, fsp->fsp_name->st.st_ex_gid);
+	init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+	status = security_descriptor_dacl_add(*ppdesc, &ace);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1,("failed to add MS NFS style ACE\n"));
+		return status;
+	}
+
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS fruit_fset_nt_acl(vfs_handle_struct *handle,
+				  files_struct *fsp,
+				  uint32 security_info_sent,
+				  const struct security_descriptor *psd)
+{
+	NTSTATUS status;
+	bool do_chmod;
+	mode_t ms_nfs_mode;
+	int result;
+
+	DEBUG(1, ("fruit_fset_nt_acl: %s\n", fsp_str_dbg(fsp)));
+
+	status = check_ms_nfs(handle, fsp, psd, &ms_nfs_mode, &do_chmod);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("fruit_fset_nt_acl: check_ms_nfs failed%s\n", fsp_str_dbg(fsp)));
+		return status;
+	}
+
+	status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("fruit_fset_nt_acl: SMB_VFS_NEXT_FSET_NT_ACL failed%s\n", fsp_str_dbg(fsp)));
+		return status;
+	}
+
+	if (do_chmod) {
+		if (fsp->fh->fd != -1) {
+			DEBUG(1, ("fchmod: %s\n", fsp_str_dbg(fsp)));
+			result = SMB_VFS_FCHMOD(fsp, ms_nfs_mode);
+		} else {
+			DEBUG(1, ("chmod: %s\n", fsp_str_dbg(fsp)));
+			result = SMB_VFS_CHMOD(fsp->conn,
+					       fsp->fsp_name->base_name,
+					       ms_nfs_mode);
+		}
+
+		if (result != 0) {
+			DEBUG(1, ("chmod: %s, result: %d, %04o error %s\n", fsp_str_dbg(fsp),
+				  result, ms_nfs_mode, strerror(errno)));
+			status = map_nt_error_from_unix(errno);
+			return status;
+		}
+	}
+
+	return NT_STATUS_OK;
+}
+
 static struct vfs_fn_pointers vfs_fruit_fns = {
 	.connect_fn = fruit_connect,
 
@@ -2949,6 +3392,11 @@ static struct vfs_fn_pointers vfs_fruit_fns = {
 	.ftruncate_fn = fruit_ftruncate,
 	.fallocate_fn = fruit_fallocate,
 	.create_file_fn = fruit_create_file,
+	.readdir_attr_fn = fruit_readdir_attr,
+
+	/* NT ACL operations */
+	.fget_nt_acl_fn = fruit_fget_nt_acl,
+	.fset_nt_acl_fn = fruit_fset_nt_acl,
 };
 
 NTSTATUS vfs_fruit_init(void);
-- 
1.9.3


From 21d13735fe5ace017f34ffa16c087f51b6daaef6 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 26 Nov 2014 15:21:36 +0100
Subject: [PATCH 09/12] s3:smbd: add SMB_VFS_READDIR_ATTR() to marshall
 direntry

SMB_VFS_READDIR_ATTR is a last minute hook to fetch additional metadata
for a directory entry when we're already marshalling the SMB reply buffer.

This would we used, when there's a need to repurpose some fields in the
the reply, like it's done with Apple's SMB2 extension "AAPL".

We then fetch AAPL metadata with the shiny new SMB_VFS_READDIR_ATTR()
VFS call and marshall appropiately.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/trans2.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 58 insertions(+), 6 deletions(-)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index e2640e4..16498b3 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -40,6 +40,7 @@
 #include "rpc_server/srv_pipe_hnd.h"
 #include "printing.h"
 #include "lib/util_ea.h"
+#include "lib/readdir_attr.h"
 
 #define DIR_ENTRY_SAFETY_MARGIN 4096
 
@@ -1627,6 +1628,7 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
 	int off;
 	int pad = 0;
 	NTSTATUS status;
+	struct readdir_attr_data *readdir_attr_data = NULL;
 
 	ZERO_STRUCT(mdate_ts);
 	ZERO_STRUCT(adate_ts);
@@ -1638,6 +1640,13 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
 	}
 	allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
 
+	status = SMB_VFS_READDIR_ATTR(conn, smb_fname, ctx, &readdir_attr_data);
+	if (!NT_STATUS_IS_OK(status)) {
+		if (!NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED, status)) {
+			return status;
+		}
+	}
+
 	file_index = get_FileIndex(conn, &smb_fname->st);
 
 	mdate_ts = smb_fname->st.st_ex_mtime;
@@ -2098,17 +2107,41 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
 		q = p; p += 4; /* q is placeholder for name length */
 		if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
 			SIVAL(p, 0, IO_REPARSE_TAG_DFS);
+		} else if (readdir_attr_data &&
+			   readdir_attr_data->type == RDATTR_AAPL) {
+			/*
+			 * OS X specific SMB2 extension negotiated via
+			 * AAPL create context: return max_access in
+			 * ea_size field.
+			 */
+			SIVAL(p, 0, readdir_attr_data->attr_data.aapl.max_access);
 		} else {
 			unsigned int ea_size = estimate_ea_size(conn, NULL,
 								smb_fname);
 			SIVAL(p,0,ea_size); /* Extended attributes */
 		}
 		p += 4;
-		/* Clear the short name buffer. This is
-		 * IMPORTANT as not doing so will trigger
-		 * a Win2k client bug. JRA.
-		 */
-		if (!was_8_3 && check_mangled_names) {
+
+		if (readdir_attr_data &&
+		    readdir_attr_data->type == RDATTR_AAPL) {
+			/*
+			 * OS X specific SMB2 extension negotiated via
+			 * AAPL create context: return resource fork
+			 * length and compressed FinderInfo in
+			 * shortname field.
+			 *
+			 * According to documentation short_name_len
+			 * should be 0, but on the wire behaviour
+			 * shows its set to 24 by clients.
+			 */
+			SSVAL(p, 0, 24);
+
+			/* Resourefork length */
+			SBVAL(p, 2, readdir_attr_data->attr_data.aapl.rfork_size);
+
+			/* Compressed FinderInfo */
+			memcpy(p + 10, &readdir_attr_data->attr_data.aapl.finder_info, 16);
+		} else if (!was_8_3 && check_mangled_names) {
 			char mangled_name[13]; /* mangled 8.3 name. */
 			if (!name_to_8_3(fname,mangled_name,True,
 					conn->params)) {
@@ -2128,10 +2161,29 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
 			}
 			SSVAL(p, 0, len);
 		} else {
+			/* Clear the short name buffer. This is
+			 * IMPORTANT as not doing so will trigger
+			 * a Win2k client bug. JRA.
+			 */
 			memset(p,'\0',26);
 		}
 		p += 26;
-		SSVAL(p,0,0); p += 2; /* Reserved ? */
+
+		/* Reserved ? */
+		if (readdir_attr_data &&
+		    readdir_attr_data->type == RDATTR_AAPL) {
+			/*
+			 * OS X specific SMB2 extension negotiated via
+			 * AAPL create context: return UNIX mode in
+			 * reserved field.
+			 */
+			uint16_t aapl_mode = (uint16_t)readdir_attr_data->attr_data.aapl.unix_mode;
+			SSVAL(p, 0, aapl_mode);
+		} else {
+			SSVAL(p, 0, 0);
+		}
+		p += 2;
+
 		SBVAL(p,0,file_index); p += 8;
 		status = srvstr_push(base_data, flags2, p,
 				  fname, PTR_DIFF(end_data, p),
-- 
1.9.3


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

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

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source4/libcli/raw/interfaces.h | 1 +
 source4/libcli/raw/rawsearch.c  | 1 +
 2 files changed, 2 insertions(+)

diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h
index dd0c3bd..5804a6b 100644
--- a/source4/libcli/raw/interfaces.h
+++ b/source4/libcli/raw/interfaces.h
@@ -2740,6 +2740,7 @@ union smb_search_data {
 		uint32_t  attrib;
 		uint32_t  ea_size;
 		uint64_t file_id;
+		uint8_t short_name_buf[24];
 		struct smb_wire_string short_name;
 		struct smb_wire_string name;
 	} id_both_directory_info;
diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c
index 0705faa..6035cc2 100644
--- a/source4/libcli/raw/rawsearch.c
+++ b/source4/libcli/raw/rawsearch.c
@@ -456,6 +456,7 @@ NTSTATUS smb_raw_search_common(TALLOC_CTX *mem_ctx,
 		smbcli_blob_pull_string(NULL, mem_ctx, blob,
 				     &data->id_both_directory_info.short_name,
 				     68, 70, STR_LEN8BIT | STR_UNICODE);
+		memcpy(data->id_both_directory_info.short_name_buf, blob->data + 70, 24);
 		data->id_both_directory_info.file_id     = BVAL(blob->data,            96);
 		len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
 					      &data->id_both_directory_info.name,
-- 
1.9.3


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

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

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


From 009c3bbdc5ab5188b1063c8a62bccfa6e607b688 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 28 Nov 2014 22:44:29 +0100
Subject: [PATCH 12/12] vfs_fruit: add AAPL options

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 docs-xml/manpages/vfs_fruit.8.xml | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/docs-xml/manpages/vfs_fruit.8.xml b/docs-xml/manpages/vfs_fruit.8.xml
index 47caeb0..a9e2e6d 100644
--- a/docs-xml/manpages/vfs_fruit.8.xml
+++ b/docs-xml/manpages/vfs_fruit.8.xml
@@ -153,6 +153,41 @@
 	    </listitem>
 	  </varlistentry>
 
+	  <varlistentry>
+	    <term>fruit:aapl = yes | no</term>
+	    <listitem>
+	      <para>A global option whether to enable Apple's SMB2+
+	      extension codenamed AAPL. Default
+	      <emphasis>yes</emphasis>. This extension enhances
+	      several deficiencies when connecting from Macs:</para>
+
+	      <itemizedlist>
+		<listitem><para>directory enumeration is enriched with
+		Mac relevant filesystem metadata (UNIX mode,
+		FinderInfo, resource fork size and effective
+		permission), as a result the Mac client doesn't need
+		to fetch this metadata individuallly per directory
+		entry resulting in an often tremendous performance
+		increase.</para></listitem>
+
+		<listitem><para>The ability to query and modify the
+		UNIX mode of directory entries.</para></listitem>
+	      </itemizedlist>
+
+	      <para>There's a set of per share options that can be
+	      used to disable the computation of specific Mac metadata
+	      in the directory enumeration context, all are enabled by
+	      default:</para>
+
+	      <itemizedlist>
+		<listitem><para>readdir_attr:aapl_rsize = true | false</para></listitem>
+		<listitem><para>readdir_attr:aapl_finder_info = true | false</para></listitem>
+		<listitem><para>readdir_attr:aapl_max_access = true | false</para></listitem>
+	      </itemizedlist>
+
+	    </listitem>
+	  </varlistentry>
+
 	</variablelist>
 </refsect1>
 
-- 
1.9.3



More information about the samba-technical mailing list