Beispiel #1
0
static bool test_lease_v2_request(struct torture_context *tctx,
				  struct smb2_tree *tree)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create io;
	struct smb2_lease ls;
	struct smb2_handle h1, h2, h3, h4, h5;
	struct smb2_write w;
	NTSTATUS status;
	const char *fname = "lease.dat";
	const char *dname = "lease.dir";
	const char *dnamefname = "lease.dir\\lease.dat";
	const char *dnamefname2 = "lease.dir\\lease2.dat";
	bool ret = true;

	smb2_util_unlink(tree, fname);
	smb2_deltree(tree, dname);

	tree->session->transport->lease.handler	= torture_lease_handler;
	tree->session->transport->lease.private_data = tree;
	tree->session->transport->oplock.handler = torture_oplock_handler;
	tree->session->transport->oplock.private_data = tree;

	ZERO_STRUCT(break_info);

	ZERO_STRUCT(io);
	smb2_lease_v2_create_share(&io, &ls, false, fname,
				   smb2_util_share_access("RWD"),
				   LEASE1, NULL,
				   smb2_util_lease_state("RHW"),
				   0);

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io.out.file.handle;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0);

	ZERO_STRUCT(io);
	smb2_lease_v2_create_share(&io, &ls, true, dname,
				   smb2_util_share_access("RWD"),
				   LEASE2, NULL,
				   smb2_util_lease_state("RHW"),
				   0);
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h2 = io.out.file.handle;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
	CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0);

	ZERO_STRUCT(io);
	smb2_lease_v2_create_share(&io, &ls, false, dnamefname,
				   smb2_util_share_access("RWD"),
				   LEASE3, &LEASE2,
				   smb2_util_lease_state("RHW"),
				   0);
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h3 = io.out.file.handle;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
		       SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET);

	torture_wait_for_lease_break(tctx);
	CHECK_VAL(break_info.count, 0);
	CHECK_VAL(break_info.failures, 0);

	ZERO_STRUCT(io);
	smb2_lease_v2_create_share(&io, &ls, false, dnamefname2,
				   smb2_util_share_access("RWD"),
				   LEASE4, NULL,
				   smb2_util_lease_state("RHW"),
				   0);
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h4 = io.out.file.handle;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0);

	torture_wait_for_lease_break(tctx);
	torture_wait_for_lease_break(tctx);
	CHECK_BREAK_INFO("RH", "", LEASE2);
	torture_wait_for_lease_break(tctx);

	ZERO_STRUCT(break_info);

	ZERO_STRUCT(io);
	smb2_lease_v2_create_share(&io, &ls, true, dname,
				   smb2_util_share_access("RWD"),
				   LEASE2, NULL,
				   smb2_util_lease_state("RHW"),
				   0);
	io.in.create_disposition = NTCREATEX_DISP_OPEN;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h5 = io.out.file.handle;
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
	CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0);
	smb2_util_close(tree, h5);

	ZERO_STRUCT(w);
	w.in.file.handle = h4;
	w.in.offset      = 0;
	w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
	memset(w.in.data.data, 'o', w.in.data.length);
	status = smb2_write(tree, &w);
	CHECK_STATUS(status, NT_STATUS_OK);

	smb_msleep(2000);
	torture_wait_for_lease_break(tctx);
	CHECK_VAL(break_info.count, 0);
	CHECK_VAL(break_info.failures, 0);

	smb2_util_close(tree, h4);
	torture_wait_for_lease_break(tctx);
	torture_wait_for_lease_break(tctx);
	CHECK_BREAK_INFO("RH", "", LEASE2);
	torture_wait_for_lease_break(tctx);

 done:
	smb2_util_close(tree, h1);
	smb2_util_close(tree, h2);
	smb2_util_close(tree, h3);
	smb2_util_close(tree, h4);
	smb2_util_close(tree, h5);

	smb2_util_unlink(tree, fname);
	smb2_deltree(tree, dname);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #2
0
/**
 * Test durable request / reconnect with AppInstanceId
 */
bool test_durable_v2_open_app_instance(struct torture_context *tctx,
				       struct smb2_tree *tree1,
				       struct smb2_tree *tree2)
{
	NTSTATUS status;
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	char fname[256];
	struct smb2_handle _h1, _h2;
	struct smb2_handle *h1 = NULL, *h2 = NULL;
	struct smb2_create io1, io2;
	bool ret = true;
	struct GUID create_guid_1 = GUID_random();
	struct GUID create_guid_2 = GUID_random();
	struct GUID app_instance_id = GUID_random();

	/* Choose a random name in case the state is left a little funky. */
	snprintf(fname, 256, "durable_v2_open_app_instance_%s.dat",
		 generate_random_str(tctx, 8));

	smb2_util_unlink(tree1, fname);

	ZERO_STRUCT(break_info);
	tree1->session->transport->oplock.handler = torture_oplock_handler;
	tree1->session->transport->oplock.private_data = tree1;

	smb2_oplock_create_share(&io1, fname,
				 smb2_util_share_access(""),
				 smb2_util_oplock_level("b"));
	io1.in.durable_open = false;
	io1.in.durable_open_v2 = true;
	io1.in.persistent_open = false;
	io1.in.create_guid = create_guid_1;
	io1.in.app_instance_id = &app_instance_id;
	io1.in.timeout = UINT32_MAX;

	status = smb2_create(tree1, mem_ctx, &io1);
	CHECK_STATUS(status, NT_STATUS_OK);
	_h1 = io1.out.file.handle;
	h1 = &_h1;
	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
	CHECK_VAL(io1.out.durable_open, false);
	CHECK_VAL(io1.out.durable_open_v2, true);
	CHECK_VAL(io1.out.persistent_open, false);
	CHECK_VAL(io1.out.timeout, io1.in.timeout);

	/*
	 * try to open the file as durable from a second tree with
	 * a different create guid but the same app_instance_id
	 * while the first handle is still open.
	 */

	smb2_oplock_create_share(&io2, fname,
				 smb2_util_share_access(""),
				 smb2_util_oplock_level("b"));
	io2.in.durable_open = false;
	io2.in.durable_open_v2 = true;
	io2.in.persistent_open = false;
	io2.in.create_guid = create_guid_2;
	io2.in.app_instance_id = &app_instance_id;
	io2.in.timeout = UINT32_MAX;

	status = smb2_create(tree2, mem_ctx, &io2);
	CHECK_STATUS(status, NT_STATUS_OK);
	_h2 = io2.out.file.handle;
	h2 = &_h2;
	CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
	CHECK_VAL(io2.out.durable_open, false);
	CHECK_VAL(io2.out.durable_open_v2, true);
	CHECK_VAL(io2.out.persistent_open, false);
	CHECK_VAL(io2.out.timeout, io2.in.timeout);

	CHECK_VAL(break_info.count, 0);

	status = smb2_util_close(tree1, *h1);
	CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
	h1 = NULL;

done:
	if (h1 != NULL) {
		smb2_util_close(tree1, *h1);
	}
	if (h2 != NULL) {
		smb2_util_close(tree2, *h2);
	}

	smb2_util_unlink(tree2, fname);

	talloc_free(tree1);
	talloc_free(tree2);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #3
0
/*
  test some interesting combinations found by gentest
 */
static bool test_create_gentest(struct torture_context *tctx, struct smb2_tree *tree)
{
	struct smb2_create io;
	NTSTATUS status;
	uint32_t access_mask, file_attributes_set;
	uint32_t ok_mask, not_supported_mask, invalid_parameter_mask;
	uint32_t not_a_directory_mask, unexpected_mask;
	union smb_fileinfo q;

	ZERO_STRUCT(io);
	io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
	io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
	io.in.create_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;

	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);

	io.in.create_options = 0xF0000000;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	io.in.create_options = 0;

	io.in.file_attributes = FILE_ATTRIBUTE_DEVICE;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	io.in.create_disposition = NTCREATEX_DISP_OPEN;
	io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
	
	io.in.create_disposition = NTCREATEX_DISP_CREATE;
	io.in.desired_access = 0x08000000;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);

	io.in.desired_access = 0x04000000;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);

	io.in.file_attributes = 0;
	io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
	io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
	ok_mask = 0;
	not_supported_mask = 0;
	invalid_parameter_mask = 0;
	not_a_directory_mask = 0;
	unexpected_mask = 0;
	{
		int i;
		for (i=0;i<32;i++) {
			io.in.create_options = 1<<i;
			if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
				continue;
			}
			status = smb2_create(tree, tctx, &io);
			if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
				not_supported_mask |= 1<<i;
			} else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
				invalid_parameter_mask |= 1<<i;
			} else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
				not_a_directory_mask |= 1<<i;
			} else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
				ok_mask |= 1<<i;
				status = smb2_util_close(tree, io.out.file.handle);
				CHECK_STATUS(status, NT_STATUS_OK);
			} else {
				unexpected_mask |= 1<<i;
				torture_comment(tctx,
				    "create option 0x%08x returned %s\n",
				    1<<i, nt_errstr(status));
			}
		}
	}
	io.in.create_options = 0;

	CHECK_EQUAL(ok_mask,                0x00efcf7e);
	CHECK_EQUAL(not_a_directory_mask,   0x00000001);
	CHECK_EQUAL(not_supported_mask,     0x00102080);
	CHECK_EQUAL(invalid_parameter_mask, 0xff000000);
	CHECK_EQUAL(unexpected_mask,        0x00000000);

	io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
	io.in.file_attributes = 0;
	access_mask = 0;
	{
		int i;
		for (i=0;i<32;i++) {
			io.in.desired_access = 1<<i;
			status = smb2_create(tree, tctx, &io);
			if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
			    NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) {
				access_mask |= io.in.desired_access;
			} else {
				CHECK_STATUS(status, NT_STATUS_OK);
				status = smb2_util_close(tree, io.out.file.handle);
				CHECK_STATUS(status, NT_STATUS_OK);
			}
		}
	}

	if (TARGET_IS_WIN7(tctx)) {
		CHECK_EQUAL(access_mask, 0x0de0fe00);
	} else if (torture_setting_bool(tctx, "samba4", false)) {
		CHECK_EQUAL(access_mask, 0x0cf0fe00);
	} else {
		CHECK_EQUAL(access_mask, 0x0df0fe00);
	}

	io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
	io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
	io.in.file_attributes = 0;
	ok_mask = 0;
	invalid_parameter_mask = 0;
	unexpected_mask = 0;
	file_attributes_set = 0;
	{
		int i;
		for (i=0;i<32;i++) {
			io.in.file_attributes = 1<<i;
			if (io.in.file_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
				continue;
			}
			smb2_deltree(tree, FNAME);
			status = smb2_create(tree, tctx, &io);
			if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
				invalid_parameter_mask |= 1<<i;
			} else if (NT_STATUS_IS_OK(status)) {
				uint32_t expected;
				ok_mask |= 1<<i;

				expected = (io.in.file_attributes | FILE_ATTRIBUTE_ARCHIVE) & 0x00005127;
				io.out.file_attr &= ~FILE_ATTRIBUTE_NONINDEXED;
				CHECK_EQUAL(io.out.file_attr, expected);
				file_attributes_set |= io.out.file_attr;

				status = smb2_util_close(tree, io.out.file.handle);
				CHECK_STATUS(status, NT_STATUS_OK);
			} else {
				unexpected_mask |= 1<<i;
				torture_comment(tctx,
				    "file attribute 0x%08x returned %s\n",
				    1<<i, nt_errstr(status));
			}
		}
	}

	CHECK_EQUAL(ok_mask,                0x00003fb7);
	CHECK_EQUAL(invalid_parameter_mask, 0xffff8048);
	CHECK_EQUAL(unexpected_mask,        0x00000000);
	CHECK_EQUAL(file_attributes_set,    0x00001127);

	smb2_deltree(tree, FNAME);

	/*
	 * Standalone servers doesn't support encryption
	 */
	io.in.file_attributes = FILE_ATTRIBUTE_ENCRYPTED;
	status = smb2_create(tree, tctx, &io);
	if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
		torture_comment(tctx,
		    "FILE_ATTRIBUTE_ENCRYPTED returned %s\n",
		    nt_errstr(status));
	} else {
		CHECK_STATUS(status, NT_STATUS_OK);
		CHECK_EQUAL(io.out.file_attr, (FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_ARCHIVE));
		status = smb2_util_close(tree, io.out.file.handle);
		CHECK_STATUS(status, NT_STATUS_OK);
	}

	smb2_deltree(tree, FNAME);

	ZERO_STRUCT(io);
	io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
	io.in.file_attributes    = 0;
	io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
	io.in.share_access = 
		NTCREATEX_SHARE_ACCESS_READ|
		NTCREATEX_SHARE_ACCESS_WRITE;
	io.in.create_options = 0;
	io.in.fname = FNAME ":stream1";
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);

	io.in.fname = FNAME;
	io.in.file_attributes = 0x8040;
	io.in.share_access = 
		NTCREATEX_SHARE_ACCESS_READ;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	io.in.fname = FNAME;
	io.in.file_attributes = 0;
	io.in.desired_access  = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
	io.in.query_maximal_access = true;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);

	q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
	q.access_information.in.file.handle = io.out.file.handle;
	status = smb2_getinfo_file(tree, tctx, &q);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access);

	io.in.file_attributes = 0;
	io.in.desired_access  = 0;
	io.in.query_maximal_access = false;
	io.in.share_access = 0;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
	
	smb2_deltree(tree, FNAME);

	return true;
}
Beispiel #4
0
/*
  try creating with acls
 */
