diff options
Diffstat (limited to 'source3/modules')
-rw-r--r-- | source3/modules/vfs_default.c | 111 | ||||
-rw-r--r-- | source3/modules/vfs_full_audit.c | 38 | ||||
-rw-r--r-- | source3/modules/vfs_time_audit.c | 85 |
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, |