From a13fda747238c5780d10bdf80b00edd8c2d1f6d3 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Sat, 19 Oct 2013 03:47:06 +0200 Subject: smb2_ioctl: add support for FSCTL_SRV_COPYCHUNK_WRITE 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 Reviewed-by: Jeremy Allison --- source3/smbd/smb2_ioctl_network_fs.c | 44 ++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/source3/smbd/smb2_ioctl_network_fs.c b/source3/smbd/smb2_ioctl_network_fs.c index 1e1e3e5e94..a1d67f80a9 100644 --- a/source3/smbd/smb2_ioctl_network_fs.c +++ b/source3/smbd/smb2_ioctl_network_fs.c @@ -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); -- cgit