static bool test_create_acl_ext(struct torture_context *tctx, struct smb2_tree *tree, bool test_dir)
{
	bool ret = true;
	struct smb2_create io;
	NTSTATUS status;
	struct security_ace ace;
	struct security_descriptor *sd;
	struct dom_sid *test_sid;
	union smb_fileinfo q = {};
	uint32_t attrib =
	    FILE_ATTRIBUTE_HIDDEN |
	    FILE_ATTRIBUTE_SYSTEM |
	    (test_dir ? FILE_ATTRIBUTE_DIRECTORY : 0);
	NTSTATUS (*delete_func)(struct smb2_tree *, const char *) =
	    test_dir ? smb2_util_rmdir : smb2_util_unlink;

	smb2_deltree(tree, FNAME);

	ZERO_STRUCT(io);
	io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
	io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
	io.in.create_disposition = NTCREATEX_DISP_CREATE;
	io.in.share_access = 
		NTCREATEX_SHARE_ACCESS_DELETE |
		NTCREATEX_SHARE_ACCESS_READ |
		NTCREATEX_SHARE_ACCESS_WRITE;
	io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT | 0x00200000 |
	    (test_dir ?  NTCREATEX_OPTIONS_DIRECTORY :
		(NTCREATEX_OPTIONS_NON_DIRECTORY_FILE));

	io.in.fname = FNAME;

	torture_comment(tctx, "basic create\n");

	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
	q.query_secdesc.in.file.handle = io.out.file.handle;
	q.query_secdesc.in.secinfo_flags = 
		SECINFO_OWNER |
		SECINFO_GROUP |
		SECINFO_DACL;
	status = smb2_getinfo_file(tree, tctx, &q);
	CHECK_STATUS(status, NT_STATUS_OK);
	sd = q.query_secdesc.out.sd;

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);
	status = delete_func(tree, FNAME);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "adding a new ACE\n");
	test_sid = dom_sid_parse_talloc(tctx, SID_NT_AUTHENTICATED_USERS);

	ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
	ace.flags = 0;
	ace.access_mask = SEC_STD_ALL;
	ace.trustee = *test_sid;

	status = security_descriptor_dacl_add(sd, &ace);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "creating a file with an initial ACL\n");

	io.in.sec_desc = sd;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);
	status = delete_func(tree, FNAME);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "creating with attributes\n");

	io.in.sec_desc = NULL;
	io.in.file_attributes = attrib;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);
	status = delete_func(tree, FNAME);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "creating with attributes and ACL\n");

	io.in.sec_desc = sd;
	io.in.file_attributes = attrib;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
	FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
	
	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);
	status = delete_func(tree, FNAME);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "creating with attributes, ACL and owner\n");
	sd = security_descriptor_dacl_create(tctx,
					0, SID_WORLD, SID_BUILTIN_USERS,
					SID_WORLD,
					SEC_ACE_TYPE_ACCESS_ALLOWED,
					SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
					0,
					NULL);

	io.in.sec_desc = sd;
	io.in.file_attributes = attrib;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
	FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));

 done:
	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);
	status = delete_func(tree, FNAME);
	CHECK_STATUS(status, NT_STATUS_OK);

	return ret;
}
Beispiel #5
0
static bool test_compound_break(struct torture_context *tctx,
			         struct smb2_tree *tree)
{
	const char *fname1 = "some-file.pptx";
	NTSTATUS status;
	bool ret = true;
	union smb_open io1;
	struct smb2_create io2;
	struct smb2_getinfo gf;
	struct smb2_request *req[2];
	struct smb2_handle h1;
	struct smb2_handle h;

	tree->session->transport->oplock.handler = torture_oplock_handler;
	tree->session->transport->oplock.private_data = tree;

	ZERO_STRUCT(break_info);

	/*
	  base ntcreatex parms
	*/
	ZERO_STRUCT(io1.smb2);
	io1.generic.level = RAW_OPEN_SMB2;
	io1.smb2.in.desired_access = (SEC_STD_SYNCHRONIZE|
					SEC_STD_READ_CONTROL|
					SEC_FILE_READ_ATTRIBUTE|
					SEC_FILE_READ_EA|
					SEC_FILE_READ_DATA);
	io1.smb2.in.alloc_size = 0;
	io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
			NTCREATEX_SHARE_ACCESS_WRITE|
			NTCREATEX_SHARE_ACCESS_DELETE;
	io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
	io1.smb2.in.create_options = 0;
	io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
	io1.smb2.in.security_flags = 0;
	io1.smb2.in.fname = fname1;

	torture_comment(tctx, "TEST2: open a file with an batch "
			"oplock (share mode: all)\n");
	io1.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;

	status = smb2_create(tree, tctx, &(io1.smb2));
	torture_assert_ntstatus_ok(tctx, status, "Error opening the file");

	h1 = io1.smb2.out.file.handle;

	torture_comment(tctx, "TEST2: Opening second time with compound\n");

	ZERO_STRUCT(io2);

	io2.in.desired_access = (SEC_STD_SYNCHRONIZE|
				SEC_FILE_READ_ATTRIBUTE|
				SEC_FILE_READ_EA);
	io2.in.alloc_size = 0;
	io2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	io2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
			NTCREATEX_SHARE_ACCESS_WRITE|
			NTCREATEX_SHARE_ACCESS_DELETE;
	io2.in.create_disposition = NTCREATEX_DISP_OPEN;
	io2.in.create_options = 0;
	io2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
	io2.in.security_flags = 0;
	io2.in.fname = fname1;
	io2.in.oplock_level = 0;

	smb2_transport_compound_start(tree->session->transport, 2);

	req[0] = smb2_create_send(tree, &io2);

	smb2_transport_compound_set_related(tree->session->transport, true);

	h.data[0] = UINT64_MAX;
	h.data[1] = UINT64_MAX;

	ZERO_STRUCT(gf);
	gf.in.file.handle = h;
	gf.in.info_type = SMB2_GETINFO_FILE;
	gf.in.info_class = 0x16;
	gf.in.output_buffer_length = 0x1000;
	gf.in.input_buffer_length = 0;

	req[1] = smb2_getinfo_send(tree, &gf);

	status = smb2_create_recv(req[0], tree, &io2);
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_getinfo_recv(req[1], tree, &gf);
	CHECK_STATUS(status, NT_STATUS_OK);

done:

	smb2_util_close(tree, h1);
	smb2_util_unlink(tree, fname1);
	return ret;
}
Beispiel #6
0
	}

	/* it seems vista is now fussier about alignment? */
	if (strchr(fname, ':') == NULL) {
		/* setup some EAs */
		io.in.eas.num_eas = 2;
		io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2);
		io.in.eas.eas[0].flags = 0;
		io.in.eas.eas[0].name.s = "EAONE";
		io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6);
		io.in.eas.eas[1].flags = 0;
		io.in.eas.eas[1].name.s = "SECONDEA";
		io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8);
	}

	status = smb2_create(tree, tmp_ctx, &io);
	talloc_free(tmp_ctx);
	NT_STATUS_NOT_OK_RETURN(status);

	*handle = io.out.file.handle;

	if (!dir) {
		status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
		NT_STATUS_NOT_OK_RETURN(status);
	}

	/* 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.in.file.handle = *handle;
Beispiel #7
0
/*
  Open, take BRL, disconnect, reconnect.
*/
bool test_durable_open_lock(struct torture_context *tctx,
			    struct smb2_tree *tree)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create io;
	struct smb2_lease ls;
	struct smb2_handle h;
	struct smb2_lock lck;
	struct smb2_lock_element el[2];
	NTSTATUS status;
	char fname[256];
	bool ret = true;
	uint64_t lease;

	/*
	 * Choose a random name and random lease in case the state is left a
	 * little funky.
	 */
	lease = random();
	snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));

	/* Clean slate */
	smb2_util_unlink(tree, fname);

	/* Create with lease */
	ZERO_STRUCT(io);
	io.in.security_flags		= 0x00;
	io.in.oplock_level		= SMB2_OPLOCK_LEVEL_LEASE;
	io.in.impersonation_level	= NTCREATEX_IMPERSONATION_IMPERSONATION;
	io.in.create_flags		= 0x00000000;
	io.in.reserved			= 0x00000000;
	io.in.desired_access		= SEC_RIGHTS_FILE_ALL;
	io.in.file_attributes		= FILE_ATTRIBUTE_NORMAL;
	io.in.share_access		= NTCREATEX_SHARE_ACCESS_READ |
					  NTCREATEX_SHARE_ACCESS_WRITE |
					  NTCREATEX_SHARE_ACCESS_DELETE;
	io.in.create_disposition	= NTCREATEX_DISP_OPEN_IF;
	io.in.create_options		= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
					  NTCREATEX_OPTIONS_ASYNC_ALERT	|
					  NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
					  0x00200000;
	io.in.fname			= fname;
	io.in.durable_open 		= true;

	ZERO_STRUCT(ls);
	ls.lease_key.data[0] = lease;
	ls.lease_key.data[1] = ~lease;
	ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE;
	io.in.lease_request = &ls;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h = io.out.file.handle;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);

	CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
	CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
	CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
	CHECK_VAL(io.out.lease_response.lease_state,
	    SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);

	ZERO_STRUCT(lck);
	ZERO_STRUCT(el);
	lck.in.locks		= el;
	lck.in.lock_count	= 0x0001;
	lck.in.reserved		= 0x00000000;
	lck.in.file.handle	= h;
	el[0].offset		= 0;
	el[0].length		= 1;
	el[0].reserved		= 0x00000000;
	el[0].flags		= SMB2_LOCK_FLAG_EXCLUSIVE;
	status = smb2_lock(tree, &lck);
	CHECK_STATUS(status, NT_STATUS_OK);

	/* Disconnect/Reconnect. */
	talloc_free(tree);
	tree = NULL;

	if (!torture_smb2_connection(tctx, &tree)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle = &h;
	io.in.lease_request = &ls;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h = io.out.file.handle;

	lck.in.file.handle	= h;
	el[0].flags		= SMB2_LOCK_FLAG_UNLOCK;
	status = smb2_lock(tree, &lck);
	CHECK_STATUS(status, NT_STATUS_OK);

 done:
	smb2_util_close(tree, h);
	smb2_util_unlink(tree, fname);

	return ret;
}
Beispiel #8
0
/**
 * testing various create blob combinations.
 */
