From d931455e6e627511935fc82d2c6bc4e23743ebc3 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Nov 2005 06:31:33 +0000 Subject: r11773: added a SMB2-SETINFO test suite. This tests the following levels: BASIC_INFORMATION DISPOSITION_INFORMATION ALLOCATION_INFORMATION END_OF_FILE_INFORMATION POSITION_INFORMATION MODE_INFORMATION (This used to be commit 8804b6a7eb59ab0a9088f89d191194fba71befe3) --- source4/torture/smb2/config.mk | 3 +- source4/torture/smb2/setinfo.c | 224 +++++++++++++++++++++++++++++++++++++++++ source4/torture/smb2/util.c | 151 +++++++++++++++++++++++++++ 3 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 source4/torture/smb2/setinfo.c (limited to 'source4/torture/smb2') diff --git a/source4/torture/smb2/config.mk b/source4/torture/smb2/config.mk index 7c7cdeab62..bcd256a22b 100644 --- a/source4/torture/smb2/config.mk +++ b/source4/torture/smb2/config.mk @@ -6,7 +6,8 @@ ADD_OBJ_FILES = \ connect.o \ scan.o \ util.o \ - getinfo.o + getinfo.o \ + setinfo.o REQUIRED_SUBSYSTEMS = \ LIBCLI_SMB2 # End SUBSYSTEM TORTURE_SMB2 diff --git a/source4/torture/smb2/setinfo.c b/source4/torture/smb2/setinfo.c new file mode 100644 index 0000000000..a743c2e5d9 --- /dev/null +++ b/source4/torture/smb2/setinfo.c @@ -0,0 +1,224 @@ +/* + Unix SMB/CIFS implementation. + + SMB2 setinfo individual test suite + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "system/time.h" + +#define BASEDIR "" + +/* basic testing of all SMB2 setinfo calls + for each call we test that it succeeds, and where possible test + for consistency between the calls. +*/ +BOOL torture_smb2_setinfo(void) +{ + struct smb2_tree *tree; + BOOL ret = True; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct smb2_handle handle; + char *fname; + char *fname_new; + union smb_fileinfo finfo1, finfo2; + union smb_setfileinfo sfinfo; + NTSTATUS status, status2; + const char *call_name; + time_t basetime = (time(NULL) - 86400) & ~1; + int n = time(NULL) % 100; + + fname = talloc_asprintf(mem_ctx, BASEDIR "fnum_test_%d.txt", n); + fname_new = talloc_asprintf(mem_ctx, BASEDIR "fnum_test_new_%d.txt", n); + + if (!torture_smb2_connection(mem_ctx, &tree)) { + return False; + } + +#define RECREATE_FILE(fname) do { \ + smb2_util_close(tree, handle); \ + status = smb2_create_complex_file(tree, fname, &handle); \ + if (!NT_STATUS_IS_OK(status)) { \ + printf("(%s) ERROR: open of %s failed (%s)\n", \ + __location__, fname, nt_errstr(status)); \ + ret = False; \ + goto done; \ + }} while (0) + +#define RECREATE_BOTH do { \ + RECREATE_FILE(fname); \ + } while (0) + + RECREATE_BOTH; + +#define CHECK_CALL(call, rightstatus) do { \ + call_name = #call; \ + sfinfo.generic.level = RAW_SFILEINFO_ ## call; \ + sfinfo.generic.file.handle = handle; \ + status = smb2_setinfo_file(tree, &sfinfo); \ + if (!NT_STATUS_EQUAL(status, rightstatus)) { \ + printf("(%s) %s - %s (should be %s)\n", __location__, #call, \ + nt_errstr(status), nt_errstr(rightstatus)); \ + ret = False; \ + } \ + finfo1.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION; \ + finfo1.generic.in.handle = handle; \ + status2 = smb2_getinfo_file(tree, mem_ctx, &finfo1); \ + if (!NT_STATUS_IS_OK(status2)) { \ + printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \ + ret = False; \ + }} while (0) + +#define CHECK1(call) \ + do { if (NT_STATUS_IS_OK(status)) { \ + finfo2.generic.level = RAW_FILEINFO_ ## call; \ + finfo2.generic.in.handle = handle; \ + status2 = smb2_getinfo_file(tree, mem_ctx, &finfo2); \ + if (!NT_STATUS_IS_OK(status2)) { \ + printf("%s - %s\n", #call, nt_errstr(status2)); \ + } \ + }} while (0) + +#define CHECK_VALUE(call, stype, field, value) do { \ + CHECK1(call); \ + if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \ + printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \ + call_name, #stype, #field, \ + (uint_t)value, (uint_t)finfo2.stype.out.field); \ + dump_all_info(mem_ctx, &finfo1); \ + }} while (0) + +#define CHECK_TIME(call, stype, field, value) do { \ + CHECK1(call); \ + if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \ + printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \ + call_name, #stype, #field, \ + (uint_t)value, \ + (uint_t)nt_time_to_unix(finfo2.stype.out.field)); \ + printf("\t%s", timestring(mem_ctx, value)); \ + printf("\t%s\n", nt_time_string(mem_ctx, finfo2.stype.out.field)); \ + dump_all_info(mem_ctx, &finfo1); \ + }} while (0) + +#define CHECK_STR(call, stype, field, value) do { \ + CHECK1(call); \ + if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && strcmp(finfo2.stype.out.field, value) != 0) { \ + printf("(%s) %s - %s/%s should be '%s' - '%s'\n", __location__, \ + call_name, #stype, #field, \ + value, \ + finfo2.stype.out.field); \ + dump_all_info(mem_ctx, &finfo1); \ + }} while (0) + +#define CHECK_STATUS(status, correct) do { \ + if (!NT_STATUS_EQUAL(status, correct)) { \ + printf("(%s) Incorrect status %s - should be %s\n", \ + __location__, nt_errstr(status), nt_errstr(correct)); \ + ret = False; \ + goto done; \ + }} while (0) + + + printf("test basic_information level\n"); + basetime += 86400; + unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100); + unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200); + unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300); + unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400); + sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY; + CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); + CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100); + CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200); + CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time, basetime + 300); + CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_READONLY); + + printf("a zero time means don't change\n"); + unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0); + unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0); + unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0); + unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0); + sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; + CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); + CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100); + CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200); + CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time, basetime + 300); + CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL); + + printf("test disposition_information level\n"); + sfinfo.disposition_info.in.delete_on_close = 1; + CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 1); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 0); + + sfinfo.disposition_info.in.delete_on_close = 0; + CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 0); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 1); + + printf("test allocation_information level\n"); + sfinfo.allocation_info.in.alloc_size = 0; + CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 0); + + sfinfo.allocation_info.in.alloc_size = 4096; + CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 4096); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0); + + printf("test end_of_file_info level\n"); + sfinfo.end_of_file_info.in.size = 37; + CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 37); + + sfinfo.end_of_file_info.in.size = 7; + CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 7); + + printf("test position_information level\n"); + sfinfo.position_information.in.position = 123456; + CHECK_CALL(POSITION_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456); + + printf("test mode_information level\n"); + sfinfo.mode_information.in.mode = 2; + CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2); + + sfinfo.mode_information.in.mode = 1; + CHECK_CALL(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER); + + sfinfo.mode_information.in.mode = 0; + CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK); + CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); + +done: + status = smb2_util_close(tree, handle); + if (NT_STATUS_IS_ERR(status)) { + printf("Failed to delete %s - %s\n", fname, nt_errstr(status)); + } + smb2_util_unlink(tree, fname); + + talloc_free(mem_ctx); + return ret; +} + + diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c index 95624220f7..bb239bdd1b 100644 --- a/source4/torture/smb2/util.c +++ b/source4/torture/smb2/util.c @@ -26,6 +26,157 @@ #include "libcli/smb2/smb2_calls.h" #include "lib/cmdline/popt_common.h" #include "lib/events/events.h" +#include "system/time.h" + + +/* + close a handle with SMB2 +*/ +NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h) +{ + struct smb2_close c; + + ZERO_STRUCT(c); + c.in.handle = h; + + return smb2_close(tree, &c); +} + +/* + unlink a file with SMB2 +*/ +NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname) +{ + struct smb2_create io; + NTSTATUS status; + + ZERO_STRUCT(io); + io.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.in.open_disposition = NTCREATEX_DISP_OPEN; + io.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; + io.in.fname = fname; + io.in.blob = data_blob(NULL, 0); + + status = smb2_create(tree, tree, &io); + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + return NT_STATUS_OK; + } + NT_STATUS_NOT_OK_RETURN(status); + + return smb2_util_close(tree, io.out.handle); +} + +/* + write to a file on SMB2 +*/ +NTSTATUS smb2_util_write(struct smb2_tree *tree, + struct smb2_handle handle, + const void *buf, off_t offset, size_t size) +{ + struct smb2_write w; + + ZERO_STRUCT(w); + w.in.offset = offset; + w.in.handle = handle; + w.in.data = data_blob_const(buf, size); + + return smb2_write(tree, &w); +} + +/* + create a complex file using the SMB2 protocol +*/ +NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, struct smb2_handle *handle) +{ + char buf[7] = "abc"; + struct smb2_create io; + union smb_setfileinfo setfile; + union smb_fileinfo fileinfo; + time_t t = (time(NULL) & ~1); + NTSTATUS status; + + ZERO_STRUCT(io); + io.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF; + io.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + io.in.create_options = 0; + io.in.fname = fname; + io.in.blob = data_blob(NULL, 0); + + status = smb2_create(tree, tree, &io); + NT_STATUS_NOT_OK_RETURN(status); + + *handle = io.out.handle; + + status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf)); + NT_STATUS_NOT_OK_RETURN(status); + +#if 0 + if (strchr(fname, ':') == NULL) { + /* setup some EAs */ + setfile.generic.level = RAW_SFILEINFO_EA_SET; + setfile.generic.file.fnum = fnum; + setfile.ea_set.in.num_eas = 2; + setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2); + setfile.ea_set.in.eas[0].flags = 0; + setfile.ea_set.in.eas[0].name.s = "EAONE"; + setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6); + setfile.ea_set.in.eas[1].flags = 0; + setfile.ea_set.in.eas[1].name.s = "SECONDEA"; + setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8); + status = smb_raw_setfileinfo(cli->tree, &setfile); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to setup EAs\n"); + } + } +#endif + + /* make sure all the timestamps aren't the same, and are also + in different DST zones*/ + setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION; + setfile.generic.file.handle = *handle; + + setfile.basic_info.in.create_time = t + 9*30*24*60*60; + setfile.basic_info.in.access_time = t + 6*30*24*60*60; + setfile.basic_info.in.write_time = t + 3*30*24*60*60; + setfile.basic_info.in.change_time = t + 1*30*24*60*60; + setfile.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; + + status = smb2_setinfo_file(tree, &setfile); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to setup file times - %s\n", nt_errstr(status)); + } + + /* make sure all the timestamps aren't the same */ + fileinfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION; + fileinfo.generic.in.handle = *handle; + + status = smb2_getinfo_file(tree, tree, &fileinfo); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to query file times - %s\n", nt_errstr(status)); + } + + if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) { + printf("create_time not setup correctly\n"); + } + if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) { + printf("access_time not setup correctly\n"); + } + if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) { + printf("write_time not setup correctly\n"); + } + + return NT_STATUS_OK; +} /* show lots of information about a file -- cgit