From 72b41da68681436ea2c1d8c3e0eddb4d36c98159 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 30 May 2011 17:14:56 +0200 Subject: s3: Support shadow copy display over SMB2 Autobuild-User: Volker Lendecke Autobuild-Date: Tue May 31 12:53:10 CEST 2011 on sn-devel-104 (cherry picked from commit 0fcafbf69b345b703dc759518afc8620a7d6f2e8) --- source3/smbd/smb2_ioctl.c | 121 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 121 insertions(+), 0 deletions(-) diff --git a/source3/smbd/smb2_ioctl.c b/source3/smbd/smb2_ioctl.c index 6dc0cec..3ee0453 100644 --- a/source3/smbd/smb2_ioctl.c +++ b/source3/smbd/smb2_ioctl.c @@ -24,6 +24,7 @@ #include "../libcli/smb/smb_common.h" #include "../lib/util/tevent_ntstatus.h" #include "rpc_server/srv_pipe_hnd.h" +#include "include/ntioctl.h" static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -377,6 +378,126 @@ static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx, req); return req; + case 0x00144064: /* FSCTL_SRV_ENUMERATE_SNAPSHOTS */ + { + /* + * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots) + * and return their volume names. If max_data_count is 16, then it is just + * asking for the number of volumes and length of the combined names. + * + * pdata is the data allocated by our caller, but that uses + * total_data_count (which is 0 in our case) rather than max_data_count. + * Allocate the correct amount and return the pointer to let + * it be deallocated when we return. + */ + struct shadow_copy_data *shadow_data = NULL; + bool labels = False; + uint32_t labels_data_count = 0; + uint32_t data_count; + uint32_t i; + char *pdata; + NTSTATUS status; + + if (in_max_output < 16) { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: " + "in_max_output(%u) < 16 is invalid!\n", + in_max_output)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + if (in_max_output > 16) { + labels = True; + } + + shadow_data = TALLOC_ZERO_P(talloc_tos(), + struct shadow_copy_data); + if (tevent_req_nomem(shadow_data, req)) { + DEBUG(0,("TALLOC_ZERO() failed!\n")); + return tevent_req_post(req, ev); + } + + /* + * Call the VFS routine to actually do the work. + */ + if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels) + != 0) { + if (errno == ENOSYS) { + DEBUG(5, ("FSCTL_GET_SHADOW_COPY_DATA: " + "connectpath %s, not supported.\n", + smbreq->conn->connectpath)); + status = NT_STATUS_NOT_SUPPORTED; + } else { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: " + "connectpath %s, failed.\n", + smbreq->conn->connectpath)); + status = map_nt_error_from_unix(errno); + } + TALLOC_FREE(shadow_data); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + labels_data_count = + (shadow_data->num_volumes*2*sizeof(SHADOW_COPY_LABEL)) + + 2; + + if (labels) { + data_count = 12+labels_data_count+4; + } else { + data_count = 16; + } + + if (labels && (in_max_output < data_count)) { + DEBUG(0, ("FSCTL_GET_SHADOW_COPY_DATA: " + "in_max_output(%u) too small (%u) bytes " + "needed!\n", in_max_output, data_count)); + TALLOC_FREE(shadow_data); + tevent_req_nterror(req, NT_STATUS_BUFFER_TOO_SMALL); + return tevent_req_post(req, ev); + } + + state->out_output = data_blob_talloc(state, NULL, data_count); + if (tevent_req_nomem(state->out_output.data, req)) { + return tevent_req_post(req, ev); + } + + pdata = (char *)state->out_output.data; + + /* num_volumes 4 bytes */ + SIVAL(pdata, 0, shadow_data->num_volumes); + + if (labels) { + /* num_labels 4 bytes */ + SIVAL(pdata, 4, shadow_data->num_volumes); + } + + /* needed_data_count 4 bytes */ + SIVAL(pdata, 8, labels_data_count+4); + + pdata += 12; + + DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for " + "path[%s].\n", + shadow_data->num_volumes, fsp_str_dbg(fsp))); + if (labels && shadow_data->labels) { + for (i=0; inum_volumes; i++) { + srvstr_push(pdata, smbreq->flags2, + pdata, shadow_data->labels[i], + 2*sizeof(SHADOW_COPY_LABEL), + STR_UNICODE|STR_TERMINATE); + pdata += 2*sizeof(SHADOW_COPY_LABEL); + DEBUGADD(10, ("Label[%u]: '%s'\n", i, + shadow_data->labels[i])); + } + } + + TALLOC_FREE(shadow_data); + + tevent_req_done(req); + return tevent_req_post(req, ev); + } + default: if (IS_IPC(smbreq->conn)) { tevent_req_nterror(req, NT_STATUS_FS_DRIVER_REQUIRED); -- 1.7.3.1 From f48ffeefa8c46d79f26da21d6602e33c7017472a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 30 May 2011 12:06:31 +0200 Subject: s3: Remove SHADOW_COPY_DATA typedef (cherry picked from commit 0ec9a90c29b86435f32c1d47d89df85fa51742f2) --- source3/include/ntioctl.h | 4 ++-- source3/modules/vfs_default.c | 5 ++++- source3/modules/vfs_full_audit.c | 3 ++- source3/modules/vfs_shadow_copy.c | 5 ++++- source3/modules/vfs_shadow_copy2.c | 4 ++-- source3/modules/vfs_time_audit.c | 2 +- source3/smbd/nttrans.c | 5 +++-- source3/smbd/vfs.c | 2 +- 8 files changed, 19 insertions(+), 11 deletions(-) diff --git a/source3/include/ntioctl.h b/source3/include/ntioctl.h index 41b1dce..3ed4a19 100644 --- a/source3/include/ntioctl.h +++ b/source3/include/ntioctl.h @@ -77,13 +77,13 @@ /* For FSCTL_GET_SHADOW_COPY_DATA ...*/ typedef char SHADOW_COPY_LABEL[25]; -typedef struct shadow_copy_data { +struct shadow_copy_data { TALLOC_CTX *mem_ctx; /* Total number of shadow volumes currently mounted */ uint32 num_volumes; /* Concatenated list of labels */ SHADOW_COPY_LABEL *labels; -} SHADOW_COPY_DATA; +}; #endif /* _NTIOCTL_H */ diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 5d6b512..4d06a10 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -84,7 +84,10 @@ static int vfswrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_T #endif } -static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, bool labels) +static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle, + struct files_struct *fsp, + struct shadow_copy_data *shadow_copy_data, + bool labels) { errno = ENOSYS; return -1; /* Not implemented. */ diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index a723a0c..17713f0 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -695,7 +695,8 @@ static int smb_full_audit_set_quota(struct vfs_handle_struct *handle, static int smb_full_audit_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, - SHADOW_COPY_DATA *shadow_copy_data, bool labels) + struct shadow_copy_data *shadow_copy_data, + bool labels) { int result; diff --git a/source3/modules/vfs_shadow_copy.c b/source3/modules/vfs_shadow_copy.c index b93f98d..c1ffac7 100644 --- a/source3/modules/vfs_shadow_copy.c +++ b/source3/modules/vfs_shadow_copy.c @@ -216,7 +216,10 @@ static int shadow_copy_closedir(vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp return 0; } -static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, bool labels) +static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, + files_struct *fsp, + struct shadow_copy_data *shadow_copy_data, + bool labels) { SMB_STRUCT_DIR *p = SMB_VFS_NEXT_OPENDIR(handle,fsp->conn->connectpath,NULL,0); diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index df3bde7..f612c1b 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -837,7 +837,7 @@ static int shadow_copy2_label_cmp_desc(const void *x, const void *y) sort the shadow copy data in ascending or descending order */ static void shadow_copy2_sort_data(vfs_handle_struct *handle, - SHADOW_COPY_DATA *shadow_copy2_data) + struct shadow_copy_data *shadow_copy2_data) { int (*cmpfunc)(const void *, const void *); const char *sort; @@ -869,7 +869,7 @@ static void shadow_copy2_sort_data(vfs_handle_struct *handle, static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle, files_struct *fsp, - SHADOW_COPY_DATA *shadow_copy2_data, + struct shadow_copy_data *shadow_copy2_data, bool labels) { SMB_STRUCT_DIR *p; diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 37fe1c6..d21542c 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -144,7 +144,7 @@ static int smb_time_audit_set_quota(struct vfs_handle_struct *handle, static int smb_time_audit_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, - SHADOW_COPY_DATA *shadow_copy_data, + struct shadow_copy_data *shadow_copy_data, bool labels) { int result; diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 5b14182..524d490 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -2214,7 +2214,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, * Allocate the correct amount and return the pointer to let * it be deallocated when we return. */ - SHADOW_COPY_DATA *shadow_data = NULL; + struct shadow_copy_data *shadow_data = NULL; TALLOC_CTX *shadow_mem_ctx = NULL; bool labels = False; uint32 labels_data_count = 0; @@ -2243,7 +2243,8 @@ static void call_nt_transact_ioctl(connection_struct *conn, return; } - shadow_data = TALLOC_ZERO_P(shadow_mem_ctx,SHADOW_COPY_DATA); + shadow_data = TALLOC_ZERO_P(shadow_mem_ctx, + struct shadow_copy_data); if (shadow_data == NULL) { DEBUG(0,("TALLOC_ZERO() failed!\n")); talloc_destroy(shadow_mem_ctx); diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 3bde0a3..bdcb8e4 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1174,7 +1174,7 @@ int smb_vfs_call_set_quota(struct vfs_handle_struct *handle, int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, - SHADOW_COPY_DATA *shadow_copy_data, + struct shadow_copy_data *shadow_copy_data, bool labels) { VFS_FIND(get_shadow_copy_data); -- 1.7.3.1 From 578d1abc336c2e3408ac955b59643695eb0877b2 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 30 May 2011 12:11:53 +0200 Subject: struct make "struct shadow_copy_data" its own talloc context (cherry picked from commit d77854fbb22bc9237cea14aae1179bbfe3bd0998) --- source3/include/ntioctl.h | 1 - source3/modules/vfs_shadow_copy.c | 2 +- source3/modules/vfs_shadow_copy2.c | 2 +- source3/smbd/nttrans.c | 21 +++++---------------- 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/source3/include/ntioctl.h b/source3/include/ntioctl.h index 3ed4a19..18707c5 100644 --- a/source3/include/ntioctl.h +++ b/source3/include/ntioctl.h @@ -78,7 +78,6 @@ typedef char SHADOW_COPY_LABEL[25]; struct shadow_copy_data { - TALLOC_CTX *mem_ctx; /* Total number of shadow volumes currently mounted */ uint32 num_volumes; /* Concatenated list of labels */ diff --git a/source3/modules/vfs_shadow_copy.c b/source3/modules/vfs_shadow_copy.c index c1ffac7..1db47d2 100644 --- a/source3/modules/vfs_shadow_copy.c +++ b/source3/modules/vfs_shadow_copy.c @@ -253,7 +253,7 @@ static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, continue; } - tlabels = (SHADOW_COPY_LABEL *)TALLOC_REALLOC(shadow_copy_data->mem_ctx, + tlabels = (SHADOW_COPY_LABEL *)TALLOC_REALLOC(shadow_copy_data, shadow_copy_data->labels, (shadow_copy_data->num_volumes+1)*sizeof(SHADOW_COPY_LABEL)); if (tlabels == NULL) { diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index f612c1b..fedfb53 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -918,7 +918,7 @@ static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle, continue; } - tlabels = talloc_realloc(shadow_copy2_data->mem_ctx, + tlabels = talloc_realloc(shadow_copy2_data, shadow_copy2_data->labels, SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1); if (tlabels == NULL) { diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 524d490..427e566 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -2215,7 +2215,6 @@ static void call_nt_transact_ioctl(connection_struct *conn, * it be deallocated when we return. */ struct shadow_copy_data *shadow_data = NULL; - TALLOC_CTX *shadow_mem_ctx = NULL; bool labels = False; uint32 labels_data_count = 0; uint32 i; @@ -2236,29 +2235,19 @@ static void call_nt_transact_ioctl(connection_struct *conn, labels = True; } - shadow_mem_ctx = talloc_init("SHADOW_COPY_DATA"); - if (shadow_mem_ctx == NULL) { - DEBUG(0,("talloc_init(SHADOW_COPY_DATA) failed!\n")); - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - shadow_data = TALLOC_ZERO_P(shadow_mem_ctx, + shadow_data = TALLOC_ZERO_P(talloc_tos(), struct shadow_copy_data); if (shadow_data == NULL) { DEBUG(0,("TALLOC_ZERO() failed!\n")); - talloc_destroy(shadow_mem_ctx); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } - shadow_data->mem_ctx = shadow_mem_ctx; - /* * Call the VFS routine to actually do the work. */ if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) { - talloc_destroy(shadow_data->mem_ctx); + TALLOC_FREE(shadow_data); if (errno == ENOSYS) { DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n", conn->connectpath)); @@ -2283,14 +2272,14 @@ static void call_nt_transact_ioctl(connection_struct *conn, if (max_data_countmem_ctx); + TALLOC_FREE(shadow_data); reply_nterror(req, NT_STATUS_BUFFER_TOO_SMALL); return; } pdata = nttrans_realloc(ppdata, data_count); if (pdata == NULL) { - talloc_destroy(shadow_data->mem_ctx); + TALLOC_FREE(shadow_data); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } @@ -2323,7 +2312,7 @@ static void call_nt_transact_ioctl(connection_struct *conn, } } - talloc_destroy(shadow_data->mem_ctx); + TALLOC_FREE(shadow_data); send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, pdata, data_count); -- 1.7.3.1