bool test_durable_v2_open_create_blob(struct torture_context *tctx,
				      struct smb2_tree *tree)
{
	NTSTATUS status;
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	char fname[256];
	struct smb2_handle _h;
	struct smb2_handle *h = NULL;
	struct smb2_create io;
	struct GUID create_guid = GUID_random();
	bool ret = true;
	struct smbcli_options options;

	options = tree->session->transport->options;

	/* Choose a random name in case the state is left a little funky. */
	snprintf(fname, 256, "durable_v2_open_create_blob_%s.dat",
		 generate_random_str(tctx, 8));

	smb2_util_unlink(tree, fname);

	smb2_oplock_create_share(&io, fname,
				 smb2_util_share_access(""),
				 smb2_util_oplock_level("b"));
	io.in.durable_open = false;
	io.in.durable_open_v2 = true;
	io.in.persistent_open = false;
	io.in.create_guid = create_guid;
	io.in.timeout = UINT32_MAX;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	_h = io.out.file.handle;
	h = &_h;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
	CHECK_VAL(io.out.durable_open, false);
	CHECK_VAL(io.out.durable_open_v2, true);
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.timeout, io.in.timeout);

	/* disconnect */
	TALLOC_FREE(tree);

	/* create a new session (same client_guid) */
	if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	/*
	 * check invalid combinations of durable handle
	 * request and reconnect blobs
	 * See MS-SMB2: 3.3.5.9.12
	 * Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context
	 */
	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
	io.in.durable_open = true;   /* durable v1 handle request */
	io.in.create_guid = create_guid;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle = h;     /* durable v1 reconnect request */
	io.in.durable_open_v2 = true; /* durable v2 handle request */
	io.in.create_guid = create_guid;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle = h;    /* durable v1 reconnect request */
	io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
	io.in.create_guid = create_guid;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle_v2 = h;  /* durable v2 reconnect request */
	io.in.durable_open_v2 = true; /* durable v2 handle request */
	io.in.create_guid = create_guid;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

done:
	if (h != NULL) {
		smb2_util_close(tree, *h);
	}

	smb2_util_unlink(tree, fname);

	talloc_free(tree);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #9
0
static bool test_lease_multibreak(struct torture_context *tctx,
                                  struct smb2_tree *tree)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create io;
	struct smb2_lease ls;
	struct smb2_handle h, h2, h3;
	struct smb2_write w;
	NTSTATUS status;
	const char *fname = "lease.dat";
	bool ret = true;
	uint32_t caps;

	caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
	if (!(caps & SMB2_CAP_LEASING)) {
		torture_skip(tctx, "leases are not supported");
	}

	tree->session->transport->lease.handler	= torture_lease_handler;
	tree->session->transport->lease.private_data = tree;
	tree->session->transport->oplock.handler = torture_oplock_handler;
	tree->session->transport->oplock.private_data = tree;

	smb2_util_unlink(tree, fname);

	ZERO_STRUCT(break_info);

	/* Grab lease, upgrade to RHW .. */
	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h = io.out.file.handle;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RH", true, LEASE1);

	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h2 = io.out.file.handle;
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RHW", true, LEASE1);

	/* Contend with LEASE2. */
	smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h3 = io.out.file.handle;
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RH", true, LEASE2);

	/* Verify that we were only sent one break. */
	CHECK_BREAK_INFO("RHW", "RH", LEASE1);

	/* Drop LEASE1 / LEASE2 */
	status = smb2_util_close(tree, h);
	CHECK_STATUS(status, NT_STATUS_OK);
	status = smb2_util_close(tree, h2);
	CHECK_STATUS(status, NT_STATUS_OK);
	status = smb2_util_close(tree, h3);
	CHECK_STATUS(status, NT_STATUS_OK);

	ZERO_STRUCT(break_info);

	/* Grab an R lease. */
	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h = io.out.file.handle;
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "R", true, LEASE1);

	/* Grab a level-II oplock. */
	smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h2 = io.out.file.handle;
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
	break_info.held_oplock_level = io.out.oplock_level;

	/* Verify no breaks. */
	CHECK_VAL(break_info.count, 0);
	CHECK_VAL(break_info.failures, 0);

	/* Open for truncate, force a break. */
	smb2_generic_create(&io, NULL, false, fname,
	    NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h3 = io.out.file.handle;
	CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
	break_info.held_oplock_level = io.out.oplock_level;

	/* Sleep, use a write to clear the recv queue. */
	smb_msleep(250);
	ZERO_STRUCT(w);
	w.in.file.handle = h3;
	w.in.offset      = 0;
	w.in.data        = data_blob_talloc(mem_ctx, NULL, 4096);
	memset(w.in.data.data, 'o', w.in.data.length);
	status = smb2_write(tree, &w);
	CHECK_STATUS(status, NT_STATUS_OK);

	/* Verify one oplock break, one lease break. */
	CHECK_VAL(break_info.oplock_count, 1);
	CHECK_VAL(break_info.oplock_failures, 0);
	CHECK_VAL(break_info.oplock_level, smb2_util_oplock_level(""));
	CHECK_BREAK_INFO("R", "", LEASE1);

 done:
	smb2_util_close(tree, h);
	smb2_util_close(tree, h2);
	smb2_util_close(tree, h3);

	smb2_util_unlink(tree, fname);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #10
0
/*
  Open, disconnect, oplock break, reconnect.
*/
bool test_durable_open_oplock(struct torture_context *tctx,
			      struct smb2_tree *tree1,
			      struct smb2_tree *tree2)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create io1, io2;
	struct smb2_handle h1, h2;
	NTSTATUS status;
	char fname[256];
	bool ret = true;

	/* Choose a random name in case the state is left a little funky. */
	snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));

	/* Clean slate */
	smb2_util_unlink(tree1, fname);

	/* Create with batch oplock */
	ZERO_STRUCT(io1);
	io1.in.security_flags		= 0x00;
	io1.in.oplock_level		= SMB2_OPLOCK_LEVEL_BATCH;
	io1.in.impersonation_level	= NTCREATEX_IMPERSONATION_IMPERSONATION;
	io1.in.create_flags		= 0x00000000;
	io1.in.reserved			= 0x00000000;
	io1.in.desired_access		= SEC_RIGHTS_FILE_ALL;
	io1.in.file_attributes		= FILE_ATTRIBUTE_NORMAL;
	io1.in.share_access		= NTCREATEX_SHARE_ACCESS_READ |
					  NTCREATEX_SHARE_ACCESS_WRITE |
					  NTCREATEX_SHARE_ACCESS_DELETE;
	io1.in.create_disposition	= NTCREATEX_DISP_OPEN_IF;
	io1.in.create_options		= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
					  NTCREATEX_OPTIONS_ASYNC_ALERT	|
					  NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
					  0x00200000;
	io1.in.fname			= fname;
	io1.in.durable_open		= true;

	io2 = io1;
	io2.in.create_disposition	= NTCREATEX_DISP_OPEN;

	status = smb2_create(tree1, mem_ctx, &io1);
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io1.out.file.handle;
	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);

	/* Disconnect after getting the batch */
	talloc_free(tree1);
	tree1 = NULL;

	/*
	 * Windows7 (build 7000) will break a batch oplock immediately if the
	 * original client is gone. (ZML: This seems like a bug. It should give
	 * some time for the client to reconnect!)
	 */
	status = smb2_create(tree2, mem_ctx, &io2);
	CHECK_STATUS(status, NT_STATUS_OK);
	h2 = io2.out.file.handle;
	CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);

	/* What if tree1 tries to come back and reclaim? */
	if (!torture_smb2_connection(tctx, &tree1)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	ZERO_STRUCT(io1);
	io1.in.fname = fname;
	io1.in.durable_handle = &h1;

	status = smb2_create(tree1, mem_ctx, &io1);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

 done:
	smb2_util_close(tree2, h2);
	smb2_util_unlink(tree2, fname);

	return ret;
}
Beispiel #11
0
static bool test_lease_oplock(struct torture_context *tctx,
                              struct smb2_tree *tree)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create io;
	struct smb2_lease ls;
	struct smb2_handle h, h2;
	NTSTATUS status;
	const char *fname = "lease.dat";
	bool ret = true;
	int i;
	uint32_t caps;

	caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
	if (!(caps & SMB2_CAP_LEASING)) {
		torture_skip(tctx, "leases are not supported");
	}

	tree->session->transport->lease.handler	= torture_lease_handler;
	tree->session->transport->lease.private_data = tree;
	tree->session->transport->oplock.handler = torture_oplock_handler;
	tree->session->transport->oplock.private_data = tree;

	smb2_util_unlink(tree, fname);

	for (i = 0; i < NOPLOCK_RESULTS; i++) {
		const char *held = oplock_results[i][0];
		const char *contend = oplock_results[i][1];
		const char *brokento = oplock_results[i][2];
		const char *granted = oplock_results[i][3];
		torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
		    "expecting break to %s(%x) and grant of %s(%x)\n",
		    held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
		    brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));

		ZERO_STRUCT(break_info);

		/* Grab lease. */
		smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
		status = smb2_create(tree, mem_ctx, &io);
		CHECK_STATUS(status, NT_STATUS_OK);
		h = io.out.file.handle;
		CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
		CHECK_LEASE(&io, held, true, LEASE1);

		/* Does an oplock contend the lease? */
		smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
		status = smb2_create(tree, mem_ctx, &io);
		CHECK_STATUS(status, NT_STATUS_OK);
		h2 = io.out.file.handle;
		CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
		break_info.held_oplock_level = io.out.oplock_level;

		if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
			CHECK_BREAK_INFO(held, brokento, LEASE1);
		} else {
			CHECK_VAL(break_info.count, 0);
			CHECK_VAL(break_info.failures, 0);
		}

		smb2_util_close(tree, h);
		smb2_util_close(tree, h2);

		status = smb2_util_unlink(tree, fname);
		CHECK_STATUS(status, NT_STATUS_OK);
	}

	for (i = 0; i < NOPLOCK_RESULTS; i++) {
		const char *held = oplock_results_2[i][0];
		const char *contend = oplock_results_2[i][1];
		const char *brokento = oplock_results_2[i][2];
		const char *granted = oplock_results_2[i][3];
		torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
		    "expecting break to %s(%x) and grant of %s(%x)\n",
		    held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
		    brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));

		ZERO_STRUCT(break_info);

		/* Grab an oplock. */
		smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
		status = smb2_create(tree, mem_ctx, &io);
		CHECK_STATUS(status, NT_STATUS_OK);
		h = io.out.file.handle;
		CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
		CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
		break_info.held_oplock_level = io.out.oplock_level;

		/* Grab lease. */
		smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend));
		status = smb2_create(tree, mem_ctx, &io);
		CHECK_STATUS(status, NT_STATUS_OK);
		h2 = io.out.file.handle;
		CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
		CHECK_LEASE(&io, granted, true, LEASE1);

		if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
			CHECK_VAL(break_info.oplock_count, 1);
			CHECK_VAL(break_info.oplock_failures, 0);
			CHECK_VAL(break_info.oplock_level, smb2_util_oplock_level(brokento));
			break_info.held_oplock_level = break_info.oplock_level;
		} else {
			CHECK_VAL(break_info.oplock_count, 0);
			CHECK_VAL(break_info.oplock_failures, 0);
		}

		smb2_util_close(tree, h);
		smb2_util_close(tree, h2);

		status = smb2_util_unlink(tree, fname);
		CHECK_STATUS(status, NT_STATUS_OK);
	}

 done:
	smb2_util_close(tree, h);
	smb2_util_close(tree, h2);

	smb2_util_unlink(tree, fname);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #12
