diff options
author | Richard Sharpe <realrichardsharpe@gmail.com> | 2011-09-16 11:52:22 -0700 |
---|---|---|
committer | Richard Sharpe <realrichardsharpe@gmail.com> | 2011-10-01 07:02:20 -0700 |
commit | c875ab8747d65cc6556228616f076b0928013c87 (patch) | |
tree | bc7b582ac872d66273e8a1cd643770d6b01aa63a /source3 | |
parent | e8f143a45cceb8d2c01d45167a0c90d5c7f38289 (diff) | |
download | samba-c875ab8747d65cc6556228616f076b0928013c87.tar.gz samba-c875ab8747d65cc6556228616f076b0928013c87.tar.bz2 samba-c875ab8747d65cc6556228616f076b0928013c87.zip |
Move FSCTL handling into the VFS. Initial code changes. Passes smbtorture NTTRANS-FSCTL. Test added to selftests.
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/vfs.h | 22 | ||||
-rw-r--r-- | source3/include/vfs_macros.h | 6 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 335 | ||||
-rwxr-xr-x | source3/selftest/tests.py | 2 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 367 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 17 |
6 files changed, 413 insertions, 336 deletions
diff --git a/source3/include/vfs.h b/source3/include/vfs.h index b47e80f674..3b5e0e7f6a 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -136,6 +136,7 @@ /* Leave at 28 - not yet released. Rename open function to open_fn. - gd */ /* Leave at 28 - not yet released. Make getwd function always return malloced memory. JRA. */ /* Bump to version 29 - Samba 3.6.0 will ship with interface version 28. */ +/* Leave at 29 - not yet releases. Add fsctl. Richard Sharpe */ #define SMB_VFS_INTERFACE_VERSION 29 /* @@ -329,6 +330,17 @@ struct vfs_fn_pointers { TALLOC_CTX *mem_ctx, char **mapped_name); + NTSTATUS (*fsctl)(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *ctx, + uint32_t function, + uint16_t req_flags, + const uint8_t *_in_data, + uint32_t in_len, + uint8_t **_out_data, + uint32_t max_out_len, + uint32_t *out_len); + /* NT ACL operations. */ NTSTATUS (*fget_nt_acl)(struct vfs_handle_struct *handle, @@ -692,6 +704,16 @@ NTSTATUS smb_vfs_call_translate_name(struct vfs_handle_struct *handle, enum vfs_translate_direction direction, TALLOC_CTX *mem_ctx, char **mapped_name); +NTSTATUS smb_vfs_call_fsctl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *ctx, + uint32_t function, + uint16_t req_flags, + const uint8_t *_in_data, + uint32_t in_len, + uint8_t **_out_data, + uint32_t max_out_len, + uint32_t *out_len); NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32 security_info, diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index c7686f1db5..3dd6a64249 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -364,6 +364,12 @@ #define SMB_VFS_NEXT_TRANSLATE_NAME(handle, name, direction, mem_ctx, mapped_name) \ smb_vfs_call_translate_name((handle)->next, (name), (direction), (mem_ctx), (mapped_name)) +#define SMB_VFS_FSCTL(fsp, ctx, function, req_flags, in_data, in_len, out_data, max_out_len, out_len) \ + smb_vfs_call_fsctl((fsp)->conn->vfs_handles, (fsp), (ctx), (function), (req_flags), (in_data), (in_len), (out_data), (max_out_len), (out_len)) + +#define SMB_VFS_NEXT_FSCTL(handle, fsp, ctx, function, req_flags, in_data, in_len, out_data, max_out_len, out_len) \ + smb_vfs_call_fsctl((handle)->next, (fsp), (ctx), (function), (req_flags), (in_data), (in_len), (out_data), (max_out_len), (out_len)) + #define SMB_VFS_FGET_NT_ACL(fsp, security_info, ppdesc) \ smb_vfs_call_fget_nt_acl((fsp)->conn->vfs_handles, (fsp), (security_info), (ppdesc)) #define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc) \ diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 55b6bc7bfc..d1bf95eb23 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -24,6 +24,8 @@ #include "smbd/smbd.h" #include "ntioctl.h" #include "smbprofile.h" +#include "../libcli/security/security.h" +#include "passdb/lookup_sid.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS @@ -591,6 +593,338 @@ static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle, return NT_STATUS_NONE_MAPPED; } +/* + * Implement the default fsctl operation. + */ +static bool vfswrap_logged_ioctl_message = false; + +static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *ctx, + uint32_t function, + uint16_t req_flags, /* Needed for UNICODE ... */ + const uint8_t *_in_data, + uint32_t in_len, + uint8_t **_out_data, + uint32_t max_out_len, + uint32_t *out_len) +{ + const char *in_data = (const char *)_in_data; + char **out_data = (char **)_out_data; + + switch (function) { + case FSCTL_SET_SPARSE: + { + bool set_sparse = true; + NTSTATUS status; + + if (in_len >= 1 && in_data[0] == 0) { + set_sparse = false; + } + + status = file_set_sparse(handle->conn, fsp, set_sparse); + + DEBUG(NT_STATUS_IS_OK(status) ? 10 : 9, + ("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n", + smb_fname_str_dbg(fsp->fsp_name), set_sparse, + nt_errstr(status))); + + return status; + } + + case FSCTL_CREATE_OR_GET_OBJECT_ID: + { + unsigned char objid[16]; + char *return_data = NULL; + + /* This should return the object-id on this file. + * I think I'll make this be the inode+dev. JRA. + */ + + DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on FID[0x%04X]\n",fsp->fnum)); + + *out_len = (max_out_len >= 64) ? 64 : max_out_len; + /* Hmmm, will this cause problems if less data asked for? */ + return_data = talloc_array(ctx, char, 64); + if (return_data == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* For backwards compatibility only store the dev/inode. */ + push_file_id_16(return_data, &fsp->file_id); + memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16); + push_file_id_16(return_data+32, &fsp->file_id); + *out_data = return_data; + return NT_STATUS_OK; + } + + case FSCTL_GET_REPARSE_POINT: + { + /* Fail it with STATUS_NOT_A_REPARSE_POINT */ + DEBUG(10, ("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X] Status: NOT_IMPLEMENTED\n", fsp->fnum)); + return NT_STATUS_NOT_A_REPARSE_POINT; + } + + case FSCTL_SET_REPARSE_POINT: + { + /* Fail it with STATUS_NOT_A_REPARSE_POINT */ + DEBUG(10, ("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X] Status: NOT_IMPLEMENTED\n", fsp->fnum)); + return NT_STATUS_NOT_A_REPARSE_POINT; + } + + case FSCTL_GET_SHADOW_COPY_DATA: + { + /* + * 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 labels_data_count = 0; + uint32 i; + char *cur_pdata = NULL; + + if (max_out_len < 16) { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n", + max_out_len)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (max_out_len > 16) { + labels = True; + } + + shadow_data = talloc_zero(ctx, struct shadow_copy_data); + if (shadow_data == NULL) { + DEBUG(0,("TALLOC_ZERO() failed!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* + * Call the VFS routine to actually do the work. + */ + if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) { + TALLOC_FREE(shadow_data); + if (errno == ENOSYS) { + DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n", + fsp->conn->connectpath)); + return NT_STATUS_NOT_SUPPORTED; + } else { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n", + fsp->conn->connectpath)); + return NT_STATUS_UNSUCCESSFUL; + } + } + + labels_data_count = (shadow_data->num_volumes * 2 * + sizeof(SHADOW_COPY_LABEL)) + 2; + + if (!labels) { + *out_len = 16; + } else { + *out_len = 12 + labels_data_count + 4; + } + + if (max_out_len < *out_len) { + DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n", + max_out_len, *out_len)); + TALLOC_FREE(shadow_data); + return NT_STATUS_BUFFER_TOO_SMALL; + } + + cur_pdata = talloc_array(ctx, char, *out_len); + if (cur_pdata == NULL) { + TALLOC_FREE(shadow_data); + return NT_STATUS_NO_MEMORY; + } + + *out_data = cur_pdata; + + /* num_volumes 4 bytes */ + SIVAL(cur_pdata, 0, shadow_data->num_volumes); + + if (labels) { + /* num_labels 4 bytes */ + SIVAL(cur_pdata, 4, shadow_data->num_volumes); + } + + /* needed_data_count 4 bytes */ + SIVAL(cur_pdata, 8, labels_data_count + 4); + + cur_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; i<shadow_data->num_volumes; i++) { + srvstr_push(cur_pdata, req_flags, + 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_FREE(shadow_data); + + return NT_STATUS_OK; + } + + case FSCTL_FIND_FILES_BY_SID: + { + /* pretend this succeeded - + * + * we have to send back a list with all files owned by this SID + * + * but I have to check that --metze + */ + struct dom_sid sid; + uid_t uid; + size_t sid_len; + + DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n", fsp->fnum)); + + if (in_len < 8) { + /* NT_STATUS_BUFFER_TOO_SMALL maybe? */ + return NT_STATUS_INVALID_PARAMETER; + } + + sid_len = MIN(in_len - 4,SID_MAX_SIZE); + + /* unknown 4 bytes: this is not the length of the sid :-( */ + /*unknown = IVAL(pdata,0);*/ + + if (!sid_parse(in_data + 4, sid_len, &sid)) { + return NT_STATUS_INVALID_PARAMETER; + } + DEBUGADD(10, ("for SID: %s\n", sid_string_dbg(&sid))); + + if (!sid_to_uid(&sid, &uid)) { + DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n", + sid_string_dbg(&sid), + (unsigned long)sid_len)); + uid = (-1); + } + + /* we can take a look at the find source :-) + * + * find ./ -uid $uid -name '*' is what we need here + * + * + * and send 4bytes len and then NULL terminated unicode strings + * 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) + * + * 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, + * so we have to cache the result + * + * --metze + */ + + /* this works for now... */ + return NT_STATUS_OK; + } + + case FSCTL_QUERY_ALLOCATED_RANGES: + { + /* FIXME: This is just a dummy reply, telling that all of the + * file is allocated. MKS cp needs that. + * Adding the real allocated ranges via FIEMAP on Linux + * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make + * this FSCTL correct for sparse files. + */ + NTSTATUS status; + uint64_t offset, length; + char *out_data_tmp = NULL; + + if (in_len != 16) { + DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n", + in_len)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (max_out_len < 16) { + DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n", + max_out_len)); + return NT_STATUS_INVALID_PARAMETER; + } + + offset = BVAL(in_data,0); + length = BVAL(in_data,8); + + if (offset + length < offset) { + /* No 64-bit integer wrap. */ + return NT_STATUS_INVALID_PARAMETER; + } + + /* Shouldn't this be SMB_VFS_STAT ... ? */ + status = vfs_stat_fsp(fsp); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *out_len = 16; + out_data_tmp = talloc_array(ctx, char, *out_len); + if (out_data_tmp == NULL) { + DEBUG(10, ("unable to allocate memory for response\n")); + return NT_STATUS_NO_MEMORY; + } + + if (offset > fsp->fsp_name->st.st_ex_size || + fsp->fsp_name->st.st_ex_size == 0 || + length == 0) { + memset(out_data_tmp, 0, *out_len); + } else { + uint64_t end = offset + length; + end = MIN(end, fsp->fsp_name->st.st_ex_size); + SBVAL(out_data_tmp, 0, 0); + SBVAL(out_data_tmp, 8, end); + } + + *out_data = out_data_tmp; + + return NT_STATUS_OK; + } + + case FSCTL_IS_VOLUME_DIRTY: + { + DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on FID[0x%04X] " + "(but not implemented)\n", fsp->fnum)); + /* + * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx + * says we have to respond with NT_STATUS_INVALID_PARAMETER + */ + return NT_STATUS_INVALID_PARAMETER; + } + + default: + /* + * Only print once ... unfortunately there could be lots of + * different FSCTLs that are called. + */ + if (!vfswrap_logged_ioctl_message) { + vfswrap_logged_ioctl_message = true; + DEBUG(2, ("%s (0x%x): Currently not implemented.\n", + __func__, function)); + } + } + + return NT_STATUS_NOT_SUPPORTED; +} + /******************************************************************** Given a stat buffer return the allocated size on disk, taking into account sparse files. @@ -1732,6 +2066,7 @@ static struct vfs_fn_pointers vfs_default_fns = { .strict_lock = vfswrap_strict_lock, .strict_unlock = vfswrap_strict_unlock, .translate_name = vfswrap_translate_name, + .fsctl = vfswrap_fsctl, /* NT ACL operations. */ diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index ff350eba4c..b4c41fd404 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -59,7 +59,7 @@ tests=[ "FDPASS", "LOCK1", "LOCK2", "LOCK3", "LOCK4", "LOCK5", "LOCK6", "LOCK7", "TCON2", "IOCTL", "CHKPATH", "FDSESS", "LOCAL-SUBSTITUTE", "CHAIN1", "CHAIN2", "GETADDRINFO", "POSIX", "UID-REGRESSION-TEST", "SHORTNAME-TEST", "LOCAL-BASE64", "LOCAL-GENCACHE", "POSIX-APPEND", - "CASE-INSENSITIVE-CREATE", "SMB2-BASIC", + "CASE-INSENSITIVE-CREATE", "SMB2-BASIC", "NTTRANS-FSCTL", "BAD-NBT-SESSION", "LOCAL-string_to_sid", "LOCAL-CONVERT-STRING" ] diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index d24dd1ef2d..c69aa6ae2f 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -2121,12 +2121,16 @@ static void call_nt_transact_ioctl(connection_struct *conn, char **ppdata, uint32 data_count, uint32 max_data_count) { + NTSTATUS status; uint32 function; uint16 fidnum; files_struct *fsp; uint8 isFSctl; uint8 compfilter; + char *out_data = NULL; + uint32 out_data_len = 0; char *pdata = *ppdata; + TALLOC_CTX *ctx = talloc_tos(); if (setup_count != 8) { DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count)); @@ -2139,353 +2143,46 @@ static void call_nt_transact_ioctl(connection_struct *conn, 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", + DEBUG(10, ("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n", function, fidnum, isFSctl, compfilter)); fsp=file_fsp(req, fidnum); - /* 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);*/ - - SMB_PERFCOUNT_SET_IOCTL(&req->pcd, function); - - switch (function) { - case FSCTL_SET_SPARSE: - { - bool set_sparse = true; - NTSTATUS status; - - if (data_count >= 1 && pdata[0] == 0) { - set_sparse = false; - } - DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X]set[%u]\n", - fidnum, set_sparse)); - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - status = file_set_sparse(conn, fsp, set_sparse); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(9,("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n", - smb_fname_str_dbg(fsp->fsp_name), set_sparse, nt_errstr(status))); - reply_nterror(req, status); - return; - } - - DEBUG(10,("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n", - smb_fname_str_dbg(fsp->fsp_name), set_sparse, nt_errstr(status))); - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); + /* + * We don't really implement IOCTLs, especially on files. + */ + if (!isFSctl) { + DEBUG(10, ("isFSctl: 0x%02X indicates IOCTL, not FSCTL!\n", + isFSctl)); + reply_nterror(req, NT_STATUS_NOT_SUPPORTED); return; } - case FSCTL_CREATE_OR_GET_OBJECT_ID: - { - unsigned char objid[16]; - - /* This should return the object-id on this file. - * I think I'll make this be the inode+dev. JRA. - */ - - DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on FID[0x%04X]\n",fidnum)); - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - data_count = 64; - pdata = nttrans_realloc(ppdata, data_count); - if (pdata == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - /* For backwards compatibility only store the dev/inode. */ - push_file_id_16(pdata, &fsp->file_id); - memcpy(pdata+16,create_volume_objectid(conn,objid),16); - push_file_id_16(pdata+32, &fsp->file_id); - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, - pdata, data_count); + /* Has to be for an open file! */ + if (!check_fsp_open(conn, req, fsp)) { return; } - case FSCTL_GET_REPARSE_POINT: - /* pretend this fail - my winXP does it like this - * --metze - */ - - DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); - reply_nterror(req, NT_STATUS_NOT_A_REPARSE_POINT); - return; - - case FSCTL_SET_REPARSE_POINT: - /* pretend this fail - I'm assuming this because of the FSCTL_GET_REPARSE_POINT case. - * --metze - */ - - DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); - reply_nterror(req, NT_STATUS_NOT_A_REPARSE_POINT); - return; - - 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. - */ - struct shadow_copy_data *shadow_data = NULL; - bool labels = False; - uint32 labels_data_count = 0; - uint32 i; - char *cur_pdata; - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - if (max_data_count < 16) { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n", - max_data_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (max_data_count > 16) { - labels = True; - } - - shadow_data = talloc_zero(talloc_tos(), - struct shadow_copy_data); - if (shadow_data == NULL) { - DEBUG(0,("TALLOC_ZERO() failed!\n")); - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - /* - * Call the VFS routine to actually do the work. - */ - if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) { - TALLOC_FREE(shadow_data); - if (errno == ENOSYS) { - DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n", - conn->connectpath)); - reply_nterror(req, NT_STATUS_NOT_SUPPORTED); - return; - } else { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n", - conn->connectpath)); - reply_nterror(req, NT_STATUS_UNSUCCESSFUL); - return; - } - } - - 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_count<data_count) { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n", - max_data_count,data_count)); - TALLOC_FREE(shadow_data); - reply_nterror(req, NT_STATUS_BUFFER_TOO_SMALL); - return; - } - - pdata = nttrans_realloc(ppdata, data_count); - if (pdata == NULL) { - TALLOC_FREE(shadow_data); - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - 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+4); - - cur_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;i<shadow_data->num_volumes;i++) { - srvstr_push(pdata, req->flags2, - 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_FREE(shadow_data); - - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, - pdata, data_count); - - return; - } - - case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */ - { - /* pretend this succeeded - - * - * we have to send back a list with all files owned by this SID - * - * but I have to check that --metze - */ - struct dom_sid sid; - uid_t uid; - size_t sid_len; - - DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum)); - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - if (data_count < 8) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - sid_len = MIN(data_count-4,SID_MAX_SIZE); - - /* unknown 4 bytes: this is not the length of the sid :-( */ - /*unknown = IVAL(pdata,0);*/ - - if (!sid_parse(pdata+4,sid_len,&sid)) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - DEBUGADD(10, ("for SID: %s\n", sid_string_dbg(&sid))); - - if (!sid_to_uid(&sid, &uid)) { - DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n", - sid_string_dbg(&sid), - (unsigned long)sid_len)); - uid = (-1); - } - - /* we can take a look at the find source :-) - * - * find ./ -uid $uid -name '*' is what we need here - * - * - * and send 4bytes len and then NULL terminated unicode strings - * 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, - * so we have to cache the result - * - * --metze - */ - - /* this works for now... */ - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); - return; - } - case FSCTL_QUERY_ALLOCATED_RANGES: - { - /* FIXME: This is just a dummy reply, telling that all of the - * file is allocated. MKS cp needs that. - * Adding the real allocated ranges via FIEMAP on Linux - * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make - * this FSCTL correct for sparse files. - */ - NTSTATUS status; - uint64_t offset, length; - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - if (data_count != 16) { - DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n", - data_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (max_data_count < 16) { - DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_data_count(%u) < 16 is invalid!\n", - max_data_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - offset = BVAL(pdata,0); - length = BVAL(pdata,8); - - if (offset + length < offset) { - /* No 64-bit integer wrap. */ - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - status = vfs_stat_fsp(fsp); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } + SMB_PERFCOUNT_SET_IOCTL(&req->pcd, function); - if (offset > fsp->fsp_name->st.st_ex_size || - fsp->fsp_name->st.st_ex_size == 0 || - length == 0) { - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); - } else { - uint64_t end = offset + length; - end = MIN(end, fsp->fsp_name->st.st_ex_size); - SBVAL(pdata,0,0); - SBVAL(pdata,8,end); - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, - pdata, 16); - } - return; - } - case FSCTL_IS_VOLUME_DIRTY: - DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on FID[0x%04X] " - "(but not implemented)\n", (int)fidnum)); - /* - * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx - * says we have to respond with NT_STATUS_INVALID_PARAMETER - */ - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - default: - /* Only print this once... */ - if (!logged_ioctl_message) { - logged_ioctl_message = true; - DEBUG(2,("call_nt_transact_ioctl(0x%x): " - "Currently not implemented.\n", - function)); - } + /* + * out_data might be allocated by the VFS module, but talloc should be + * used, and should be cleaned up when the request ends. + */ + status = SMB_VFS_FSCTL(fsp, + ctx, + function, + req->flags2, + (uint8_t *)pdata, + data_count, + (uint8_t **)&out_data, + max_data_count, + &out_data_len); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + } else { + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, out_data, out_data_len); } - - reply_nterror(req, NT_STATUS_NOT_SUPPORTED); } diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index c6edef282f..9b1f2484b4 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1721,6 +1721,23 @@ NTSTATUS smb_vfs_call_translate_name(struct vfs_handle_struct *handle, mapped_name); } +NTSTATUS smb_vfs_call_fsctl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *ctx, + uint32_t function, + uint16_t req_flags, + const uint8_t *in_data, + uint32_t in_len, + uint8_t **out_data, + uint32_t max_out_len, + uint32_t *out_len) +{ + VFS_FIND(fsctl); + return handle->fns->fsctl(handle, fsp, ctx, function, req_flags, + in_data, in_len, out_data, max_out_len, + out_len); +} + NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32 security_info, |