From f47ff9d2271990d43a1387ff39c0e75d01611b2a Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 13 Aug 2013 18:07:23 +0200 Subject: torture: extend FSCTL_[GET/SET]_COMPRESSION tests Check for inheritance of compression attributes from parent directories. Also, test error handling for invalid requests. Signed-off-by: David Disseldorp Reviewed-by: Jeremy Allison --- source4/torture/smb2/ioctl.c | 273 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 234 insertions(+), 39 deletions(-) (limited to 'source4/torture/smb2') diff --git a/source4/torture/smb2/ioctl.c b/source4/torture/smb2/ioctl.c index 6b5895b7c0..d3ac73f760 100644 --- a/source4/torture/smb2/ioctl.c +++ b/source4/torture/smb2/ioctl.c @@ -29,6 +29,7 @@ #define FNAME "testfsctl.dat" #define FNAME2 "testfsctl2.dat" +#define DNAME "testfsctl_dir" /* basic testing of SMB2 shadow copy calls @@ -1530,20 +1531,16 @@ static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context *torture, return true; } -static bool test_ioctl_compress_file_flag(struct torture_context *torture, - struct smb2_tree *tree) +static NTSTATUS test_ioctl_compress_get(struct torture_context *torture, + TALLOC_CTX *mem_ctx, + struct smb2_tree *tree, + struct smb2_handle fh, + uint16_t *_compression_fmt) { - struct smb2_handle fh; - NTSTATUS status; union smb_ioctl ioctl; - TALLOC_CTX *tmp_ctx = talloc_new(tree); struct compression_state cmpr_state; enum ndr_err_code ndr_ret; - bool ok; - - ok = test_setup_create_fill(torture, tree, tmp_ctx, - FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL); - torture_assert(torture, ok, "setup compression file"); + NTSTATUS status; ZERO_STRUCT(ioctl); ioctl.smb2.level = RAW_IOCTL_SMB2; @@ -1552,60 +1549,252 @@ static bool test_ioctl_compress_file_flag(struct torture_context *torture, ioctl.smb2.in.max_response_size = sizeof(struct compression_state); ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; - status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2); - if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) - || NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) { - smb2_util_close(tree, fh); - torture_skip(torture, "FSCTL_GET_COMPRESSION not supported\n"); + status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2); + if (!NT_STATUS_IS_OK(status)) { + return status; } - torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION"); - ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, + ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, mem_ctx, &cmpr_state, (ndr_pull_flags_fn_t)ndr_pull_compression_state); - torture_assert_ndr_success(torture, ndr_ret, - "ndr_pull_compression_state"); + if (ndr_ret != NDR_ERR_SUCCESS) { + return NT_STATUS_INTERNAL_ERROR; + } - torture_assert(torture, (cmpr_state.format == COMPRESSION_FORMAT_NONE), - "initial compression state not NONE"); + *_compression_fmt = cmpr_state.format; + return NT_STATUS_OK; +} + +static NTSTATUS test_ioctl_compress_set(struct torture_context *torture, + TALLOC_CTX *mem_ctx, + struct smb2_tree *tree, + struct smb2_handle fh, + uint16_t compression_fmt) +{ + union smb_ioctl ioctl; + struct compression_state cmpr_state; + enum ndr_err_code ndr_ret; + NTSTATUS status; ZERO_STRUCT(ioctl); ioctl.smb2.level = RAW_IOCTL_SMB2; ioctl.smb2.in.file.handle = fh; ioctl.smb2.in.function = FSCTL_SET_COMPRESSION; + ioctl.smb2.in.max_response_size = 0; ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; - cmpr_state.format = COMPRESSION_FORMAT_DEFAULT; - ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx, + cmpr_state.format = compression_fmt; + ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, mem_ctx, &cmpr_state, (ndr_push_flags_fn_t)ndr_push_compression_state); - torture_assert_ndr_success(torture, ndr_ret, - "ndr_push_compression_state"); + if (ndr_ret != NDR_ERR_SUCCESS) { + return NT_STATUS_INTERNAL_ERROR; + } - status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2); + status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2); + return status; +} + +static bool test_ioctl_compress_file_flag(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle fh; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + bool ok; + uint16_t compression_fmt; + + ok = test_setup_create_fill(torture, tree, tmp_ctx, + FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL); + torture_assert(torture, ok, "setup compression file"); + + status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh, + &compression_fmt); + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) { + smb2_util_close(tree, fh); + torture_skip(torture, "FSCTL_GET_COMPRESSION not supported\n"); + } + torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION"); + + torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE), + "initial compression state not NONE"); + + status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh, + COMPRESSION_FORMAT_DEFAULT); + torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION"); + + status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh, + &compression_fmt); + torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION"); + + torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1), + "invalid compression state after set"); + + smb2_util_close(tree, fh); + talloc_free(tmp_ctx); + return true; +} + +static bool test_ioctl_compress_dir_inherit(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle dirh; + struct smb2_handle fh; + NTSTATUS status; + struct smb2_create io; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + uint16_t compression_fmt; + bool ok; + char path_buf[PATH_MAX]; + + smb2_deltree(tree, DNAME); + status = smb2_util_mkdir(tree, DNAME); + torture_assert_ntstatus_ok(torture, status, "mkdir"); + + ZERO_STRUCT(io); + io.in.desired_access = SEC_RIGHTS_FILE_ALL; + io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io.in.create_disposition = NTCREATEX_DISP_OPEN; + io.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + io.in.fname = DNAME; + + status = smb2_create(tree, tmp_ctx, &io); + torture_assert_ntstatus_ok(torture, status, "dir create"); + dirh = io.out.file.handle; + + /* set compression on base share, then check for file inheritance */ + status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh, + COMPRESSION_FORMAT_LZNT1); + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) { + smb2_util_close(tree, dirh); + smb2_deltree(tree, DNAME); + torture_skip(torture, "FSCTL_SET_COMPRESSION not supported\n"); + } + torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION"); + + status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh, + &compression_fmt); + torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION"); + + torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1), + "invalid compression state after set"); + + snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME); + ok = test_setup_create_fill(torture, tree, tmp_ctx, + path_buf, &fh, 4096, SEC_RIGHTS_FILE_ALL); + torture_assert(torture, ok, "setup compression file"); + + status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh, + &compression_fmt); + torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION"); + + torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1), + "compression attr not inherited by new file"); + + /* check compressed data is consistent */ + ok = check_pattern(torture, tree, tmp_ctx, fh, 0, 4096, 0); + + /* disable dir compression attr, file should remain compressed */ + status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh, + COMPRESSION_FORMAT_NONE); torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION"); + status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh, + &compression_fmt); + torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION"); + + torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1), + "file compression attr removed after dir change"); + smb2_util_close(tree, fh); + + /* new files should no longer inherit compression attr */ + snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME2); + ok = test_setup_create_fill(torture, tree, tmp_ctx, + path_buf, &fh, 0, SEC_RIGHTS_FILE_ALL); + torture_assert(torture, ok, "setup file"); + + status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh, + &compression_fmt); + torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION"); + + torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE), + "compression attr present on new file"); + + smb2_util_close(tree, fh); + smb2_util_close(tree, dirh); + smb2_deltree(tree, DNAME); + talloc_free(tmp_ctx); + return true; +} + +static bool test_ioctl_compress_invalid_format(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle fh; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + bool ok; + uint16_t compression_fmt; + + ok = test_setup_create_fill(torture, tree, tmp_ctx, + FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL); + torture_assert(torture, ok, "setup compression file"); + + status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh, + 0x0042); /* bogus */ + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) { + smb2_util_close(tree, fh); + torture_skip(torture, "FSCTL_SET_COMPRESSION not supported\n"); + } + torture_assert_ntstatus_equal(torture, status, + NT_STATUS_INVALID_PARAMETER, + "invalid FSCTL_SET_COMPRESSION"); + + status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh, + &compression_fmt); + torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION"); + + torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE), + "initial compression state not NONE"); + + smb2_util_close(tree, fh); + talloc_free(tmp_ctx); + return true; +} + +static bool test_ioctl_compress_invalid_buf(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle fh; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + bool ok; + union smb_ioctl ioctl; + + ok = test_setup_create_fill(torture, tree, tmp_ctx, + FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL); + torture_assert(torture, ok, "setup compression file"); + ZERO_STRUCT(ioctl); ioctl.smb2.level = RAW_IOCTL_SMB2; ioctl.smb2.in.file.handle = fh; ioctl.smb2.in.function = FSCTL_GET_COMPRESSION; - ioctl.smb2.in.max_response_size = sizeof(struct compression_state); + ioctl.smb2.in.max_response_size = 0; /* no room for rsp data */ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2); - torture_assert_ntstatus_ok(torture, status, - "FSCTL_GET_COMPRESSION"); - - ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, - &cmpr_state, - (ndr_pull_flags_fn_t)ndr_pull_compression_state); - - torture_assert_ndr_success(torture, ndr_ret, - "ndr_pull_compression_state"); - - torture_assert(torture, (cmpr_state.format == COMPRESSION_FORMAT_LZNT1), - "invalid compression state after set"); + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) { + smb2_util_close(tree, fh); + torture_skip(torture, "FSCTL_GET_COMPRESSION not supported\n"); + } + /* expect Server 2k12 response status */ + torture_assert_ntstatus_equal(torture, status, + NT_STATUS_INVALID_USER_BUFFER, + "invalid FSCTL_SET_COMPRESSION"); smb2_util_close(tree, fh); talloc_free(tmp_ctx); @@ -1657,6 +1846,12 @@ struct torture_suite *torture_smb2_ioctl_init(void) test_ioctl_copy_chunk_max_output_sz); torture_suite_add_1smb2_test(suite, "compress_file_flag", test_ioctl_compress_file_flag); + torture_suite_add_1smb2_test(suite, "compress_dir_inherit", + test_ioctl_compress_dir_inherit); + torture_suite_add_1smb2_test(suite, "compress_invalid_format", + test_ioctl_compress_invalid_format); + torture_suite_add_1smb2_test(suite, "compress_invalid_buf", + test_ioctl_compress_invalid_buf); suite->description = talloc_strdup(suite, "SMB2-IOCTL tests"); -- cgit