summaryrefslogtreecommitdiff
path: root/source3/modules
diff options
context:
space:
mode:
Diffstat (limited to 'source3/modules')
-rw-r--r--source3/modules/vfs_default.c111
-rw-r--r--source3/modules/vfs_full_audit.c38
-rw-r--r--source3/modules/vfs_time_audit.c85
3 files changed, 234 insertions, 0 deletions
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 0f651dca51..d937c4a862 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -31,6 +31,7 @@
#include "librpc/gen_ndr/ndr_dfsblobs.h"
#include "lib/util/tevent_unix.h"
#include "lib/asys/asys.h"
+#include "lib/util/tevent_ntstatus.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
@@ -1323,6 +1324,114 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
return NT_STATUS_NOT_SUPPORTED;
}
+struct vfs_cc_state {
+ off_t copied;
+ uint8_t buf[65536];
+};
+
+static struct tevent_req *vfswrap_copy_chunk_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *src_fsp,
+ off_t src_off,
+ struct files_struct *dest_fsp,
+ off_t dest_off,
+ off_t num)
+{
+ struct tevent_req *req;
+ struct vfs_cc_state *vfs_cc_state;
+ NTSTATUS status;
+
+ DEBUG(10, ("performing server side copy chunk of length %lu\n",
+ (unsigned long)num));
+
+ req = tevent_req_create(mem_ctx, &vfs_cc_state, struct vfs_cc_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ status = vfs_stat_fsp(src_fsp);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (src_fsp->fsp_name->st.st_ex_size < 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
+ * the end of file, the server SHOULD<240> treat this as a
+ * STATUS_END_OF_FILE error.
+ * ...
+ * <240> Section 3.3.5.15.6: Windows servers will return
+ * STATUS_INVALID_VIEW_SIZE instead of STATUS_END_OF_FILE.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
+ return tevent_req_post(req, ev);
+ }
+
+ /* could use 2.6.33+ sendfile here to do this in kernel */
+ while (vfs_cc_state->copied < num) {
+ ssize_t ret;
+ off_t this_num = MIN(sizeof(vfs_cc_state->buf),
+ num - vfs_cc_state->copied);
+
+ ret = SMB_VFS_PREAD(src_fsp, vfs_cc_state->buf,
+ this_num, src_off);
+ if (ret == -1) {
+ tevent_req_nterror(req, map_nt_error_from_unix(errno));
+ return tevent_req_post(req, ev);
+ }
+ if (ret != this_num) {
+ /* zero tolerance for short reads */
+ tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
+ return tevent_req_post(req, ev);
+ }
+ src_off += ret;
+
+ ret = SMB_VFS_PWRITE(dest_fsp, vfs_cc_state->buf,
+ this_num, dest_off);
+ if (ret == -1) {
+ tevent_req_nterror(req, map_nt_error_from_unix(errno));
+ return tevent_req_post(req, ev);
+ }
+ if (ret != this_num) {
+ /* zero tolerance for short writes */
+ tevent_req_nterror(req, NT_STATUS_IO_DEVICE_ERROR);
+ return tevent_req_post(req, ev);
+ }
+ dest_off += ret;
+
+ vfs_cc_state->copied += this_num;
+ }
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS vfswrap_copy_chunk_recv(struct vfs_handle_struct *handle,
+ struct tevent_req *req,
+ off_t *copied)
+{
+ struct vfs_cc_state *vfs_cc_state = tevent_req_data(req,
+ struct vfs_cc_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ DEBUG(2, ("server side copy chunk failed: %s\n",
+ nt_errstr(status)));
+ *copied = 0;
+ tevent_req_received(req);
+ return status;
+ }
+
+ *copied = vfs_cc_state->copied;
+ DEBUG(10, ("server side copy chunk copied %lu\n",
+ (unsigned long)*copied));
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
+
/********************************************************************
Given a stat buffer return the allocated size on disk, taking into
account sparse files.
@@ -2367,6 +2476,8 @@ static struct vfs_fn_pointers vfs_default_fns = {
.strict_unlock_fn = vfswrap_strict_unlock,
.translate_name_fn = vfswrap_translate_name,
.fsctl_fn = vfswrap_fsctl,
+ .copy_chunk_send_fn = vfswrap_copy_chunk_send,
+ .copy_chunk_recv_fn = vfswrap_copy_chunk_recv,
/* NT ACL operations. */
diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
index b1fb090dc6..549f55e189 100644
--- a/source3/modules/vfs_full_audit.c
+++ b/source3/modules/vfs_full_audit.c
@@ -161,6 +161,8 @@ typedef enum _vfs_op_type {
SMB_VFS_OP_STRICT_LOCK,
SMB_VFS_OP_STRICT_UNLOCK,
SMB_VFS_OP_TRANSLATE_NAME,
+ SMB_VFS_OP_COPY_CHUNK_SEND,
+ SMB_VFS_OP_COPY_CHUNK_RECV,
/* NT ACL operations. */
@@ -281,6 +283,8 @@ static struct {
{ SMB_VFS_OP_STRICT_LOCK, "strict_lock" },
{ SMB_VFS_OP_STRICT_UNLOCK, "strict_unlock" },
{ SMB_VFS_OP_TRANSLATE_NAME, "translate_name" },
+ { SMB_VFS_OP_COPY_CHUNK_SEND, "copy_chunk_send" },
+ { SMB_VFS_OP_COPY_CHUNK_RECV, "copy_chunk_recv" },
{ 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" },
@@ -1732,6 +1736,38 @@ static NTSTATUS smb_full_audit_translate_name(struct vfs_handle_struct *handle,
return result;
}
+static struct tevent_req *smb_full_audit_copy_chunk_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *src_fsp,
+ off_t src_off,
+ struct files_struct *dest_fsp,
+ off_t dest_off,
+ off_t num)
+{
+ struct tevent_req *req;
+
+ req = SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, mem_ctx, ev, src_fsp,
+ src_off, dest_fsp, dest_off, num);
+
+ do_log(SMB_VFS_OP_COPY_CHUNK_SEND, req, handle, "");
+
+ return req;
+}
+
+static NTSTATUS smb_full_audit_copy_chunk_recv(struct vfs_handle_struct *handle,
+ struct tevent_req *req,
+ off_t *copied)
+{
+ NTSTATUS result;
+
+ result = SMB_VFS_NEXT_COPY_CHUNK_RECV(handle, req, copied);
+
+ do_log(SMB_VFS_OP_COPY_CHUNK_RECV, NT_STATUS_IS_OK(result), handle, "");
+
+ return result;
+}
+
static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
uint32 security_info,
TALLOC_CTX *mem_ctx,
@@ -2131,6 +2167,8 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
.strict_lock_fn = smb_full_audit_strict_lock,
.strict_unlock_fn = smb_full_audit_strict_unlock,
.translate_name_fn = smb_full_audit_translate_name,
+ .copy_chunk_send_fn = smb_full_audit_copy_chunk_send,
+ .copy_chunk_recv_fn = smb_full_audit_copy_chunk_recv,
.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 95b4148232..1b14d650af 100644
--- a/source3/modules/vfs_time_audit.c
+++ b/source3/modules/vfs_time_audit.c
@@ -29,6 +29,7 @@
#include "smbd/smbd.h"
#include "ntioctl.h"
#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_ntstatus.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
@@ -1668,6 +1669,88 @@ static NTSTATUS smb_time_audit_translate_name(struct vfs_handle_struct *handle,
return result;
}
+struct time_audit_cc_state {
+ struct timespec ts_send;
+ struct vfs_handle_struct *handle;
+ off_t copied;
+};
+static void smb_time_audit_copy_chunk_done(struct tevent_req *subreq);
+
+static struct tevent_req *smb_time_audit_copy_chunk_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *src_fsp,
+ off_t src_off,
+ struct files_struct *dest_fsp,
+ off_t dest_off,
+ off_t num)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct time_audit_cc_state *cc_state;
+
+ req = tevent_req_create(mem_ctx, &cc_state, struct time_audit_cc_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ cc_state->handle = handle;
+ clock_gettime_mono(&cc_state->ts_send);
+ subreq = SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, cc_state, ev,
+ src_fsp, src_off,
+ dest_fsp, dest_off, num);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq, smb_time_audit_copy_chunk_done, req);
+ return req;
+}
+
+static void smb_time_audit_copy_chunk_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct time_audit_cc_state *cc_state
+ = tevent_req_data(req, struct time_audit_cc_state);
+ NTSTATUS status;
+
+ status = SMB_VFS_NEXT_COPY_CHUNK_RECV(cc_state->handle,
+ subreq,
+ &cc_state->copied);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS smb_time_audit_copy_chunk_recv(struct vfs_handle_struct *handle,
+ struct tevent_req *req,
+ off_t *copied)
+{
+ struct time_audit_cc_state *cc_state
+ = tevent_req_data(req, struct time_audit_cc_state);
+ struct timespec ts_recv;
+ double timediff;
+ NTSTATUS status;
+
+ clock_gettime_mono(&ts_recv);
+ timediff = nsec_time_diff(&ts_recv, &cc_state->ts_send)*1.0e-9;
+ if (timediff > audit_timeout) {
+ smb_time_audit_log("copy_chunk", timediff);
+ }
+
+ *copied = cc_state->copied;
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
static NTSTATUS smb_time_audit_fget_nt_acl(vfs_handle_struct *handle,
files_struct *fsp,
uint32 security_info,
@@ -2179,6 +2262,8 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
.strict_lock_fn = smb_time_audit_strict_lock,
.strict_unlock_fn = smb_time_audit_strict_unlock,
.translate_name_fn = smb_time_audit_translate_name,
+ .copy_chunk_send_fn = smb_time_audit_copy_chunk_send,
+ .copy_chunk_recv_fn = smb_time_audit_copy_chunk_recv,
.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,