0
static bool test_lease_upgrade3(struct torture_context *tctx,
                                struct smb2_tree *tree)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_handle h, h2, hnew;
	NTSTATUS status;
	struct smb2_create io;
	struct smb2_lease ls;
	const char *fname = "upgrade3.dat";
	bool ret = true;
	int i;
	uint32_t caps;

	caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
	if (!(caps & SMB2_CAP_LEASING)) {
		torture_skip(tctx, "leases are not supported");
	}

	tree->session->transport->lease.handler	= torture_lease_handler;
	tree->session->transport->lease.private_data = tree;

	smb2_util_unlink(tree, fname);

	for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
		struct lease_upgrade3_test t = lease_upgrade3_tests[i];

		smb2_util_unlink(tree, fname);

		ZERO_STRUCT(break_info);

		/* grab first lease */
		smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
		status = smb2_create(tree, mem_ctx, &io);
		CHECK_STATUS(status, NT_STATUS_OK);
		CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
		CHECK_LEASE(&io, t.held1, true, LEASE1);
		h = io.out.file.handle;

		/* grab second lease */
		smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
		status = smb2_create(tree, mem_ctx, &io);
		CHECK_STATUS(status, NT_STATUS_OK);
		CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
		CHECK_LEASE(&io, t.held2, true, LEASE2);
		h2 = io.out.file.handle;

		/* no break has happened */
		CHECK_VAL(break_info.count, 0);
		CHECK_VAL(break_info.failures, 0);

		/* try to upgrade lease1 */
		smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
		status = smb2_create(tree, mem_ctx, &io);
		CHECK_STATUS(status, NT_STATUS_OK);
		CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
		CHECK_LEASE(&io, t.upgraded_to, true, LEASE1);
		hnew = io.out.file.handle;

		/* no break has happened */
		CHECK_VAL(break_info.count, 0);
		CHECK_VAL(break_info.failures, 0);

		smb2_util_close(tree, hnew);
		smb2_util_close(tree, h);
		smb2_util_close(tree, h2);
	}

 done:
	smb2_util_close(tree, h);
	smb2_util_close(tree, hnew);
	smb2_util_close(tree, h2);

	smb2_util_unlink(tree, fname);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #13
0
static bool test_lease_upgrade(struct torture_context *tctx,
                               struct smb2_tree *tree)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create io;
	struct smb2_lease ls;
	struct smb2_handle h, hnew;
	NTSTATUS status;
	const char *fname = "lease.dat";
	bool ret = true;
	uint32_t caps;

	caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
	if (!(caps & SMB2_CAP_LEASING)) {
		torture_skip(tctx, "leases are not supported");
	}

	smb2_util_unlink(tree, fname);

	/* Grab a RH lease. */
	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RH", true, LEASE1);
	h = io.out.file.handle;

	/* Upgrades (sidegrades?) to RW leave us with an RH. */
	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RW"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RH", true, LEASE1);
	hnew = io.out.file.handle;

	smb2_util_close(tree, hnew);

	/* Upgrade to RHW lease. */
	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RHW", true, LEASE1);
	hnew = io.out.file.handle;

	smb2_util_close(tree, h);
	h = hnew;

	/* Attempt to downgrade - original lease state is maintained. */
	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RHW", true, LEASE1);
	hnew = io.out.file.handle;

	smb2_util_close(tree, hnew);

 done:
	smb2_util_close(tree, h);
	smb2_util_close(tree, hnew);

	smb2_util_unlink(tree, fname);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #14
0
/**
 * Basic test for doing a durable open
 * and do a session reconnect while the first
 * session is still active and the handle is
 * still open in the client.
 * This closes the original session and  a
 * durable reconnect on the new session succeeds.
 */
bool test_durable_v2_open_reopen1a(struct torture_context *tctx,
				   struct smb2_tree *tree)
{
	NTSTATUS status;
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	char fname[256];
	struct smb2_handle _h;
	struct smb2_handle *h = NULL;
	struct smb2_create io, io2;
	struct GUID create_guid = GUID_random();
	bool ret = true;
	struct smb2_tree *tree2 = NULL;
	uint64_t previous_session_id;
	struct smbcli_options options;

	options = tree->session->transport->options;

	/* Choose a random name in case the state is left a little funky. */
	snprintf(fname, 256, "durable_v2_open_reopen1a_%s.dat",
		 generate_random_str(tctx, 8));

	smb2_util_unlink(tree, fname);

	smb2_oplock_create_share(&io, fname,
				 smb2_util_share_access(""),
				 smb2_util_oplock_level("b"));
	io.in.durable_open = false;
	io.in.durable_open_v2 = true;
	io.in.persistent_open = false;
	io.in.create_guid = create_guid;
	io.in.timeout = UINT32_MAX;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	_h = io.out.file.handle;
	h = &_h;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
	CHECK_VAL(io.out.durable_open, false);
	CHECK_VAL(io.out.durable_open_v2, true);
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.timeout, io.in.timeout);

	/*
	 * a session reconnect on a second tcp connection
	 */

	previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);

	if (!torture_smb2_connection_ext(tctx, previous_session_id,
					 &options, &tree2))
	{
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	/*
	 * check that this has deleted the old session
	 */

	ZERO_STRUCT(io);
	io.in.fname = "";
	io.in.durable_handle_v2 = h;
	io.in.create_guid = create_guid;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);

	/*
	 * but a durable reconnect on the new session succeeds:
	 */

	ZERO_STRUCT(io2);
	io2.in.fname = "";
	io2.in.durable_handle_v2 = h;
	io2.in.create_guid = create_guid;
	status = smb2_create(tree2, mem_ctx, &io2);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
	CHECK_VAL(io2.out.durable_open, false);
	CHECK_VAL(io2.out.durable_open_v2, false); /* no dh2q response blob */
	CHECK_VAL(io2.out.persistent_open, false);
	CHECK_VAL(io2.out.timeout, io.in.timeout);
	_h = io2.out.file.handle;
	h = &_h;

done:
	if (h != NULL) {
		smb2_util_close(tree, *h);
	}

	smb2_util_unlink(tree, fname);

	talloc_free(tree);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #15
0
/*
  Open, disconnect, open in another tree, reconnect.

  This test actually demonstrates a minimum level of respect for the durable
  open in the face of another open. As long as this test shows an inability to
  reconnect after an open, the oplock/lease tests above will certainly
  demonstrate an error on reconnect.
*/
bool test_durable_open_open(struct torture_context *tctx,
			    struct smb2_tree *tree1,
			    struct smb2_tree *tree2)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create io1, io2;
	struct smb2_lease ls;
	struct smb2_handle h1, h2;
	NTSTATUS status;
	char fname[256];
	bool ret = true;
	uint64_t lease;

	/*
	 * Choose a random name and random lease in case the state is left a
	 * little funky.
	 */
	lease = random();
	snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));

	/* Clean slate */
	smb2_util_unlink(tree1, fname);

	/* Create with lease */
	ZERO_STRUCT(io1);
	io1.in.security_flags		= 0x00;
	io1.in.oplock_level		= SMB2_OPLOCK_LEVEL_LEASE;
	io1.in.impersonation_level	= NTCREATEX_IMPERSONATION_IMPERSONATION;
	io1.in.create_flags		= 0x00000000;
	io1.in.reserved			= 0x00000000;
	io1.in.desired_access		= SEC_RIGHTS_FILE_ALL;
	io1.in.file_attributes		= FILE_ATTRIBUTE_NORMAL;
	io1.in.share_access		= NTCREATEX_SHARE_ACCESS_NONE;
	io1.in.create_disposition	= NTCREATEX_DISP_OPEN_IF;
	io1.in.create_options		= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
					  NTCREATEX_OPTIONS_ASYNC_ALERT	|
					  NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
					  0x00200000;
	io1.in.fname			= fname;
	io1.in.durable_open 		= true;

	io2 = io1;
	io2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
	io2.in.durable_open = false;

	ZERO_STRUCT(ls);
	ls.lease_key.data[0] = lease;
	ls.lease_key.data[1] = ~lease;
	ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE;
	io1.in.lease_request = &ls;

	status = smb2_create(tree1, mem_ctx, &io1);
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io1.out.file.handle;
	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);

	CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
	CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
	CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
	CHECK_VAL(io1.out.lease_response.lease_state,
	    SMB2_LEASE_READ|SMB2_LEASE_HANDLE);

	/* Disconnect */
	talloc_free(tree1);
	tree1 = NULL;

	/* Open the file in tree2 */
	status = smb2_create(tree2, mem_ctx, &io2);
	CHECK_STATUS(status, NT_STATUS_OK);
	h2 = io2.out.file.handle;
	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);

	/* Reconnect */
	if (!torture_smb2_connection(tctx, &tree1)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	ZERO_STRUCT(io1);
	io1.in.fname = fname;
	io1.in.durable_handle = &h1;
	io1.in.lease_request = &ls;

	/*
	 * Windows7 (build 7000) will give away an open immediately if the
	 * original client is gone. (ZML: This seems like a bug. It should give
	 * some time for the client to reconnect!)
	 */
	status = smb2_create(tree1, mem_ctx, &io1);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
	h1 = io1.out.file.handle;

 done:
	smb2_util_close(tree2, h2);
	smb2_util_unlink(tree2, fname);
	smb2_util_close(tree1, h1);
	smb2_util_unlink(tree1, fname);

	return ret;
}
Beispiel #16
0
/**
 * basic test for doing a durable open
 * tcp disconnect, reconnect, do a durable reopen (succeeds)
 */
bool test_durable_v2_open_reopen2(struct torture_context *tctx,
				  struct smb2_tree *tree)
{
	NTSTATUS status;
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	char fname[256];
	struct smb2_handle _h;
	struct smb2_handle *h = NULL;
	struct smb2_create io;
	struct GUID create_guid = GUID_random();
	struct GUID create_guid_invalid = GUID_random();
	bool ret = true;

	/* Choose a random name in case the state is left a little funky. */
	snprintf(fname, 256, "durable_v2_open_reopen2_%s.dat",
		 generate_random_str(tctx, 8));

	smb2_util_unlink(tree, fname);

