smb2_ioctl: add support for FSCTL_SRV_COPYCHUNK_WRITE
authorDavid Disseldorp <ddiss@samba.org>
Sat, 19 Oct 2013 01:47:06 +0000 (03:47 +0200)
committerJeremy Allison <jra@samba.org>
Fri, 25 Oct 2013 18:41:19 +0000 (11:41 -0700)
FSCTL_SRV_COPYCHUNK can only be used when the client has the copy-chunk
target file open with FILE_WRITE_DATA and FILE_READ_DATA.
FSCTL_SRV_COPYCHUNK_WRITE requires only FILE_WRITE_DATA access on the
target, and is therefore suitable for cp --reflink, which opens the
target file O_WRONLY.

Signed-off-by: David Disseldorp <ddiss@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/smbd/smb2_ioctl_network_fs.c

index 1e1e3e5..a1d67f8 100644 (file)
@@ -80,29 +80,37 @@ struct fsctl_srv_copychunk_state {
 };
 static void fsctl_srv_copychunk_vfs_done(struct tevent_req *subreq);
 
-static NTSTATUS copychunk_check_handles(struct files_struct *src_fsp,
+static NTSTATUS copychunk_check_handles(uint32_t ctl_code,
+                                       struct files_struct *src_fsp,
                                        struct files_struct *dst_fsp,
                                        struct smb_request *smb1req)
 {
        /*
         * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request
-        * If Open.GrantedAccess of the destination file does not
-        * include FILE_WRITE_DATA, then the request MUST be failed with
-        * STATUS_ACCESS_DENIED. If Open.GrantedAccess of the
-        * destination file does not include FILE_READ_DATA access and
-        * the CtlCode is FSCTL_SRV_COPYCHUNK, then the request MUST be
-        * failed with STATUS_ACCESS_DENIED.
+        * The server MUST fail the request with STATUS_ACCESS_DENIED if any of
+        * the following are true:
+        * - The Open.GrantedAccess of the destination file does not include
+        *   FILE_WRITE_DATA or FILE_APPEND_DATA.
         */
        if (!CHECK_WRITE(dst_fsp)) {
                DEBUG(5, ("copy chunk no write on dest handle (%s).\n",
                        smb_fname_str_dbg(dst_fsp->fsp_name) ));
                return NT_STATUS_ACCESS_DENIED;
        }
-       if (!CHECK_READ(dst_fsp, smb1req)) {
+       /*
+        * - The Open.GrantedAccess of the destination file does not include
+        *   FILE_READ_DATA, and the CtlCode is FSCTL_SRV_COPYCHUNK.
+        */
+       if ((ctl_code == FSCTL_SRV_COPYCHUNK)
+         && !CHECK_READ(dst_fsp, smb1req)) {
                DEBUG(5, ("copy chunk no read on dest handle (%s).\n",
                        smb_fname_str_dbg(dst_fsp->fsp_name) ));
                return NT_STATUS_ACCESS_DENIED;
        }
+       /*
+        * - The Open.GrantedAccess of the source file does not include
+        *   FILE_READ_DATA access.
+        */
        if (!CHECK_READ(src_fsp, smb1req)) {
                DEBUG(5, ("copy chunk no read on src handle (%s).\n",
                        smb_fname_str_dbg(src_fsp->fsp_name) ));
@@ -136,6 +144,7 @@ static NTSTATUS copychunk_check_handles(struct files_struct *src_fsp,
 
 static struct tevent_req *fsctl_srv_copychunk_send(TALLOC_CTX *mem_ctx,
                                                   struct tevent_context *ev,
+                                                  uint32_t ctl_code,
                                                   struct files_struct *dst_fsp,
                                                   DATA_BLOB *in_input,
                                                   size_t in_max_output,
@@ -150,6 +159,10 @@ static struct tevent_req *fsctl_srv_copychunk_send(TALLOC_CTX *mem_ctx,
        struct srv_copychunk *chunk;
        struct fsctl_srv_copychunk_state *state;
 
+       /* handler for both copy-chunk variants */
+       SMB_ASSERT((ctl_code == FSCTL_SRV_COPYCHUNK)
+               || (ctl_code == FSCTL_SRV_COPYCHUNK_WRITE));
+
        req = tevent_req_create(mem_ctx, &state,
                                struct fsctl_srv_copychunk_state);
        if (req == NULL) {
@@ -188,7 +201,8 @@ static struct tevent_req *fsctl_srv_copychunk_send(TALLOC_CTX *mem_ctx,
 
        state->dst_fsp = dst_fsp;
 
-       state->status = copychunk_check_handles(state->src_fsp,
+       state->status = copychunk_check_handles(ctl_code,
+                                               state->src_fsp,
                                                state->dst_fsp,
                                                smb2req->smb1req);
        if (!NT_STATUS_IS_OK(state->status)) {
@@ -446,8 +460,18 @@ struct tevent_req *smb2_ioctl_network_fs(uint32_t ctl_code,
        NTSTATUS status;
 
        switch (ctl_code) {
+       /*
+        * [MS-SMB2] 2.2.31
+        * FSCTL_SRV_COPYCHUNK is issued when a handle has
+        * FILE_READ_DATA and FILE_WRITE_DATA access to the file;
+        * FSCTL_SRV_COPYCHUNK_WRITE is issued when a handle only has
+        * FILE_WRITE_DATA access.
+        */
+       case FSCTL_SRV_COPYCHUNK_WRITE: /* FALL THROUGH */
        case FSCTL_SRV_COPYCHUNK:
-               subreq = fsctl_srv_copychunk_send(state, ev, state->fsp,
+               subreq = fsctl_srv_copychunk_send(state, ev,
+                                                 ctl_code,
+                                                 state->fsp,
                                                  &state->in_input,
                                                  state->in_max_output,
                                                  state->smb2req);