The branch, master has been updated via 595cc42 Add the new test_nttrans_fsctl.c to waf via c875ab8 Move FSCTL handling into the VFS. Initial code changes. Passes smbtorture NTTRANS-FSCTL. Test added to selftests. via e8f143a Add a torture test to test existing FSCTL responses from c704d92 Fix bug #8493 - DFS breaks zip file extracting unless "follow symlinks = no" set
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 595cc42a46f5dfbac5c17a403fb1f82769f26ff2 Author: Richard Sharpe <realrichardsha...@gmail.com> Date: Sat Oct 1 09:03:13 2011 -0700 Add the new test_nttrans_fsctl.c to waf Autobuild-User: Richard Sharpe <sha...@samba.org> Autobuild-Date: Sat Oct 1 19:36:53 CEST 2011 on sn-devel-104 commit c875ab8747d65cc6556228616f076b0928013c87 Author: Richard Sharpe <realrichardsha...@gmail.com> Date: Fri Sep 16 11:52:22 2011 -0700 Move FSCTL handling into the VFS. Initial code changes. Passes smbtorture NTTRANS-FSCTL. Test added to selftests. commit e8f143a45cceb8d2c01d45167a0c90d5c7f38289 Author: Richard Sharpe <realrichardsha...@gmail.com> Date: Thu Sep 15 16:13:54 2011 -0700 Add a torture test to test existing FSCTL responses ----------------------------------------------------------------------- Summary of changes: source3/Makefile.in | 1 + source3/include/vfs.h | 22 ++ source3/include/vfs_macros.h | 6 + source3/modules/vfs_default.c | 335 +++++++++++++++++++++++++++++++ source3/selftest/tests.py | 2 +- source3/smbd/nttrans.c | 367 +++------------------------------- source3/smbd/vfs.c | 17 ++ source3/torture/proto.h | 1 + source3/torture/test_nttrans_fsctl.c | 287 ++++++++++++++++++++++++++ source3/torture/torture.c | 1 + source3/wscript_build | 1 + 11 files changed, 704 insertions(+), 336 deletions(-) create mode 100644 source3/torture/test_nttrans_fsctl.c Changeset truncated at 500 lines: diff --git a/source3/Makefile.in b/source3/Makefile.in index bddde78..c736ae8 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -1251,6 +1251,7 @@ SMBTORTURE_OBJ1 = torture/torture.o torture/nbio.o torture/scanner.o torture/uta torture/test_async_echo.o \ torture/test_smbsock_any_connect.o \ torture/test_nttrans_create.o \ + torture/test_nttrans_fsctl.o \ torture/test_notify_online.o \ torture/test_addrchange.o \ torture/test_case_insensitive.o \ diff --git a/source3/include/vfs.h b/source3/include/vfs.h index b47e80f..3b5e0e7 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 c7686f1..3dd6a64 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 55b6bc7..d1bf95e 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 ff350eb..b4c41fd 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 d24dd1e..c69aa6a 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; -- Samba Shared Repository