diff options
Diffstat (limited to 'source3/modules')
-rw-r--r-- | source3/modules/offload_token.c | 90 | ||||
-rw-r--r-- | source3/modules/offload_token.h | 3 | ||||
-rw-r--r-- | source3/modules/vfs_btrfs.c | 46 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 48 | ||||
-rw-r--r-- | source3/modules/vfs_fruit.c | 29 | ||||
-rw-r--r-- | source3/modules/vfs_full_audit.c | 10 | ||||
-rw-r--r-- | source3/modules/vfs_time_audit.c | 7 |
7 files changed, 207 insertions, 26 deletions
diff --git a/source3/modules/offload_token.c b/source3/modules/offload_token.c index 2969262f48e..05528da46b5 100644 --- a/source3/modules/offload_token.c +++ b/source3/modules/offload_token.c @@ -20,6 +20,7 @@ #include "includes.h" #include "smbd/smbd.h" #include "smbd/globals.h" +#include "../libcli/security/security.h" #include "dbwrap/dbwrap.h" #include "dbwrap/dbwrap_rbt.h" #include "dbwrap/dbwrap_open.h" @@ -220,3 +221,92 @@ NTSTATUS vfs_offload_token_create_blob(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } + +NTSTATUS vfs_offload_token_check_handles(uint32_t fsctl, + files_struct *src_fsp, + files_struct *dst_fsp) +{ + if (src_fsp->vuid != dst_fsp->vuid) { + DBG_INFO("copy chunk handles not in the same session.\n"); + return NT_STATUS_ACCESS_DENIED; + } + + if (!NT_STATUS_IS_OK(src_fsp->op->status)) { + DBG_INFO("copy chunk source handle invalid: %s\n", + nt_errstr(src_fsp->op->status)); + return NT_STATUS_ACCESS_DENIED; + } + + if (!NT_STATUS_IS_OK(dst_fsp->op->status)) { + DBG_INFO("copy chunk destination handle invalid: %s\n", + nt_errstr(dst_fsp->op->status)); + return NT_STATUS_ACCESS_DENIED; + } + + if (src_fsp->deferred_close != NULL) { + DBG_INFO("copy chunk src handle with deferred close.\n"); + return NT_STATUS_ACCESS_DENIED; + } + + if (dst_fsp->deferred_close != NULL) { + DBG_INFO("copy chunk dst handle with deferred close.\n"); + return NT_STATUS_ACCESS_DENIED; + } + + if (src_fsp->is_directory) { + DBG_INFO("copy chunk no read on src directory handle (%s).\n", + smb_fname_str_dbg(src_fsp->fsp_name)); + return NT_STATUS_ACCESS_DENIED; + } + + if (dst_fsp->is_directory) { + DBG_INFO("copy chunk no read on dst directory handle (%s).\n", + smb_fname_str_dbg(dst_fsp->fsp_name)); + return NT_STATUS_ACCESS_DENIED; + } + + if (IS_IPC(src_fsp->conn) || IS_IPC(dst_fsp->conn)) { + DBG_INFO("copy chunk no access on IPC$ handle.\n"); + return NT_STATUS_ACCESS_DENIED; + } + + if (IS_PRINT(src_fsp->conn) || IS_PRINT(dst_fsp->conn)) { + DBG_INFO("copy chunk no access on PRINT handle.\n"); + return NT_STATUS_ACCESS_DENIED; + } + + /* + * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request + * 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. + * + * A non writable dst handle also doesn't make sense for other fsctls. + */ + if (!CHECK_WRITE(dst_fsp)) { + DBG_INFO("dest handle not writable (%s).\n", + smb_fname_str_dbg(dst_fsp->fsp_name)); + return NT_STATUS_ACCESS_DENIED; + } + /* + * - The Open.GrantedAccess of the destination file does not include + * FILE_READ_DATA, and the CtlCode is FSCTL_SRV_COPYCHUNK. + */ + if ((fsctl == FSCTL_SRV_COPYCHUNK) && !CHECK_READ_IOCTL(dst_fsp)) { + DBG_INFO("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_SMB2(src_fsp)) { + DBG_INFO("src handle not readable (%s).\n", + smb_fname_str_dbg(src_fsp->fsp_name)); + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} diff --git a/source3/modules/offload_token.h b/source3/modules/offload_token.h index 569edcfdd17..1e8e26d476f 100644 --- a/source3/modules/offload_token.h +++ b/source3/modules/offload_token.h @@ -34,4 +34,7 @@ NTSTATUS vfs_offload_token_create_blob(TALLOC_CTX *mem_ctx, const files_struct *fsp, uint32_t fsctl, DATA_BLOB *token_blob); +NTSTATUS vfs_offload_token_check_handles(uint32_t fsctl, + files_struct *src_fsp, + files_struct *dst_fsp); #endif diff --git a/source3/modules/vfs_btrfs.c b/source3/modules/vfs_btrfs.c index 79175378efc..f310a3dfd65 100644 --- a/source3/modules/vfs_btrfs.c +++ b/source3/modules/vfs_btrfs.c @@ -206,8 +206,9 @@ static void btrfs_offload_write_done(struct tevent_req *subreq); static struct tevent_req *btrfs_offload_write_send(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct files_struct *src_fsp, - off_t src_off, + uint32_t fsctl, + DATA_BLOB *token, + off_t transfer_offset, struct files_struct *dest_fsp, off_t dest_off, off_t num, @@ -218,7 +219,10 @@ static struct tevent_req *btrfs_offload_write_send(struct vfs_handle_struct *han struct btrfs_ioctl_clone_range_args cr_args; struct lock_struct src_lck; struct lock_struct dest_lck; + off_t src_off = transfer_offset; + files_struct *src_fsp = NULL; int ret; + bool handle_offload_write = true; NTSTATUS status; req = tevent_req_create(mem_ctx, &cc_state, struct btrfs_cc_state); @@ -233,16 +237,38 @@ static struct tevent_req *btrfs_offload_write_send(struct vfs_handle_struct *han cc_state->handle = handle; + status = vfs_offload_token_db_fetch_fsp(btrfs_offload_ctx, + token, &src_fsp); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + switch (fsctl) { + case FSCTL_SRV_COPYCHUNK: + case FSCTL_SRV_COPYCHUNK_WRITE: + case FSCTL_DUP_EXTENTS_TO_FILE: + break; + + default: + handle_offload_write = false; + break; + } + if (num == 0) { /* * With a @src_length of zero, BTRFS_IOC_CLONE_RANGE clones * all data from @src_offset->EOF! This is certainly not what * the caller expects, and not what vfs_default does. */ + handle_offload_write = false; + } + + if (!handle_offload_write) { cc_state->subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle, cc_state, ev, - src_fsp, - src_off, + fsctl, + token, + transfer_offset, dest_fsp, dest_off, num, flags); @@ -255,6 +281,13 @@ static struct tevent_req *btrfs_offload_write_send(struct vfs_handle_struct *han return req; } + status = vfs_offload_token_check_handles( + fsctl, src_fsp, dest_fsp); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + status = vfs_stat_fsp(src_fsp); if (tevent_req_nterror(req, status)) { return tevent_req_post(req, ev); @@ -323,8 +356,9 @@ static struct tevent_req *btrfs_offload_write_send(struct vfs_handle_struct *han (unsigned long long)cr_args.dest_offset)); cc_state->subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle, cc_state, ev, - src_fsp, - src_off, + fsctl, + token, + transfer_offset, dest_fsp, dest_off, num, flags); diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 9b86a905203..9add9155f12 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -1689,6 +1689,7 @@ struct vfswrap_offload_write_state { struct lock_struct read_lck; bool write_lck_locked; struct lock_struct write_lck; + DATA_BLOB *token; struct files_struct *src_fsp; off_t src_off; struct files_struct *dst_fsp; @@ -1705,8 +1706,9 @@ static struct tevent_req *vfswrap_offload_write_send( struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct files_struct *src_fsp, - off_t src_off, + uint32_t fsctl, + DATA_BLOB *token, + off_t transfer_offset, struct files_struct *dest_fsp, off_t dest_off, off_t to_copy, @@ -1715,10 +1717,9 @@ static struct tevent_req *vfswrap_offload_write_send( struct tevent_req *req; struct vfswrap_offload_write_state *state = NULL; size_t num = MIN(to_copy, COPYCHUNK_MAX_TOTAL_LEN); + files_struct *src_fsp = NULL; NTSTATUS status; - DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy); - req = tevent_req_create(mem_ctx, &state, struct vfswrap_offload_write_state); if (req == NULL) { @@ -1738,8 +1739,8 @@ static struct tevent_req *vfswrap_offload_write_send( *state = (struct vfswrap_offload_write_state) { .ev = ev, - .src_fsp = src_fsp, - .src_off = src_off, + .token = token, + .src_off = transfer_offset, .dst_fsp = dest_fsp, .dst_off = dest_off, .to_copy = to_copy, @@ -1747,11 +1748,44 @@ static struct tevent_req *vfswrap_offload_write_send( .flags = flags, }; + switch (fsctl) { + case FSCTL_SRV_COPYCHUNK: + case FSCTL_SRV_COPYCHUNK_WRITE: + break; + + case FSCTL_OFFLOAD_WRITE: + tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + return tevent_req_post(req, ev); + + default: + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return tevent_req_post(req, ev); + } + + /* + * From here on we assume a copy-chunk fsctl + */ + if (to_copy == 0) { tevent_req_done(req); return tevent_req_post(req, ev); } + status = vfs_offload_token_db_fetch_fsp(vfswrap_offload_ctx, + token, &src_fsp); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + state->src_fsp = src_fsp; + + DBG_DEBUG("server side copy chunk of length %" PRIu64 "\n", to_copy); + + status = vfs_offload_token_check_handles(fsctl, src_fsp, dest_fsp); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + state->buf = talloc_array(state, uint8_t, num); if (tevent_req_nomem(state->buf, req)) { return tevent_req_post(req, ev); @@ -1762,7 +1796,7 @@ static struct tevent_req *vfswrap_offload_write_send( return tevent_req_post(req, ev); } - if (src_fsp->fsp_name->st.st_ex_size < src_off + num) { + if (src_fsp->fsp_name->st.st_ex_size < state->src_off + num) { /* * [MS-SMB2] 3.3.5.15.6 Handling a Server-Side Data Copy Request * If the SourceOffset or SourceOffset + Length extends beyond diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 279366ca08c..db6324a3574 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -5485,8 +5485,9 @@ static void fruit_offload_write_done(struct tevent_req *subreq); static struct tevent_req *fruit_offload_write_send(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct files_struct *src_fsp, - off_t src_off, + uint32_t fsctl, + DATA_BLOB *token, + off_t transfer_offset, struct files_struct *dest_fsp, off_t dest_off, off_t num, @@ -5496,6 +5497,8 @@ static struct tevent_req *fruit_offload_write_send(struct vfs_handle_struct *han struct fruit_offload_write_state *state; NTSTATUS status; struct fruit_config_data *config; + off_t src_off = transfer_offset; + files_struct *src_fsp = NULL; off_t to_copy = num; DEBUG(10,("soff: %ju, doff: %ju, len: %ju\n", @@ -5511,9 +5514,22 @@ static struct tevent_req *fruit_offload_write_send(struct vfs_handle_struct *han return NULL; } state->handle = handle; - state->src_fsp = src_fsp; state->dst_fsp = dest_fsp; + switch (fsctl) { + case FSCTL_SRV_COPYCHUNK: + case FSCTL_SRV_COPYCHUNK_WRITE: + status = vfs_offload_token_db_fetch_fsp(fruit_offload_ctx, + token, &src_fsp); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + state->src_fsp = src_fsp; + break; + default: + break; + } + /* * Check if this a OS X copyfile style copychunk request with * a requested chunk count of 0 that was translated to a @@ -5521,7 +5537,7 @@ static struct tevent_req *fruit_offload_write_send(struct vfs_handle_struct *han * = dest_off = num = 0. */ if ((src_off == 0) && (dest_off == 0) && (num == 0) && - src_fsp->aapl_copyfile_supported && + src_fsp != NULL && src_fsp->aapl_copyfile_supported && dest_fsp->aapl_copyfile_supported) { status = vfs_stat_fsp(src_fsp); @@ -5536,8 +5552,9 @@ static struct tevent_req *fruit_offload_write_send(struct vfs_handle_struct *han subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle, mem_ctx, ev, - src_fsp, - src_off, + fsctl, + token, + transfer_offset, dest_fsp, dest_off, to_copy, diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index f9d14a8e845..892cf5d7378 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -1944,8 +1944,9 @@ static NTSTATUS smb_full_audit_offload_read_recv( static struct tevent_req *smb_full_audit_offload_write_send(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct files_struct *src_fsp, - off_t src_off, + uint32_t fsctl, + DATA_BLOB *token, + off_t transfer_offset, struct files_struct *dest_fsp, off_t dest_off, off_t num, @@ -1953,8 +1954,9 @@ static struct tevent_req *smb_full_audit_offload_write_send(struct vfs_handle_st { struct tevent_req *req; - req = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle, mem_ctx, ev, src_fsp, - src_off, dest_fsp, dest_off, num, + req = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle, mem_ctx, ev, + fsctl, token, transfer_offset, + dest_fsp, dest_off, num, flags); do_log(SMB_VFS_OP_OFFLOAD_WRITE_SEND, req, handle, ""); diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 6dc03fb7a04..cc21a476245 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -2005,8 +2005,9 @@ static void smb_time_audit_offload_write_done(struct tevent_req *subreq); static struct tevent_req *smb_time_audit_offload_write_send(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct files_struct *src_fsp, - off_t src_off, + uint32_t fsctl, + DATA_BLOB *token, + off_t transfer_offset, struct files_struct *dest_fsp, off_t dest_off, off_t num, @@ -2025,7 +2026,7 @@ static struct tevent_req *smb_time_audit_offload_write_send(struct vfs_handle_st state->handle = handle; clock_gettime_mono(&state->ts_send); subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle, state, ev, - src_fsp, src_off, + fsctl, token, transfer_offset, dest_fsp, dest_off, num, flags); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); |