	smb2_oplock_create_share(&io, fname,
				 smb2_util_share_access(""),
				 smb2_util_oplock_level("b"));
	io.in.durable_open = false;
	io.in.durable_open_v2 = true;
	io.in.persistent_open = false;
	io.in.create_guid = create_guid;
	io.in.timeout = UINT32_MAX;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	_h = io.out.file.handle;
	h = &_h;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
	CHECK_VAL(io.out.durable_open, false);
	CHECK_VAL(io.out.durable_open_v2, true);
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.timeout, io.in.timeout);

	/* disconnect, leaving the durable open */
	TALLOC_FREE(tree);

	if (!torture_smb2_connection(tctx, &tree)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	/*
	 * first a few failure cases
	 */

	ZERO_STRUCT(io);
	io.in.fname = "";
	io.in.durable_handle_v2 = h;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

	ZERO_STRUCT(io);
	io.in.fname = "__non_existing_fname__";
	io.in.durable_handle_v2 = h;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle_v2 = h;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

	/* a non-zero but non-matching create_guid does not change it: */
	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle_v2 = h;
	io.in.create_guid = create_guid_invalid;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

	/*
	 * now success:
	 * The important difference is that the create_guid is provided.
	 */
	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_open_v2 = false;
	io.in.durable_handle_v2 = h;
	io.in.create_guid = create_guid;
	h = NULL;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.durable_open, false);
	CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
	_h = io.out.file.handle;
	h = &_h;

	/* disconnect one more time */
	TALLOC_FREE(tree);

	if (!torture_smb2_connection(tctx, &tree)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	ZERO_STRUCT(io);
	/* These are completely ignored by the server */
	io.in.security_flags = 0x78;
	io.in.oplock_level = 0x78;
	io.in.impersonation_level = 0x12345678;
	io.in.create_flags = 0x12345678;
	io.in.reserved = 0x12345678;
	io.in.desired_access = 0x12345678;
	io.in.file_attributes = 0x12345678;
	io.in.share_access = 0x12345678;
	io.in.create_disposition = 0x12345678;
	io.in.create_options = 0x12345678;
	io.in.fname = "__non_existing_fname__";

	/*
	 * only io.in.durable_handle_v2 and
	 * io.in.create_guid are checked
	 */
	io.in.durable_open_v2 = false;
	io.in.durable_handle_v2 = h;
	io.in.create_guid = create_guid;
	h = NULL;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.durable_open, false);
	CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
	_h = io.out.file.handle;
	h = &_h;

done:
	if (h != NULL) {
		smb2_util_close(tree, *h);
	}

	smb2_util_unlink(tree, fname);

	talloc_free(tree);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #17
0
/*
   basic testing of SMB2 durable opens
   regarding the position information on the handle
*/
bool test_durable_open_file_position(struct torture_context *tctx,
				     struct smb2_tree *tree1,
				     struct smb2_tree *tree2)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_handle h1, h2;
	struct smb2_create io1, io2;
	NTSTATUS status;
	const char *fname = "durable_open_position.dat";
	union smb_fileinfo qfinfo;
	union smb_setfileinfo sfinfo;
	bool ret = true;
	uint64_t pos;

	smb2_util_unlink(tree1, fname);

	ZERO_STRUCT(io1);
	io1.in.security_flags		= 0x00;
	io1.in.oplock_level		= SMB2_OPLOCK_LEVEL_BATCH;
	io1.in.impersonation_level	= NTCREATEX_IMPERSONATION_IMPERSONATION;
	io1.in.create_flags		= 0x00000000;
	io1.in.reserved			= 0x00000000;
	io1.in.desired_access		= SEC_RIGHTS_FILE_ALL;
	io1.in.file_attributes		= FILE_ATTRIBUTE_NORMAL;
	io1.in.share_access		= NTCREATEX_SHARE_ACCESS_READ |
					  NTCREATEX_SHARE_ACCESS_WRITE |
					  NTCREATEX_SHARE_ACCESS_DELETE;
	io1.in.create_disposition	= NTCREATEX_DISP_OPEN_IF;
	io1.in.create_options		= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
					  NTCREATEX_OPTIONS_ASYNC_ALERT	|
					  NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
					  0x00200000;
	io1.in.durable_open		= true;
	io1.in.fname			= fname;

	status = smb2_create(tree1, mem_ctx, &io1);
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io1.out.file.handle;
	CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);

	/* TODO: check extra blob content */

	ZERO_STRUCT(qfinfo);
	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
	qfinfo.generic.in.file.handle = h1;
	status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_VAL(qfinfo.position_information.out.position, 0);
	pos = qfinfo.position_information.out.position;
	torture_comment(tctx, "position: %llu\n",
			(unsigned long long)pos);

	ZERO_STRUCT(sfinfo);
	sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
	sfinfo.generic.in.file.handle = h1;
	sfinfo.position_information.in.position = 0x1000;
	status = smb2_setinfo_file(tree1, &sfinfo);
	CHECK_STATUS(status, NT_STATUS_OK);

	ZERO_STRUCT(qfinfo);
	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
	qfinfo.generic.in.file.handle = h1;
	status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
	pos = qfinfo.position_information.out.position;
	torture_comment(tctx, "position: %llu\n",
			(unsigned long long)pos);

	talloc_free(tree1);
	tree1 = NULL;

	ZERO_STRUCT(qfinfo);
	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
	qfinfo.generic.in.file.handle = h1;
	status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
	CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);

	ZERO_STRUCT(io2);
	io2.in.fname = fname;
	io2.in.durable_handle = &h1;

	status = smb2_create(tree2, mem_ctx, &io2);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
	CHECK_VAL(io2.out.reserved, 0x00);
	CHECK_VAL(io2.out.create_action, NTCREATEX_ACTION_EXISTED);
	CHECK_VAL(io2.out.alloc_size, 0);
	CHECK_VAL(io2.out.size, 0);
	CHECK_VAL(io2.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io2.out.reserved2, 0);

	h2 = io2.out.file.handle;

	ZERO_STRUCT(qfinfo);
	qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
	qfinfo.generic.in.file.handle = h2;
	status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
	pos = qfinfo.position_information.out.position;
	torture_comment(tctx, "position: %llu\n",
			(unsigned long long)pos);

	smb2_util_close(tree2, h2);

	talloc_free(mem_ctx);

	smb2_util_unlink(tree2, fname);
done:
	return ret;
}
Beispiel #18
0
/**
 * durable reconnect test:
 * connect with v1, reconnect with v2 : fails (no create_guid...)
 */
bool test_durable_v2_open_reopen2c(struct torture_context *tctx,
				   struct smb2_tree *tree)
{
	NTSTATUS status;
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	char fname[256];
	struct smb2_handle _h;
	struct smb2_handle *h = NULL;
	struct smb2_create io;
	struct GUID create_guid = GUID_random();
	bool ret = true;
	struct smbcli_options options;

	options = tree->session->transport->options;

	/* Choose a random name in case the state is left a little funky. */
	snprintf(fname, 256, "durable_v2_open_reopen2c_%s.dat",
		 generate_random_str(tctx, 8));

	smb2_util_unlink(tree, fname);

	smb2_oplock_create_share(&io, fname,
				 smb2_util_share_access(""),
				 smb2_util_oplock_level("b"));
	io.in.durable_open = true;
	io.in.durable_open_v2 = false;
	io.in.persistent_open = false;
	io.in.create_guid = create_guid;
	io.in.timeout = UINT32_MAX;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	_h = io.out.file.handle;
	h = &_h;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
	CHECK_VAL(io.out.durable_open, true);
	CHECK_VAL(io.out.durable_open_v2, false);
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.timeout, 0);

	/* disconnect, leaving the durable open */
	TALLOC_FREE(tree);

	if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle_v2 = h;     /* durable v2 reconnect */
	io.in.create_guid = create_guid;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

done:
	if (h != NULL) {
		smb2_util_close(tree, *h);
	}

	smb2_util_unlink(tree, fname);

	talloc_free(tree);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #19
0
static bool test_smb2_open_for_delete(struct torture_context *tctx,
				      struct smb2_tree *tree)
{
	union smb_open io;
	union smb_fileinfo finfo;
	const char *fname = DNAME "\\torture_open_for_delete.txt";
	NTSTATUS status;
	struct smb2_handle h, h1;
	bool ret = true;

	torture_comment(tctx,
		"Checking SMB2_OPEN for delete on a readonly file.\n");
	smb2_util_unlink(tree, fname);
	smb2_deltree(tree, fname);

	status = torture_smb2_testdir(tree, DNAME, &h);
	CHECK_STATUS(status, NT_STATUS_OK);

	/* reasonable default parameters */
	ZERO_STRUCT(io.smb2);
	io.generic.level = RAW_OPEN_SMB2;
	io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
	io.smb2.in.alloc_size = 0;
	io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
	io.smb2.in.file_attributes = FILE_ATTRIBUTE_READONLY;
	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
	io.smb2.in.create_options = 0;
	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
	io.smb2.in.security_flags = 0;
	io.smb2.in.fname = fname;

	/* Create the readonly file. */

	status = smb2_create(tree, tctx, &(io.smb2));
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io.smb2.out.file.handle;

	CHECK_VAL(io.smb2.out.oplock_level, 0);
	io.smb2.in.create_options = 0;
	CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
	CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
	smb2_util_close(tree, h1);

	/* Now try and open for delete only - should succeed. */
	io.smb2.in.desired_access = SEC_STD_DELETE;
	io.smb2.in.file_attributes = 0;
	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
				NTCREATEX_SHARE_ACCESS_WRITE |
				NTCREATEX_SHARE_ACCESS_DELETE;
	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
	status = smb2_create(tree, tctx, &(io.smb2));
	CHECK_STATUS(status, NT_STATUS_OK);

	smb2_util_unlink(tree, fname);

	smb2_util_close(tree, h1);
	smb2_util_unlink(tree, fname);
	smb2_deltree(tree, DNAME);

	return ret;
}
Beispiel #20
0
static bool test_compound_padding(struct torture_context *tctx,
				  struct smb2_tree *tree)
{
	struct smb2_handle h;
	struct smb2_create cr;
	struct smb2_read r;
	const char *fname = "compound_read.dat";
	const char *sname = "compound_read.dat:foo";
	struct smb2_request *req[3];
	NTSTATUS status;
	bool ret = false;

	smb2_util_unlink(tree, fname);

	/* Write file */
	ZERO_STRUCT(cr);
	cr.in.desired_access = SEC_FILE_WRITE_DATA;
	cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	cr.in.create_disposition = NTCREATEX_DISP_CREATE;
	cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
	cr.in.fname = fname;
	cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
		NTCREATEX_SHARE_ACCESS_WRITE|
		NTCREATEX_SHARE_ACCESS_DELETE;
	status = smb2_create(tree, tctx, &cr);
	CHECK_STATUS(status, NT_STATUS_OK);
	h = cr.out.file.handle;

	status = smb2_util_write(tree, h, "123", 0, 3);
	CHECK_STATUS(status, NT_STATUS_OK);

	smb2_util_close(tree, h);

	/* Write stream */
	ZERO_STRUCT(cr);
	cr.in.desired_access = SEC_FILE_WRITE_DATA;
	cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	cr.in.create_disposition = NTCREATEX_DISP_CREATE;
	cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
	cr.in.fname = sname;
	cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
		NTCREATEX_SHARE_ACCESS_WRITE|
		NTCREATEX_SHARE_ACCESS_DELETE;
	status = smb2_create(tree, tctx, &cr);
	CHECK_STATUS(status, NT_STATUS_OK);
	h = cr.out.file.handle;

	status = smb2_util_write(tree, h, "456", 0, 3);
	CHECK_STATUS(status, NT_STATUS_OK);

	smb2_util_close(tree, h);

	/* Check compound read from basefile */
	smb2_transport_compound_start(tree->session->transport, 2);

	ZERO_STRUCT(cr);
	cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
	cr.in.desired_access	= SEC_FILE_READ_DATA;
	cr.in.file_attributes	= FILE_ATTRIBUTE_NORMAL;
	cr.in.create_disposition = NTCREATEX_DISP_OPEN;
	cr.in.fname		= fname;
	cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
		NTCREATEX_SHARE_ACCESS_WRITE|
		NTCREATEX_SHARE_ACCESS_DELETE;
	req[0] = smb2_create_send(tree, &cr);

	smb2_transport_compound_set_related(tree->session->transport, true);

	ZERO_STRUCT(r);
	h.data[0] = UINT64_MAX;
	h.data[1] = UINT64_MAX;
	r.in.file.handle = h;
	r.in.length      = 3;
	r.in.offset      = 0;
	r.in.min_count      = 1;
	req[1] = smb2_read_send(tree, &r);

