From a83bac7571d067b672a181942c8fea6ffbfcc33f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 7 Aug 2003 21:47:46 +0000 Subject: Shadow copy API - Original work by "Ken Cross" , adapted into a patch by "Stefan (metze) Metzmacher" . Jeremy. (This used to be commit ce5c91d35dabc5ff6fb3df2b259ed186d6a7e0da) --- source3/include/ntioctl.h | 19 +++++ source3/include/smb_macros.h | 6 ++ source3/include/vfs.h | 9 ++- source3/include/vfs_macros.h | 3 + source3/smbd/nttrans.c | 171 +++++++++++++++++++++++++++++++++++++------ source3/smbd/vfs-wrap.c | 66 +++++++++-------- source3/smbd/vfs.c | 2 +- 7 files changed, 221 insertions(+), 55 deletions(-) (limited to 'source3') diff --git a/source3/include/ntioctl.h b/source3/include/ntioctl.h index 17791fde18..9814c88e5e 100644 --- a/source3/include/ntioctl.h +++ b/source3/include/ntioctl.h @@ -23,6 +23,8 @@ we only need the sparse flag */ +#ifndef _NTIOCTL_H +#define _NTIOCTL_H /* IOCTL information */ /* List of ioctl function codes that look to be of interest to remote clients like this. */ @@ -53,6 +55,8 @@ #define FSCTL_SIS_COPYFILE 0x00090100 #define FSCTL_SIS_LINK_FILES 0x0009C104 +#define FSCTL_GET_SHADOW_COPY_DATA 0x00144064 /* KJC -- Shadow Copy information */ + #if 0 #define FSCTL_SECURITY_ID_CHECK #define FSCTL_DISMOUNT_VOLUME @@ -66,3 +70,18 @@ #define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 #define IO_REPARSE_TAG_HSM 0xC0000004 #define IO_REPARSE_TAG_SIS 0x80000007 + + +/* For FSCTL_GET_SHADOW_COPY_DATA ...*/ +typedef char SHADOW_COPY_LABEL[25]; + +typedef 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/include/smb_macros.h b/source3/include/smb_macros.h index 21ccdf295c..178fd9c358 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -77,6 +77,12 @@ #define OPEN_CONN(conn) ((conn) && (conn)->open) #define IS_IPC(conn) ((conn) && (conn)->ipc) #define IS_PRINT(conn) ((conn) && (conn)->printer) +#define FSP_BELONGS_CONN(fsp,conn) do {\ + extern struct current_user current_user;\ + if (!((fsp) && (conn) && ((conn)==(fsp)->conn) && (current_user.vuid==(fsp)->vuid))) \ + return(ERROR_DOS(ERRDOS,ERRbadfid));\ + } while(0) + #define FNUM_OK(fsp,c) (OPEN_FSP(fsp) && (c)==(fsp)->conn && current_user.vuid==(fsp)->vuid) #define CHECK_FSP(fsp,conn) do {\ diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 452f4dc23b..dd489702aa 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -50,8 +50,8 @@ /* Changed to version 6 for the new module system, fixed cascading and quota functions. --metze */ /* Changed to version 7 to include the get_nt_acl info parameter. JRA. */ /* Changed to version 8 includes EA calls. JRA. */ - -#define SMB_VFS_INTERFACE_VERSION 8 +/* Changed to version 9 to include the get_shadow_data call. --metze */ +#define SMB_VFS_INTERFACE_VERSION 9 /* to bug old modules witch are trying to compile with the old functions */ @@ -91,6 +91,8 @@ typedef enum _vfs_op_type { SMB_VFS_OP_DISK_FREE, SMB_VFS_OP_GET_QUOTA, SMB_VFS_OP_SET_QUOTA, + SMB_VFS_OP_GET_SHADOW_COPY_DATA, + /* Directory operations */ @@ -196,6 +198,7 @@ struct vfs_ops { SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize); int (*get_quota)(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt); int (*set_quota)(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt); + int (*get_shadow_copy_data)(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, BOOL labels); /* Directory operations */ @@ -293,6 +296,7 @@ struct vfs_ops { struct vfs_handle_struct *disk_free; struct vfs_handle_struct *get_quota; struct vfs_handle_struct *set_quota; + struct vfs_handle_struct *get_shadow_copy_data; /* Directory operations */ @@ -379,6 +383,7 @@ struct vfs_ops { struct vfs_handle_struct *setxattr; struct vfs_handle_struct *lsetxattr; struct vfs_handle_struct *fsetxattr; + } handles; }; diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index fdbc1516e3..c4f63c352e 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -33,6 +33,7 @@ #define SMB_VFS_DISK_FREE(conn, path, small_query, bsize, dfree ,dsize) ((conn)->vfs.ops.disk_free((conn)->vfs.handles.disk_free, (conn), (path), (small_query), (bsize), (dfree), (dsize))) #define SMB_VFS_GET_QUOTA(conn, qtype, id, qt) ((conn)->vfs.ops.get_quota((conn)->vfs.handles.get_quota, (conn), (qtype), (id), (qt))) #define SMB_VFS_SET_QUOTA(conn, qtype, id, qt) ((conn)->vfs.ops.set_quota((conn)->vfs.handles.set_quota, (conn), (qtype), (id), (qt))) +#define SMB_VFS_GET_SHADOW_COPY_DATA(fsp,shadow_copy_data,labels) ((fsp)->conn->vfs.ops.get_shadow_copy_data((fsp)->conn->vfs.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels))) /* Directory operations */ #define SMB_VFS_OPENDIR(conn, fname) ((conn)->vfs.ops.opendir((conn)->vfs.handles.opendir, (conn), (fname))) @@ -128,6 +129,7 @@ #define SMB_VFS_OPAQUE_DISK_FREE(conn, path, small_query, bsize, dfree ,dsize) ((conn)->vfs_opaque.ops.disk_free((conn)->vfs_opaque.handles.disk_free, (conn), (path), (small_query), (bsize), (dfree), (dsize))) #define SMB_VFS_OPAQUE_GET_QUOTA(conn, qtype, id, qt) ((conn)->vfs_opaque.ops.get_quota((conn)->vfs_opaque.handles.get_quota, (conn), (qtype), (id), (qt))) #define SMB_VFS_OPAQUE_SET_QUOTA(conn, qtype, id, qt) ((conn)->vfs_opaque.ops.set_quota((conn)->vfs_opaque.handles.set_quota, (conn), (qtype), (id), (qt))) +#define SMB_VFS_OPAQUE_GET_SHADOW_COPY_DATA(fsp,shadow_copy_data,labels) ((fsp)->conn->vfs_opaque.ops.get_shadow_copy_data((fsp)->conn->vfs_opaque.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels))) /* Directory operations */ #define SMB_VFS_OPAQUE_OPENDIR(conn, fname) ((conn)->vfs_opaque.ops.opendir((conn)->vfs_opaque.handles.opendir, (conn), (fname))) @@ -223,6 +225,7 @@ #define SMB_VFS_NEXT_DISK_FREE(handle, conn, path, small_query, bsize, dfree ,dsize) ((handle)->vfs_next.ops.disk_free((handle)->vfs_next.handles.disk_free, (conn), (path), (small_query), (bsize), (dfree), (dsize))) #define SMB_VFS_NEXT_GET_QUOTA(handle, conn, qtype, id, qt) ((handle)->vfs_next.ops.get_quota((handle)->vfs_next.handles.get_quota, (conn), (qtype), (id), (qt))) #define SMB_VFS_NEXT_SET_QUOTA(handle, conn, qtype, id, qt) ((handle)->vfs_next.ops.set_quota((handle)->vfs_next.handles.set_quota, (conn), (qtype), (id), (qt))) +#define SMB_VFS_NEXT_GET_SHADOW_COPY_DATA(handle, fsp, shadow_copy_data ,labels) ((handle)->vfs_next.ops.get_shadow_copy_data((handle)->vfs_next.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels))) /* Directory operations */ #define SMB_VFS_NEXT_OPENDIR(handle, conn, fname) ((handle)->vfs_next.ops.opendir((handle)->vfs_next.handles.opendir, (conn), (fname))) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 3ffa6efa77..7a58e83877 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1724,7 +1724,11 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou char **ppparams, uint32 parameter_count, char **ppdata, uint32 data_count) { - unsigned fnum, control; + uint32 function; + uint16 fidnum; + files_struct *fsp; + uint8 isFSctl; + uint8 compfilter; static BOOL logged_message; char *pdata = *ppdata; @@ -1733,19 +1737,26 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } - fnum = SVAL(*ppsetup, 4); - control = IVAL(*ppsetup, 0); + function = IVAL(*ppsetup, 0); + fidnum = SVAL(*ppsetup, 4); + isFSctl = CVAL(*ppsetup, 6); + compfilter = CVAL(*ppsetup, 7); + + DEBUG(10,("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n", + function, fidnum, isFSctl, compfilter)); - DEBUG(10,("call_nt_transact_ioctl: fnum=%d control=0x%08x\n", - fnum, control)); + fsp=file_fsp(*ppsetup, 4); + /* this check is done in each implemented function case for now + because I don't want to break anything... --metze + FSP_BELONGS_CONN(fsp,conn);*/ - switch (control) { + switch (function) { case FSCTL_SET_SPARSE: /* pretend this succeeded - tho strictly we should mark the file sparse (if the local fs supports it) so we can know if we need to pre-allocate or not */ - DEBUG(10,("FSCTL_SET_SPARSE: fnum=%d control=0x%08x\n",fnum,control)); + DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); return -1; @@ -1754,7 +1765,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou but works ok like this --metze */ - DEBUG(10,("FSCTL_GET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + DEBUG(10,("FSCTL_0x000900C0: called on FID[0x%04X](but not implemented)\n",fidnum)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0); return -1; @@ -1763,7 +1774,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou * --metze */ - DEBUG(10,("FSCTL_GET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0); return -1; @@ -1772,10 +1783,125 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou * --metze */ - DEBUG(10,("FSCTL_SET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control)); + DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0); return -1; + case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/ + { + /* + * 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. + */ + uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount); + SHADOW_COPY_DATA *shadow_data = NULL; + TALLOC_CTX *shadow_mem_ctx = NULL; + BOOL labels = False; + uint32 labels_data_count = 0; + uint32 i; + char *cur_pdata; + + FSP_BELONGS_CONN(fsp,conn); + + if (max_data_count < 16) { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n", + max_data_count)); + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + + if (max_data_count > 16) { + labels = True; + } + + shadow_mem_ctx = talloc_init("SHADOW_COPY_DATA"); + if (shadow_mem_ctx == NULL) { + DEBUG(0,("talloc_init(SHADOW_COPY_DATA) failed!\n")); + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + shadow_data = (SHADOW_COPY_DATA *)talloc_zero(shadow_mem_ctx,sizeof(SHADOW_COPY_DATA)); + if (shadow_data == NULL) { + DEBUG(0,("talloc_zero() failed!\n")); + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + 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); + if (errno == ENOSYS) { + DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n", + conn->connectpath)); + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); + } else { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n", + conn->connectpath)); + return ERROR_NT(NT_STATUS_UNSUCCESSFUL); + } + } + + labels_data_count = (shadow_data->num_volumes*2*sizeof(SHADOW_COPY_LABEL))+2; + + if (!labels) { + data_count = 16; + } else { + data_count = 12+labels_data_count+4; + } + + if (max_data_countmem_ctx); + return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL); + } + + pdata = nttrans_realloc(ppdata, data_count); + if (pdata == NULL) { + talloc_destroy(shadow_data->mem_ctx); + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + cur_pdata = pdata; + + /* 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); + + cur_pdata+=12; + + DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n", + shadow_data->num_volumes,fsp->fsp_name)); + if (labels && shadow_data->labels) { + for (i=0;inum_volumes;i++) { + srvstr_push(outbuf, cur_pdata, shadow_data->labels[i], 2*sizeof(SHADOW_COPY_LABEL), STR_UNICODE|STR_TERMINATE); + cur_pdata+=2*sizeof(SHADOW_COPY_LABEL); + DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i])); + } + } + + talloc_destroy(shadow_data->mem_ctx); + + send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, pdata, data_count); + + return -1; + } + case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */ { /* pretend this succeeded - @@ -1783,24 +1909,24 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou * we have to send back a list with all files owned by this SID * * but I have to check that --metze - */ - + */ DOM_SID sid; uid_t uid; - size_t sid_len=SID_MAX_SIZE; - - DEBUG(10,("FSCTL_FIND_FILES_BY_SID: fnum=%d control=0x%08x\n",fnum,control)); + size_t sid_len = MIN(data_count-4,SID_MAX_SIZE); - /* this is not the length of the sid :-( so unknown 4 bytes */ - /*sid_len = IVAL(pdata,0); - DEBUGADD(0,("sid_len: (%u)\n",sid_len));*/ + DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum)); + + FSP_BELONGS_CONN(fsp,conn); + + /* unknown 4 bytes: this is not the length of the sid :-( */ + /*unknown = IVAL(pdata,0);*/ sid_parse(pdata+4,sid_len,&sid); - DEBUGADD(10,("SID: %s\n",sid_string_static(&sid))); + DEBUGADD(10,("for SID: %s\n",sid_string_static(&sid))); if (!NT_STATUS_IS_OK(sid_to_uid(&sid, &uid))) { - DEBUG(0,("sid_to_uid: failed, sid[%s]\n", - sid_string_static(&sid))); + DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%u]\n", + sid_string_static(&sid),sid_len)); uid = (-1); } @@ -1813,6 +1939,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou * for each file * * but I don't know how to deal with the paged results + * (maybe we can hang the result anywhere in the fsp struct) * * we don't send all files at once * and at the next we should *not* start from the beginning, @@ -1829,7 +1956,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou if (!logged_message) { logged_message = True; /* Only print this once... */ DEBUG(0,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n", - control)); + function)); } } diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c index 8d44a1a0fa..a76a7a6abd 100644 --- a/source3/smbd/vfs-wrap.c +++ b/source3/smbd/vfs-wrap.c @@ -49,6 +49,42 @@ SMB_BIG_UINT vfswrap_disk_free(vfs_handle_struct *handle, connection_struct *con result = sys_disk_free(path, small_query, bsize, dfree, dsize); return result; } + +int vfswrap_get_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt) +{ +#ifdef HAVE_SYS_QUOTAS + int result; + + START_PROFILE(syscall_get_quota); + result = sys_get_quota(conn->connectpath, qtype, id, qt); + END_PROFILE(syscall_get_quota); + return result; +#else + errno = ENOSYS; + return -1; +#endif +} + +int vfswrap_set_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt) +{ +#ifdef HAVE_SYS_QUOTAS + int result; + + START_PROFILE(syscall_set_quota); + result = sys_set_quota(conn->connectpath, qtype, id, qt); + END_PROFILE(syscall_set_quota); + return result; +#else + errno = ENOSYS; + return -1; +#endif +} + +int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, BOOL labels) +{ + errno = ENOSYS; + return -1; /* Not implemented. */ +} /* Directory operations */ @@ -756,36 +792,6 @@ int vfswrap_sys_acl_free_qualifier(vfs_handle_struct *handle, connection_struct return sys_acl_free_qualifier(qualifier, tagtype); } -int vfswrap_get_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt) -{ -#ifdef HAVE_SYS_QUOTAS - int result; - - START_PROFILE(syscall_get_quota); - result = sys_get_quota(conn->connectpath, qtype, id, qt); - END_PROFILE(syscall_get_quota); - return result; -#else - errno = ENOSYS; - return -1; -#endif -} - -int vfswrap_set_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt) -{ -#ifdef HAVE_SYS_QUOTAS - int result; - - START_PROFILE(syscall_set_quota); - result = sys_set_quota(conn->connectpath, qtype, id, qt); - END_PROFILE(syscall_set_quota); - return result; -#else - errno = ENOSYS; - return -1; -#endif -} - /**************************************************************** Extended attribute operations. *****************************************************************/ diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 5f3abe7efe..58a8a38792 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -56,6 +56,7 @@ static struct vfs_ops default_vfs = { vfswrap_disk_free, vfswrap_get_quota, vfswrap_set_quota, + vfswrap_get_shadow_copy_data, /* Directory operations */ @@ -140,7 +141,6 @@ static struct vfs_ops default_vfs = { vfswrap_setxattr, vfswrap_lsetxattr, vfswrap_fsetxattr - } }; -- cgit