summaryrefslogtreecommitdiff
path: root/source3/modules
diff options
context:
space:
mode:
authorRalph Boehme <slow@samba.org>2017-06-09 13:02:49 +0200
committerRalph Boehme <slow@samba.org>2017-07-03 19:59:08 +0200
commit3645f83a3c83fa3e4bf4dbacf885cc4295e7eadd (patch)
tree7b14b55f4f51eb63d786b91f5c0533f4d5df611f /source3/modules
parentd50f307e97ae28b9fbdc2e6cffb1b5493c583a09 (diff)
downloadsamba-3645f83a3c83fa3e4bf4dbacf885cc4295e7eadd.tar.gz
s3/vfs: make SMB_VFS_OFFLOAD_WRITE_SEND offload token based
Remove the source fsp argument and instead pass the offload token generated with SMB_VFS_OFFLOAD_READ_SEND/RECV. An actual offload fsctl is not implemented yet, neither in the VFS nor at the SMB ioctl layer, and returns NT_STATUS_NOT_IMPLEMENTED With these changes we now pass the copy-chunk-across-shares test. Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'source3/modules')
-rw-r--r--source3/modules/offload_token.c90
-rw-r--r--source3/modules/offload_token.h3
-rw-r--r--source3/modules/vfs_btrfs.c46
-rw-r--r--source3/modules/vfs_default.c48
-rw-r--r--source3/modules/vfs_fruit.c29
-rw-r--r--source3/modules/vfs_full_audit.c10
-rw-r--r--source3/modules/vfs_time_audit.c7
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);