	status = smb2_create_recv(req[0], tree, &cr);
	CHECK_STATUS(status, NT_STATUS_OK);

	/*
	 * We must do a manual smb2_request_receive() in order to be
	 * able to check the transport layer info, as smb2_read_recv()
	 * will destroy the req. smb2_read_recv() will call
	 * smb2_request_receive() again, but that's ok.
	 */
	if (!smb2_request_receive(req[1]) ||
	    !smb2_request_is_ok(req[1])) {
		torture_fail(tctx, "failed to receive read request");
	}

	/*
	 * size must be 24: 16 byte read response header plus 3
	 * requested bytes padded to an 8 byte boundary.
	 */
	CHECK_VALUE(req[1]->in.body_size, 24);

	status = smb2_read_recv(req[1], tree, &r);
	CHECK_STATUS(status, NT_STATUS_OK);

	smb2_util_close(tree, cr.out.file.handle);

	/* Check compound read from stream */
	smb2_transport_compound_start(tree->session->transport, 2);

	ZERO_STRUCT(cr);
	cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
	cr.in.desired_access	= SEC_FILE_READ_DATA;
	cr.in.file_attributes	= FILE_ATTRIBUTE_NORMAL;
	cr.in.create_disposition = NTCREATEX_DISP_OPEN;
	cr.in.fname		= sname;
	cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
		NTCREATEX_SHARE_ACCESS_WRITE|
		NTCREATEX_SHARE_ACCESS_DELETE;
	req[0] = smb2_create_send(tree, &cr);

	smb2_transport_compound_set_related(tree->session->transport, true);

	ZERO_STRUCT(r);
	h.data[0] = UINT64_MAX;
	h.data[1] = UINT64_MAX;
	r.in.file.handle = h;
	r.in.length      = 3;
	r.in.offset      = 0;
	r.in.min_count   = 1;
	req[1] = smb2_read_send(tree, &r);

	status = smb2_create_recv(req[0], tree, &cr);
	CHECK_STATUS(status, NT_STATUS_OK);

	/*
	 * We must do a manual smb2_request_receive() in order to be
	 * able to check the transport layer info, as smb2_read_recv()
	 * will destroy the req. smb2_read_recv() will call
	 * smb2_request_receive() again, but that's ok.
	 */
	if (!smb2_request_receive(req[1]) ||
	    !smb2_request_is_ok(req[1])) {
		torture_fail(tctx, "failed to receive read request");
	}

	/*
	 * size must be 24: 16 byte read response header plus 3
	 * requested bytes padded to an 8 byte boundary.
	 */
	CHECK_VALUE(req[1]->in.body_size, 24);

	status = smb2_read_recv(req[1], tree, &r);
	CHECK_STATUS(status, NT_STATUS_OK);

	h = cr.out.file.handle;

	/* Check 2 compound (unrelateated) reads from existing stream handle */
	smb2_transport_compound_start(tree->session->transport, 2);

	ZERO_STRUCT(r);
	r.in.file.handle = h;
	r.in.length      = 3;
	r.in.offset      = 0;
	r.in.min_count   = 1;
	req[0] = smb2_read_send(tree, &r);
	req[1] = smb2_read_send(tree, &r);

	/*
	 * We must do a manual smb2_request_receive() in order to be
	 * able to check the transport layer info, as smb2_read_recv()
	 * will destroy the req. smb2_read_recv() will call
	 * smb2_request_receive() again, but that's ok.
	 */
	if (!smb2_request_receive(req[0]) ||
	    !smb2_request_is_ok(req[0])) {
		torture_fail(tctx, "failed to receive read request");
	}
	if (!smb2_request_receive(req[1]) ||
	    !smb2_request_is_ok(req[1])) {
		torture_fail(tctx, "failed to receive read request");
	}

	/*
	 * size must be 24: 16 byte read response header plus 3
	 * requested bytes padded to an 8 byte boundary.
	 */
	CHECK_VALUE(req[0]->in.body_size, 24);
	CHECK_VALUE(req[1]->in.body_size, 24);

	status = smb2_read_recv(req[0], tree, &r);
	CHECK_STATUS(status, NT_STATUS_OK);
	status = smb2_read_recv(req[1], tree, &r);
	CHECK_STATUS(status, NT_STATUS_OK);

	/*
	 * now try a single read from the stream and verify there's no padding
	 */
	ZERO_STRUCT(r);
	r.in.file.handle = h;
	r.in.length      = 3;
	r.in.offset      = 0;
	r.in.min_count   = 1;
	req[0] = smb2_read_send(tree, &r);

	/*
	 * We must do a manual smb2_request_receive() in order to be
	 * able to check the transport layer info, as smb2_read_recv()
	 * will destroy the req. smb2_read_recv() will call
	 * smb2_request_receive() again, but that's ok.
	 */
	if (!smb2_request_receive(req[0]) ||
	    !smb2_request_is_ok(req[0])) {
		torture_fail(tctx, "failed to receive read request");
	}

	/*
	 * size must be 19: 16 byte read response header plus 3
	 * requested bytes without padding.
	 */
	CHECK_VALUE(req[0]->in.body_size, 19);

	status = smb2_read_recv(req[0], tree, &r);
	CHECK_STATUS(status, NT_STATUS_OK);

	smb2_util_close(tree, h);

	status = smb2_util_unlink(tree, fname);
	CHECK_STATUS(status, NT_STATUS_OK);

	ret = true;
done:
	return ret;
}
Beispiel #21
0
static bool test_smb2_open_brlocked(struct torture_context *tctx,
				    struct smb2_tree *tree)
{
	union smb_open io, io1;
	union smb_lock io2;
	struct smb2_lock_element lock[1];
	const char *fname = DNAME "\\torture_ntcreatex.txt";
	NTSTATUS status;
	bool ret = true;
	struct smb2_handle h;
	char b = 42;

	torture_comment(tctx,
		"Testing SMB2 open with a byte range locked file\n");

	smb2_util_unlink(tree, fname);

	status = torture_smb2_testdir(tree, DNAME, &h);
	CHECK_STATUS(status, NT_STATUS_OK);

	ZERO_STRUCT(io.smb2);
	io.generic.level = RAW_OPEN_SMB2;
	io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
	io.smb2.in.desired_access = 0x2019f;
	io.smb2.in.alloc_size = 0;
	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
		NTCREATEX_SHARE_ACCESS_WRITE;
	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
	io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
	io.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
	io.smb2.in.fname = fname;

	status = smb2_create(tree, tctx, &(io.smb2));
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_util_write(tree, io.smb2.out.file.handle, &b, 0, 1);
	CHECK_STATUS(status, NT_STATUS_OK);

	ZERO_STRUCT(io2.smb2);
	io2.smb2.level = RAW_LOCK_SMB2;
	io2.smb2.in.file.handle = io.smb2.out.file.handle;
	io2.smb2.in.lock_count = 1;

	ZERO_STRUCT(lock);
	lock[0].offset = 0;
	lock[0].length = 1;
	lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
			SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
	io2.smb2.in.locks = &lock[0];
	status = smb2_lock(tree, &(io2.smb2));
	CHECK_STATUS(status, NT_STATUS_OK);

	ZERO_STRUCT(io1.smb2);
	io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
	io1.smb2.in.desired_access = 0x20196;
	io1.smb2.in.alloc_size = 0;
	io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
		NTCREATEX_SHARE_ACCESS_WRITE;
	io1.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
	io1.smb2.in.create_options = 0;
	io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
	io1.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
	io1.smb2.in.fname = fname;

	status = smb2_create(tree, tctx, &(io1.smb2));
	CHECK_STATUS(status, NT_STATUS_OK);

	smb2_util_close(tree, io.smb2.out.file.handle);
	smb2_util_close(tree, io1.smb2.out.file.handle);
	smb2_util_unlink(tree, fname);
	smb2_deltree(tree, DNAME);

	return ret;
}
Beispiel #22
0
/*
 * Test creating a file with a NULL DACL.
 */
static bool test_create_null_dacl(struct torture_context *tctx,
    struct smb2_tree *tree)
{
	NTSTATUS status;
	struct smb2_create io;
	const char *fname = "nulldacl.txt";
	bool ret = true;
	struct smb2_handle handle;
	union smb_fileinfo q;
	union smb_setfileinfo s;
	struct security_descriptor *sd = security_descriptor_initialise(tctx);
	struct security_acl dacl;

	torture_comment(tctx, "TESTING SEC_DESC WITH A NULL DACL\n");

	smb2_util_unlink(tree, fname);

	ZERO_STRUCT(io);
	io.level = RAW_OPEN_SMB2;
	io.in.create_flags = 0;
	io.in.desired_access = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC
		| SEC_STD_WRITE_OWNER;
	io.in.create_options = 0;
	io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	io.in.share_access =
		NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
	io.in.alloc_size = 0;
	io.in.create_disposition = NTCREATEX_DISP_CREATE;
	io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
	io.in.security_flags = 0;
	io.in.fname = fname;
	io.in.sec_desc = sd;
	/* XXX create_options ? */
	io.in.create_options		= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
					  NTCREATEX_OPTIONS_ASYNC_ALERT	|
					  NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
					  0x00200000;

	torture_comment(tctx, "creating a file with a empty sd\n");
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	handle = io.out.file.handle;

	torture_comment(tctx, "get the original sd\n");
	q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
	q.query_secdesc.in.file.handle = handle;
	q.query_secdesc.in.secinfo_flags =
		SECINFO_OWNER |
		SECINFO_GROUP |
		SECINFO_DACL;
	status = smb2_getinfo_file(tree, tctx, &q);
	CHECK_STATUS(status, NT_STATUS_OK);

	/*
	 * Testing the created DACL,
	 * the server should add the inherited DACL
	 * when SEC_DESC_DACL_PRESENT isn't specified
	 */
	if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
		ret = false;
		torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
	}
	if (q.query_secdesc.out.sd->dacl == NULL) {
		ret = false;
		torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
	}

	torture_comment(tctx, "set NULL DACL\n");
	sd->type |= SEC_DESC_DACL_PRESENT;

	s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
	s.set_secdesc.in.file.handle = handle;
	s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
	s.set_secdesc.in.sd = sd;
	status = smb2_setinfo_file(tree, &s);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "get the sd\n");
	q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
	q.query_secdesc.in.file.handle = handle;
	q.query_secdesc.in.secinfo_flags =
		SECINFO_OWNER |
		SECINFO_GROUP |
		SECINFO_DACL;
	status = smb2_getinfo_file(tree, tctx, &q);
	CHECK_STATUS(status, NT_STATUS_OK);

	/* Testing the modified DACL */
	if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
		ret = false;
		torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
	}
	if (q.query_secdesc.out.sd->dacl != NULL) {
		ret = false;
		torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
	}

	io.in.create_disposition = NTCREATEX_DISP_OPEN;

	torture_comment(tctx, "try open for read control\n");
	io.in.desired_access = SEC_STD_READ_CONTROL;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_ACCESS_FLAGS(io.out.file.handle,
		SEC_STD_READ_CONTROL);
	smb2_util_close(tree, io.out.file.handle);

	torture_comment(tctx, "try open for write\n");
	io.in.desired_access = SEC_FILE_WRITE_DATA;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_ACCESS_FLAGS(io.out.file.handle,
		SEC_FILE_WRITE_DATA);
	smb2_util_close(tree, io.out.file.handle);

	torture_comment(tctx, "try open for read\n");
	io.in.desired_access = SEC_FILE_READ_DATA;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_ACCESS_FLAGS(io.out.file.handle,
		SEC_FILE_READ_DATA);
	smb2_util_close(tree, io.out.file.handle);

	torture_comment(tctx, "try open for generic write\n");
	io.in.desired_access = SEC_GENERIC_WRITE;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_ACCESS_FLAGS(io.out.file.handle,
		SEC_RIGHTS_FILE_WRITE);
	smb2_util_close(tree, io.out.file.handle);

	torture_comment(tctx, "try open for generic read\n");
	io.in.desired_access = SEC_GENERIC_READ;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_ACCESS_FLAGS(io.out.file.handle,
		SEC_RIGHTS_FILE_READ);
	smb2_util_close(tree, io.out.file.handle);

	torture_comment(tctx, "set DACL with 0 aces\n");
	ZERO_STRUCT(dacl);
	dacl.revision = SECURITY_ACL_REVISION_NT4;
	dacl.num_aces = 0;
	sd->dacl = &dacl;

	s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
	s.set_secdesc.in.file.handle = handle;
	s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
	s.set_secdesc.in.sd = sd;
	status = smb2_setinfo_file(tree, &s);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "get the sd\n");
	q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
	q.query_secdesc.in.file.handle = handle;
	q.query_secdesc.in.secinfo_flags =
		SECINFO_OWNER |
		SECINFO_GROUP |
		SECINFO_DACL;
	status = smb2_getinfo_file(tree, tctx, &q);
	CHECK_STATUS(status, NT_STATUS_OK);

	/* Testing the modified DACL */
	if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
		ret = false;
		torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
	}
	if (q.query_secdesc.out.sd->dacl == NULL) {
		ret = false;
		torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
	}
	if (q.query_secdesc.out.sd->dacl->num_aces != 0) {
		torture_result(tctx, TORTURE_FAIL, "DACL has %u aces!\n",
		       q.query_secdesc.out.sd->dacl->num_aces);
		ret = false;
		goto done;
	}

	torture_comment(tctx, "try open for read control\n");
	io.in.desired_access = SEC_STD_READ_CONTROL;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_ACCESS_FLAGS(io.out.file.handle,
		SEC_STD_READ_CONTROL);
	smb2_util_close(tree, io.out.file.handle);

	torture_comment(tctx, "try open for write => access_denied\n");
	io.in.desired_access = SEC_FILE_WRITE_DATA;
	status = smb2_create(tree, tctx, &io);
	if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
		CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
	} else {
		CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
	}

	torture_comment(tctx, "try open for read => access_denied\n");
	io.in.desired_access = SEC_FILE_READ_DATA;
	status = smb2_create(tree, tctx, &io);
	if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
		CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
	} else {
		CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
	}

	torture_comment(tctx, "try open for generic write => access_denied\n");
	io.in.desired_access = SEC_GENERIC_WRITE;
	status = smb2_create(tree, tctx, &io);
	if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
		CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
	} else {
		CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
	}

	torture_comment(tctx, "try open for generic read => access_denied\n");
	io.in.desired_access = SEC_GENERIC_READ;
	status = smb2_create(tree, tctx, &io);
	if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
		CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
	} else {
		CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
	}

	torture_comment(tctx, "set empty sd\n");
	sd->type &= ~SEC_DESC_DACL_PRESENT;
	sd->dacl = NULL;

	s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
	s.set_secdesc.in.file.handle = handle;
	s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
	s.set_secdesc.in.sd = sd;
	status = smb2_setinfo_file(tree, &s);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "get the sd\n");
	q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
	q.query_secdesc.in.file.handle = handle;
	q.query_secdesc.in.secinfo_flags =
		SECINFO_OWNER |
		SECINFO_GROUP |
		SECINFO_DACL;
	status = smb2_getinfo_file(tree, tctx, &q);
	CHECK_STATUS(status, NT_STATUS_OK);

	/* Testing the modified DACL */
	if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
		ret = false;
		torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
	}
	if (q.query_secdesc.out.sd->dacl != NULL) {
		ret = false;
		torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
	}
done:
	smb2_util_close(tree, handle);
	smb2_util_unlink(tree, fname);
	smb2_tdis(tree);
	smb2_logoff(tree->session);
	return ret;
}
Beispiel #23
0
static bool test_fixed(struct torture_context *tctx,
		       struct smb2_tree *tree)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create create;
	struct smb2_handle h, h2;
	struct smb2_find f;
	union smb_search_data *d;
	struct file_elem files[NFILES] = {};
	NTSTATUS status;
	bool ret = true;
	unsigned int count;
	int i;

	status = populate_tree(tctx, mem_ctx, tree, files, NFILES, &h);

	ZERO_STRUCT(create);
	create.in.desired_access = SEC_RIGHTS_DIR_ALL;
	create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
	create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
	create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
				 NTCREATEX_SHARE_ACCESS_WRITE |
				 NTCREATEX_SHARE_ACCESS_DELETE;
	create.in.create_disposition = NTCREATEX_DISP_OPEN;
	create.in.fname = DNAME;

	status = smb2_create(tree, mem_ctx, &create);
	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
	h2 = create.out.file.handle;

	ZERO_STRUCT(f);
	f.in.file.handle	= h;
	f.in.pattern		= "*";
	f.in.continue_flags	= SMB2_CONTINUE_FLAG_SINGLE;
	f.in.max_response_size	= 0x100;
	f.in.level              = SMB2_FIND_BOTH_DIRECTORY_INFO;

	/* Start enumeration on h, then delete all from h2 */
	status = smb2_find_level(tree, tree, &f, &count, &d);
	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");

	f.in.file.handle	= h2;

	do {
		status = smb2_find_level(tree, tree, &f, &count, &d);
		if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
			break;
		torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");

		for (i = 0; i < count; i++) {
			const char *found = d[i].both_directory_info.name.s;
			char *path = talloc_asprintf(mem_ctx, "%s\\%s",
			    DNAME, found);

			if (!strcmp(found, ".") || !strcmp(found, ".."))
				continue;

			status = smb2_util_unlink(tree, path);
			torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
							"");

			talloc_free(path);
		}

		f.in.continue_flags = 0;
		f.in.max_response_size	= 4096;
	} while (count != 0);

	/* Now finish h enumeration. */
	f.in.file.handle = h;

	do {
		status = smb2_find_level(tree, tree, &f, &count, &d);
		if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
			break;
		torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");

		for (i = 0; i < count; i++) {
			const char *found = d[i].both_directory_info.name.s;

			if (!strcmp(found, ".") || !strcmp(found, ".."))
				continue;

			torture_result(tctx, TORTURE_FAIL,
			    "(%s): didn't expect %s\n",
			    __location__, found);
			ret = false;
			goto done;
		}

		f.in.continue_flags = 0;
		f.in.max_response_size	= 4096;
	} while (count != 0);

 done:
	smb2_util_close(tree, h);
	smb2_util_close(tree, h2);
	smb2_deltree(tree, DNAME);
	talloc_free(mem_ctx);

	return ret;
}
Beispiel #24
0
/*
  try the various request blobs
 */
static bool test_create_blob(struct torture_context *tctx, struct smb2_tree *tree)
{
	struct smb2_create io;
	NTSTATUS status;

	smb2_deltree(tree, FNAME);

	ZERO_STRUCT(io);
	io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
	io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
	io.in.create_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		= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
					  NTCREATEX_OPTIONS_ASYNC_ALERT	|
					  NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
					  0x00200000;
	io.in.fname = FNAME;

	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "Testing alloc size\n");
	io.in.alloc_size = 4096;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size);

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "Testing durable open\n");
	io.in.durable_open = true;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "Testing query maximal access\n");
	io.in.query_maximal_access = true;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "Testing timewarp\n");
	io.in.timewarp = 10000;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
	io.in.timewarp = 0;

	torture_comment(tctx, "Testing query_on_disk\n");
	io.in.query_on_disk_id = true;
	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "Testing unknown tag\n");
	status = smb2_create_blob_add(tctx, &io.in.blobs,
				      "FooO", data_blob(NULL, 0));
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_util_close(tree, io.out.file.handle);
	CHECK_STATUS(status, NT_STATUS_OK);

	torture_comment(tctx, "Testing bad tag length\n");
	status = smb2_create_blob_add(tctx, &io.in.blobs,
				      "xxx", data_blob(NULL, 0));
	CHECK_STATUS(status, NT_STATUS_OK);

	status = smb2_create(tree, tctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	smb2_deltree(tree, FNAME);
	
	return true;
}
Beispiel #25
0
/**
 * lease_v2 variant of reopen2
 * basic test for doing a durable open
 * tcp disconnect, reconnect, do a durable reopen (succeeds)
 */
bool test_durable_v2_open_reopen2_lease_v2(struct torture_context *tctx,
					   struct smb2_tree *tree)
{
	NTSTATUS status;
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	char fname[256];
	struct smb2_handle _h;
	struct smb2_handle *h = NULL;
	struct smb2_create io;
	struct GUID create_guid = GUID_random();
	struct smb2_lease ls;
	uint64_t lease_key;
	bool ret = true;
	struct smbcli_options options;
	uint32_t caps;

	caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
	if (!(caps & SMB2_CAP_LEASING)) {
		torture_skip(tctx, "leases are not supported");
	}

	options = tree->session->transport->options;

	/* Choose a random name in case the state is left a little funky. */
	snprintf(fname, 256, "durable_v2_open_reopen2_%s.dat",
		 generate_random_str(tctx, 8));

	smb2_util_unlink(tree, fname);

	lease_key = random();
	smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
			     lease_key, 0, /* parent lease key */
			     smb2_util_lease_state("RWH"), 0 /* lease epoch */);
	io.in.durable_open = false;
	io.in.durable_open_v2 = true;
	io.in.persistent_open = false;
	io.in.create_guid = create_guid;
	io.in.timeout = UINT32_MAX;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	_h = io.out.file.handle;
	h = &_h;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.durable_open, false);
	CHECK_VAL(io.out.durable_open_v2, true);
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.timeout, io.in.timeout);
	CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
	CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
	CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);

	/* disconnect, reconnect and then do durable reopen */
	TALLOC_FREE(tree);

	if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	/* a few failure tests: */

	/*
	 * several attempts without lease attached:
	 * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
	 * irrespective of file name provided
	 */

	ZERO_STRUCT(io);
	io.in.fname = "";
	io.in.durable_handle_v2 = h;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

	ZERO_STRUCT(io);
	io.in.fname = "__non_existing_fname__";
	io.in.durable_handle_v2 = h;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_handle_v2 = h;
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

	/*
	 * attempt with lease provided, but
	 * with a changed lease key. => fails
	 */
	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_open_v2 = false;
	io.in.durable_handle_v2 = h;
	io.in.create_guid = create_guid;
	io.in.lease_request_v2 = &ls;
	io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
	/* a wrong lease key lets the request fail */
	ls.lease_key.data[0]++;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);

	/* restore the correct lease key */
	ls.lease_key.data[0]--;


	/*
	 * this last failing attempt is almost correct:
	 * only problem is: we use the wrong filename...
	 * Note that this gives INVALID_PARAMETER.
	 * This is different from oplocks!
	 */
	ZERO_STRUCT(io);
	io.in.fname = "__non_existing_fname__";
	io.in.durable_open_v2 = false;
	io.in.durable_handle_v2 = h;
	io.in.create_guid = create_guid;
	io.in.lease_request_v2 = &ls;
	io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	/*
	 * Now for a succeeding reconnect:
	 */

	ZERO_STRUCT(io);
	io.in.fname = fname;
	io.in.durable_open_v2 = false;
	io.in.durable_handle_v2 = h;
	io.in.create_guid = create_guid;
	io.in.lease_request_v2 = &ls;
	io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;

	/* the requested lease state is irrelevant */
	ls.lease_state = smb2_util_lease_state("");

	h = NULL;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);

	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.durable_open, false);
	CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
	CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
	CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
	CHECK_VAL(io.out.lease_response_v2.lease_state,
		  smb2_util_lease_state("RWH"));
	CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
	CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
	_h = io.out.file.handle;
	h = &_h;

	/* disconnect one more time */
	TALLOC_FREE(tree);

	if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
		torture_warning(tctx, "couldn't reconnect, bailing\n");
		ret = false;
		goto done;
	}

	/*
	 * demonstrate that various parameters are ignored
	 * in the reconnect
	 */

	ZERO_STRUCT(io);
	/*
	 * These are completely ignored by the server
	 */
	io.in.security_flags = 0x78;
	io.in.oplock_level = 0x78;
	io.in.impersonation_level = 0x12345678;
	io.in.create_flags = 0x12345678;
	io.in.reserved = 0x12345678;
	io.in.desired_access = 0x12345678;
	io.in.file_attributes = 0x12345678;
	io.in.share_access = 0x12345678;
	io.in.create_disposition = 0x12345678;
	io.in.create_options = 0x12345678;
	io.in.fname = "__non_existing_fname__";

	/*
	 * only these are checked:
	 * - io.in.fname
	 * - io.in.durable_handle_v2,
	 * - io.in.create_guid
	 * - io.in.lease_request_v2->lease_key
	 */

	io.in.fname = fname;
	io.in.durable_open_v2 = false;
	io.in.durable_handle_v2 = h;
	io.in.create_guid = create_guid;
	io.in.lease_request_v2 = &ls;

	/* the requested lease state is irrelevant */
	ls.lease_state = smb2_util_lease_state("");

	h = NULL;

	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_VAL(io.out.durable_open, false);
	CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
	CHECK_VAL(io.out.persistent_open, false);
	CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
	CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
	CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
	CHECK_VAL(io.out.lease_response_v2.lease_state,
		  smb2_util_lease_state("RWH"));
	CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
	CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);

	_h = io.out.file.handle;
	h = &_h;

done:
	if (h != NULL) {
		smb2_util_close(tree, *h);
	}

	smb2_util_unlink(tree, fname);

	talloc_free(tree);

	talloc_free(mem_ctx);

	return ret;
}
Beispiel #26
0
/*
  test SMB2 open
*/
static bool test_smb2_open(struct torture_context *tctx,
			   struct smb2_tree *tree)
{
	union smb_open io;
	union smb_fileinfo finfo;
	const char *fname = DNAME "\\torture_ntcreatex.txt";
	const char *dname = DNAME "\\torture_ntcreatex.dir";
	NTSTATUS status;
	struct smb2_handle h, h1;
	bool ret = true;
	int i;
	struct {
		uint32_t create_disp;
		bool with_file;
		NTSTATUS correct_status;
	} open_funcs[] = {
		{ NTCREATEX_DISP_SUPERSEDE,     true,  NT_STATUS_OK },
		{ NTCREATEX_DISP_SUPERSEDE,     false, NT_STATUS_OK },
		{ NTCREATEX_DISP_OPEN,          true,  NT_STATUS_OK },
		{ NTCREATEX_DISP_OPEN,          false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
		{ NTCREATEX_DISP_CREATE,        true,  NT_STATUS_OBJECT_NAME_COLLISION },
		{ NTCREATEX_DISP_CREATE,        false, NT_STATUS_OK },
		{ NTCREATEX_DISP_OPEN_IF,       true,  NT_STATUS_OK },
		{ NTCREATEX_DISP_OPEN_IF,       false, NT_STATUS_OK },
		{ NTCREATEX_DISP_OVERWRITE,     true,  NT_STATUS_OK },
		{ NTCREATEX_DISP_OVERWRITE,     false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
		{ NTCREATEX_DISP_OVERWRITE_IF,  true,  NT_STATUS_OK },
		{ NTCREATEX_DISP_OVERWRITE_IF,  false, NT_STATUS_OK },
		{ 6,                            true,  NT_STATUS_INVALID_PARAMETER },
		{ 6,                            false, NT_STATUS_INVALID_PARAMETER },
	};

	torture_comment(tctx, "Checking SMB2 Open\n");

	smb2_util_unlink(tree, fname);
	smb2_util_rmdir(tree, dname);

	status = torture_smb2_testdir(tree, DNAME, &h);
	CHECK_STATUS(status, NT_STATUS_OK);

	ZERO_STRUCT(io.smb2);
	/* reasonable default parameters */
	io.generic.level = RAW_OPEN_SMB2;
	io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
	io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
	io.smb2.in.alloc_size = 1024*1024;
	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
	io.smb2.in.create_options = 0;
	io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
	io.smb2.in.security_flags = 0;
	io.smb2.in.fname = fname;

	/* test the create disposition */
	for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
		if (open_funcs[i].with_file) {
			io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
			status= smb2_create(tree, tctx, &(io.smb2));
			if (!NT_STATUS_IS_OK(status)) {
				torture_comment(tctx,
				    "Failed to create file %s status %s %d\n",
				    fname, nt_errstr(status), i);

				ret = false;
				goto done;
			}
			smb2_util_close(tree, io.smb2.out.file.handle);
		}
		io.smb2.in.create_disposition = open_funcs[i].create_disp;
		status = smb2_create(tree, tctx, &(io.smb2));
		if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
			torture_comment(tctx,
			    "(%s) incorrect status %s should be %s (i=%d "
			    "with_file=%d open_disp=%d)\n",
			 __location__, nt_errstr(status),
			nt_errstr(open_funcs[i].correct_status),
			i, (int)open_funcs[i].with_file,
			(int)open_funcs[i].create_disp);

			ret = false;
			goto done;
		}
		if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
			smb2_util_close(tree, io.smb2.out.file.handle);
			smb2_util_unlink(tree, fname);
		}
	}

	/* basic field testing */
	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;

	status = smb2_create(tree, tctx, &(io.smb2));
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io.smb2.out.file.handle;

	CHECK_VAL(io.smb2.out.oplock_level, 0);
	CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
	CHECK_NTTIME(io.smb2.out.create_time, create_time);
	CHECK_NTTIME(io.smb2.out.access_time, access_time);
	CHECK_NTTIME(io.smb2.out.write_time, write_time);
	CHECK_NTTIME(io.smb2.out.change_time, change_time);
	CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
	CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
	CHECK_ALL_INFO(io.smb2.out.size, size);

	/* check fields when the file already existed */
	smb2_util_close(tree, h1);
	smb2_util_unlink(tree, fname);

	status = smb2_create_complex_file(tree, fname, &h1);
	CHECK_STATUS(status, NT_STATUS_OK);

	smb2_util_close(tree, h1);

	io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
	status = smb2_create(tree, tctx, &(io.smb2));
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io.smb2.out.file.handle;

	CHECK_VAL(io.smb2.out.oplock_level, 0);
	CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_EXISTED);
	CHECK_NTTIME(io.smb2.out.create_time, create_time);
	CHECK_NTTIME(io.smb2.out.access_time, access_time);
	CHECK_NTTIME(io.smb2.out.write_time, write_time);
	CHECK_NTTIME(io.smb2.out.change_time, change_time);
	CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
	CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
	CHECK_ALL_INFO(io.smb2.out.size, size);
	smb2_util_close(tree, h1);
	smb2_util_unlink(tree, fname);

	/* create a directory */
	io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
	io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
	io.smb2.in.alloc_size = 0;
	io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
	io.smb2.in.create_options = 0;
	io.smb2.in.fname = dname;
	fname = dname;

	smb2_util_rmdir(tree, fname);
	smb2_util_unlink(tree, fname);

	io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
	io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
	io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
	io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
				NTCREATEX_SHARE_ACCESS_WRITE;
	status = smb2_create(tree, tctx, &(io.smb2));
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io.smb2.out.file.handle;

	CHECK_VAL(io.smb2.out.oplock_level, 0);
	CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
	CHECK_NTTIME(io.smb2.out.create_time, create_time);
	CHECK_NTTIME(io.smb2.out.access_time, access_time);
	CHECK_NTTIME(io.smb2.out.write_time, write_time);
	CHECK_NTTIME(io.smb2.out.change_time, change_time);
	CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
	CHECK_VAL(io.smb2.out.file_attr & ~FILE_ATTRIBUTE_NONINDEXED,
		  FILE_ATTRIBUTE_DIRECTORY);
	CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
	CHECK_ALL_INFO(io.smb2.out.size, size);
	CHECK_VAL(io.smb2.out.size, 0);
	CHECK_VAL(io.smb2.out.alloc_size, 0);
	smb2_util_unlink(tree, fname);

done:
	smb2_util_close(tree, h1);
	smb2_util_unlink(tree, fname);
	smb2_deltree(tree, DNAME);
	return ret;
}
Beispiel #27
0
static bool test_lease_request(struct torture_context *tctx,
	                       struct smb2_tree *tree)
{
	TALLOC_CTX *mem_ctx = talloc_new(tctx);
	struct smb2_create io;
	struct smb2_lease ls;
	struct smb2_handle h1, h2;
	NTSTATUS status;
	const char *fname = "lease.dat";
	const char *fname2 = "lease2.dat";
	const char *sname = "lease.dat:stream";
	const char *dname = "lease.dir";
	bool ret = true;
	int i;
	uint32_t caps;

	caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
	if (!(caps & SMB2_CAP_LEASING)) {
		torture_skip(tctx, "leases are not supported");
	}

	smb2_util_unlink(tree, fname);
	smb2_util_unlink(tree, fname2);
	smb2_util_rmdir(tree, dname);

	/* Win7 is happy to grant RHW leases on files. */
	smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	h1 = io.out.file.handle;
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RHW", true, LEASE1);

	/* But will reject leases on directories. */
	smb2_lease_create(&io, &ls, true, dname, LEASE2, smb2_util_lease_state("RHW"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
	CHECK_LEASE(&io, "", false, 0);
	smb2_util_close(tree, io.out.file.handle);

	/* Also rejects multiple files leased under the same key. */
	smb2_lease_create(&io, &ls, true, fname2, LEASE1, smb2_util_lease_state("RHW"));
	status = smb2_create(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

	/* And grants leases on streams (with separate leasekey). */
	smb2_lease_create(&io, &ls, false, sname, LEASE2, smb2_util_lease_state("RHW"));
	status = smb2_create(tree, mem_ctx, &io);
	h2 = io.out.file.handle;
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
	CHECK_LEASE(&io, "RHW", true, LEASE2);
	smb2_util_close(tree, h2);

	smb2_util_close(tree, h1);

	/* Now see what combos are actually granted. */
	for (i = 0; i < NREQUEST_RESULTS; i++) {
		torture_comment(tctx, "Requesting lease type %s(%x),"
		    " expecting %s(%x)\n",
		    request_results[i][0], smb2_util_lease_state(request_results[i][0]),
		    request_results[i][1], smb2_util_lease_state(request_results[i][1]));
		smb2_lease_create(&io, &ls, false, fname, LEASE1,
		    smb2_util_lease_state(request_results[i][0]));
		status = smb2_create(tree, mem_ctx, &io);
		h2 = io.out.file.handle;
		CHECK_STATUS(status, NT_STATUS_OK);
		CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
		CHECK_LEASE(&io, request_results[i][1], true, LEASE1);
		smb2_util_close(tree, io.out.file.handle);
	}

 done:
	smb2_util_close(tree, h1);
	smb2_util_close(tree, h2);

	smb2_util_unlink(tree, fname);
	smb2_util_unlink(tree, fname2);
	smb2_util_rmdir(tree, dname);

	talloc_free(mem_ctx);

	return ret;
}