Exemplo n.º 1
0
Arquivo: smb2.c Projeto: gojdic/samba
static bool wrap_simple_2smb2_test(struct torture_context *torture_ctx,
				   struct torture_tcase *tcase,
				   struct torture_test *test)
{
	bool (*fn) (struct torture_context *, struct smb2_tree *, struct smb2_tree *);
	bool ret;

	struct smb2_tree *tree1;
	struct smb2_tree *tree2;
	TALLOC_CTX *mem_ctx = talloc_new(torture_ctx);

	if (!torture_smb2_connection(torture_ctx, &tree1) ||
	    !torture_smb2_connection(torture_ctx, &tree2)) {
		return false;
	}

	talloc_steal(mem_ctx, tree1);
	talloc_steal(mem_ctx, tree2);

	fn = test->fn;

	ret = fn(torture_ctx, tree1, tree2);

	/* the test may already closed some of the connections */
	talloc_free(mem_ctx);

	return ret;
}
Exemplo n.º 2
0
static bool wrap_simple_1smb2_test(struct torture_context *torture_ctx,
				   struct torture_tcase *tcase,
				   struct torture_test *test)
{
	bool (*fn) (struct torture_context *, struct smb2_tree *);
	bool ret;
	struct smb2_tree *tree1;
	TALLOC_CTX *mem_ctx = talloc_new(torture_ctx);

	if (!torture_smb2_connection(torture_ctx, &tree1)) {
		torture_fail(torture_ctx,
			    "Establishing SMB2 connection failed\n");
		return false;
	}

	/*
	 * This is a trick:
	 * The test might close the connection. If we steal the tree context
	 * before that and free the parent instead of tree directly, we avoid
	 * a double free error.
	 */
	talloc_steal(mem_ctx, tree1);

	fn = test->fn;

	ret = fn(torture_ctx, tree1);

	talloc_free(mem_ctx);

	return ret;
}
Exemplo n.º 3
0
/* basic testing of all SMB2 getinfo levels
*/
bool torture_smb2_getinfo(struct torture_context *torture)
{
	TALLOC_CTX *mem_ctx = talloc_new(NULL);
	struct smb2_tree *tree;
	bool ret = true;
	NTSTATUS status;

	if (!torture_smb2_connection(torture, &tree)) {
		return false;
	}

	smb2_deltree(tree, FNAME);
	smb2_deltree(tree, DNAME);

	status = torture_setup_complex_file(tree, FNAME);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}
	torture_setup_complex_file(tree, FNAME ":streamtwo");
	status = torture_setup_complex_dir(tree, DNAME);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}
	torture_setup_complex_file(tree, DNAME ":streamtwo");

	ret &= torture_smb2_fileinfo(torture, tree);
	ret &= torture_smb2_fsinfo(tree);
	ret &= torture_smb2_buffercheck(tree);

	talloc_free(mem_ctx);

	return ret;
}
Exemplo n.º 4
0
static bool wrap_simple_2smb2_test(struct torture_context *torture_ctx,
				   struct torture_tcase *tcase,
				   struct torture_test *test)
{
	bool (*fn) (struct torture_context *, struct smb2_tree *, struct smb2_tree *);
	bool ret = false;

	struct smb2_tree *tree1;
	struct smb2_tree *tree2;
	TALLOC_CTX *mem_ctx = talloc_new(torture_ctx);

	if (!torture_smb2_connection(torture_ctx, &tree1)) {
		torture_fail(torture_ctx,
		    "Establishing SMB2 connection failed\n");
		goto done;
	}

	talloc_steal(mem_ctx, tree1);

	if (!torture_smb2_connection(torture_ctx, &tree2)) {
		torture_fail(torture_ctx,
		    "Establishing SMB2 connection failed\n");
		goto done;
	}

	talloc_steal(mem_ctx, tree2);

	fn = test->fn;

	ret = fn(torture_ctx, tree1, tree2);

done:
	/* the test may already have closed some of the connections */
	talloc_free(mem_ctx);

	return ret;
}
Exemplo n.º 5
0
/* basic testing of SMB2 notify
*/
BOOL torture_smb2_notify(struct torture_context *torture)
{
	TALLOC_CTX *mem_ctx = talloc_new(NULL);
	struct smb2_tree *tree;
	BOOL ret = True;

	if (!torture_smb2_connection(mem_ctx, &tree)) {
		return False;
	}

	ret &= test_valid_request(mem_ctx, tree);

	talloc_free(mem_ctx);

	return ret;
}
Exemplo n.º 6
0
Arquivo: smb2.c Projeto: gojdic/samba
static bool wrap_simple_1smb2_test(struct torture_context *torture_ctx,
				   struct torture_tcase *tcase,
				   struct torture_test *test)
{
	bool (*fn) (struct torture_context *, struct smb2_tree *);
	bool ret;

	struct smb2_tree *tree1;

	if (!torture_smb2_connection(torture_ctx, &tree1))
		return false;

	fn = test->fn;

	ret = fn(torture_ctx, tree1);

	talloc_free(tree1);

	return ret;
}
Exemplo n.º 7
0
/* 
   basic testing of SMB2 connection calls
*/
BOOL torture_smb2_maxwrite(struct torture_context *torture)
{
	TALLOC_CTX *mem_ctx = talloc_new(NULL);
	struct smb2_tree *tree;
	struct smb2_handle h1;
	NTSTATUS status;

	if (!torture_smb2_connection(mem_ctx, &tree)) {
		return False;
	}

	h1 = torture_smb2_create(tree, FNAME);
	status = torture_smb2_write(mem_ctx, tree, h1);
	if (!NT_STATUS_IS_OK(status)) {
		printf("Write failed - %s\n", nt_errstr(status));
		return False;
	}

	talloc_free(mem_ctx);

	return True;
}
Exemplo n.º 8
0
static bool test_smb2_open_multi(struct torture_context *tctx,
                                 struct smb2_tree *tree)
{
    const char *fname = "test_oplock.dat";
    NTSTATUS status;
    bool ret = true;
    union smb_open io;
    struct smb2_tree **trees;
    struct smb2_request **requests;
    union smb_open *ios;
    int i, num_files = 3;
    int num_ok = 0;
    int num_collision = 0;

    torture_comment(tctx,
                    "Testing SMB2 Open with multiple connections\n");
    trees = talloc_array(tctx, struct smb2_tree *, num_files);
    requests = talloc_array(tctx, struct smb2_request *, num_files);
    ios = talloc_array(tctx, union smb_open, num_files);
    if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
            (ios == NULL)) {
        torture_comment(tctx, ("talloc failed\n"));
        ret = false;
        goto done;
    }

    tree->session->transport->options.request_timeout = 60;

    for (i=0; i<num_files; i++) {
        if (!torture_smb2_connection(tctx, &(trees[i]))) {
            torture_comment(tctx,
                            "Could not open %d'th connection\n", i);
            ret = false;
            goto done;
        }
        trees[i]->session->transport->options.request_timeout = 60;
    }

    /* cleanup */
    smb2_util_unlink(tree, fname);

    /*
      base ntcreatex parms
    */
    ZERO_STRUCT(io.smb2);
    io.generic.level = RAW_OPEN_SMB2;
    io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
    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|
                              NTCREATEX_SHARE_ACCESS_DELETE;
    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;
    io.smb2.in.create_flags = 0;

    for (i=0; i<num_files; i++) {
        ios[i] = io;
        requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
        if (requests[i] == NULL) {
            torture_comment(tctx,
                            "could not send %d'th request\n", i);
            ret = false;
            goto done;
        }
    }

    torture_comment(tctx, "waiting for replies\n");
    while (1) {
        bool unreplied = false;
        for (i=0; i<num_files; i++) {
            if (requests[i] == NULL) {
                continue;
            }
            if (requests[i]->state < SMB2_REQUEST_DONE) {
                unreplied = true;
                break;
            }
            status = smb2_create_recv(requests[i], tctx,
                                      &(ios[i].smb2));

            torture_comment(tctx,
                            "File %d returned status %s\n", i,
                            nt_errstr(status));

            if (NT_STATUS_IS_OK(status)) {
                num_ok += 1;
            }

            if (NT_STATUS_EQUAL(status,
                                NT_STATUS_OBJECT_NAME_COLLISION)) {
                num_collision += 1;
            }

            requests[i] = NULL;
        }
        if (!unreplied) {
            break;
        }

        if (event_loop_once(tctx->ev) != 0) {
            torture_comment(tctx, "event_loop_once failed\n");
            ret = false;
            goto done;
        }
    }

    if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
        ret = false;
    }
done:
    smb2_deltree(tree, fname);

    return ret;
}
Exemplo n.º 9
0
/* 
   basic testing of SMB2 connection calls
*/
BOOL torture_smb2_connect(struct torture_context *torture)
{
	TALLOC_CTX *mem_ctx = talloc_new(NULL);
	struct smb2_tree *tree;
	struct smb2_handle h1, h2;
	NTSTATUS status;

	if (!torture_smb2_connection(mem_ctx, &tree)) {
		return False;
	}

	h1 = torture_smb2_create(tree, "test9.dat");
	h2 = torture_smb2_create(tree, "test9.dat");
	status = torture_smb2_write(tree, h1);
	if (!NT_STATUS_IS_OK(status)) {
		printf("Write failed - %s\n", nt_errstr(status));
		return False;
	}
	status = torture_smb2_close(tree, h1);
	if (!NT_STATUS_IS_OK(status)) {
		printf("Close failed - %s\n", nt_errstr(status));
		return False;
	}
	status = torture_smb2_close(tree, h2);
	if (!NT_STATUS_IS_OK(status)) {
		printf("Close failed - %s\n", nt_errstr(status));
		return False;
	}

	status = smb2_util_close(tree, h1);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) {
		printf("close should have closed the handle - %s\n", nt_errstr(status));
		return False;
	}

	status = smb2_tdis(tree);
	if (!NT_STATUS_IS_OK(status)) {
		printf("tdis failed - %s\n", nt_errstr(status));
		return False;
	}

	status = smb2_tdis(tree);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
		printf("tdis should have disabled session - %s\n", nt_errstr(status));
		return False;
	}

 	status = smb2_logoff(tree->session);
	if (!NT_STATUS_IS_OK(status)) {
		printf("Logoff failed - %s\n", nt_errstr(status));
		return False;
	}

	status = smb2_logoff(tree->session);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
		printf("Logoff should have disabled session - %s\n", nt_errstr(status));
		return False;
	}

	status = smb2_keepalive(tree->session->transport);
	if (!NT_STATUS_IS_OK(status)) {
		printf("keepalive failed? - %s\n", nt_errstr(status));
		return False;
	}

	talloc_free(mem_ctx);

	return True;
}
Exemplo n.º 10
0
/* basic testing of all SMB2 setinfo calls 
   for each call we test that it succeeds, and where possible test 
   for consistency between the calls. 
*/
BOOL torture_smb2_setinfo(struct torture_context *torture)
{
	struct smb2_tree *tree;
	BOOL ret = True;
	TALLOC_CTX *mem_ctx = talloc_new(NULL);
	struct smb2_handle handle;
	char *fname;
	char *fname_new;
	union smb_fileinfo finfo2;
	union smb_setfileinfo sfinfo;
	struct security_ace ace;
	struct security_descriptor *sd;
	struct dom_sid *test_sid;
	NTSTATUS status, status2=NT_STATUS_OK;
	const char *call_name;
	time_t basetime = (time(NULL) - 86400) & ~1;
	int n = time(NULL) % 100;
	
	ZERO_STRUCT(handle);
	
	fname = talloc_asprintf(mem_ctx, BASEDIR "fnum_test_%d.txt", n);
	fname_new = talloc_asprintf(mem_ctx, BASEDIR "fnum_test_new_%d.txt", n);

	if (!torture_smb2_connection(mem_ctx, &tree)) {
		return False;
	}

#define RECREATE_FILE(fname) do { \
	smb2_util_close(tree, handle); \
	status = smb2_create_complex_file(tree, fname, &handle); \
	if (!NT_STATUS_IS_OK(status)) { \
		printf("(%s) ERROR: open of %s failed (%s)\n", \
		       __location__, fname, nt_errstr(status)); \
		ret = False; \
		goto done; \
	}} while (0)

#define RECREATE_BOTH do { \
		RECREATE_FILE(fname); \
	} while (0)

	RECREATE_BOTH;
	
#define CHECK_CALL(call, rightstatus) do { \
	call_name = #call; \
	sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
	sfinfo.generic.in.file.handle = handle; \
	status = smb2_setinfo_file(tree, &sfinfo); \
	if (!NT_STATUS_EQUAL(status, rightstatus)) { \
		printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
			nt_errstr(status), nt_errstr(rightstatus)); \
		ret = False; \
		goto done; \
	} \
	} while (0)

#define CHECK1(call) \
	do { if (NT_STATUS_IS_OK(status)) { \
		finfo2.generic.level = RAW_FILEINFO_ ## call; \
		finfo2.generic.in.file.handle = handle; \
		status2 = smb2_getinfo_file(tree, mem_ctx, &finfo2); \
		if (!NT_STATUS_IS_OK(status2)) { \
			printf("(%s) %s - %s\n", __location__, #call, nt_errstr(status2)); \
		ret = False; \
		goto done; \
		} \
	}} while (0)

#define CHECK_VALUE(call, stype, field, value) do { \
 	CHECK1(call); \
	if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \
		printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
		       call_name, #stype, #field, \
		       (uint_t)value, (uint_t)finfo2.stype.out.field); \
		torture_smb2_all_info(tree, handle); \
		ret = False; \
		goto done; \
	}} while (0)

#define CHECK_TIME(call, stype, field, value) do { \
 	CHECK1(call); \
	if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \
		printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
		        call_name, #stype, #field, \
		        (uint_t)value, \
			(uint_t)nt_time_to_unix(finfo2.stype.out.field)); \
		printf("\t%s", timestring(mem_ctx, value)); \
		printf("\t%s\n", nt_time_string(mem_ctx, finfo2.stype.out.field)); \
		torture_smb2_all_info(tree, handle); \
		ret = False; \
		goto done; \
	}} while (0)

#define CHECK_STATUS(status, correct) do { \
	if (!NT_STATUS_EQUAL(status, correct)) { \
		printf("(%s) Incorrect status %s - should be %s\n", \
		       __location__, nt_errstr(status), nt_errstr(correct)); \
		ret = False; \
		goto done; \
	}} while (0)

	torture_smb2_all_info(tree, handle);
	
	printf("test basic_information level\n");
	basetime += 86400;
	unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
	unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
	unix_to_nt_time(&sfinfo.basic_info.in.write_time,  basetime + 300);
	unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time,  basetime + 300);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib,     FILE_ATTRIBUTE_READONLY);

	printf("a zero time means don't change\n");
	unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
	unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
	unix_to_nt_time(&sfinfo.basic_info.in.write_time,  0);
	unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time,  basetime + 300);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib,     FILE_ATTRIBUTE_NORMAL);

	printf("change the attribute\n");
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN);

	printf("zero attrib means don't change\n");
	sfinfo.basic_info.in.attrib = 0;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN);

	printf("restore attribute\n");
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL);

	printf("test disposition_information level\n");
	sfinfo.disposition_info.in.delete_on_close = 1;
	CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 1);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 0);

	sfinfo.disposition_info.in.delete_on_close = 0;
	CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 0);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 1);

	printf("test allocation_information level\n");
	sfinfo.allocation_info.in.alloc_size = 0;
	CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 0);

	sfinfo.allocation_info.in.alloc_size = 4096;
	CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 4096);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0);

	printf("test end_of_file_info level\n");
	sfinfo.end_of_file_info.in.size = 37;
	CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 37);

	sfinfo.end_of_file_info.in.size = 7;
	CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 7);

	printf("test position_information level\n");
	sfinfo.position_information.in.position = 123456;
	CHECK_CALL(POSITION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, position, 123456);

	printf("test mode_information level\n");
	sfinfo.mode_information.in.mode = 2;
	CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, mode, 2);

	sfinfo.mode_information.in.mode = 1;
	CHECK_CALL(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);

	sfinfo.mode_information.in.mode = 0;
	CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);

	printf("test sec_desc level\n");
	ZERO_STRUCT(finfo2);
	finfo2.query_secdesc.in.secinfo_flags =
		SECINFO_OWNER |
		SECINFO_GROUP |
		SECINFO_DACL;
 	CHECK1(SEC_DESC);
	sd = finfo2.query_secdesc.out.sd;

	test_sid = dom_sid_parse_talloc(mem_ctx, "S-1-5-32-1234-5432");
	ZERO_STRUCT(ace);
	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);

	printf("add a new ACE to the DACL\n");

	sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags;
	sfinfo.set_secdesc.in.sd = sd;
	CHECK_CALL(SEC_DESC, NT_STATUS_OK);
 	CHECK1(SEC_DESC);

	if (!security_acl_equal(finfo2.query_secdesc.out.sd->dacl, sd->dacl)) {
		printf("%s: security descriptors don't match!\n", __location__);
		printf("got:\n");
		NDR_PRINT_DEBUG(security_descriptor, finfo2.query_secdesc.out.sd);
		printf("expected:\n");
		NDR_PRINT_DEBUG(security_descriptor, sd);
		ret = False;
	}

	printf("remove it again\n");

	status = security_descriptor_dacl_del(sd, test_sid);
	CHECK_STATUS(status, NT_STATUS_OK);

	sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags;
	sfinfo.set_secdesc.in.sd = sd;
	CHECK_CALL(SEC_DESC, NT_STATUS_OK);
 	CHECK1(SEC_DESC);

	if (!security_acl_equal(finfo2.query_secdesc.out.sd->dacl, sd->dacl)) {
		printf("%s: security descriptors don't match!\n", __location__);
		printf("got:\n");
		NDR_PRINT_DEBUG(security_descriptor, finfo2.query_secdesc.out.sd);
		printf("expected:\n");
		NDR_PRINT_DEBUG(security_descriptor, sd);
		ret = False;
	}

done:
	status = smb2_util_close(tree, handle);
	if (NT_STATUS_IS_ERR(status)) {
		printf("Failed to delete %s - %s\n", fname, nt_errstr(status));
	}
	smb2_util_unlink(tree, fname);

	talloc_free(mem_ctx);
	return ret;
}
Exemplo n.º 11
0
/*
  test writing
*/
static NTSTATUS torture_smb2_write(TALLOC_CTX *mem_ctx, 
				   struct smb2_tree *tree, 
				   struct smb2_handle handle)
{
	struct smb2_write w;
	struct smb2_read r;
	NTSTATUS status;
	int i, len;
	int max = 80000000;
	int min = 1;

	while (max > min) {
		TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);


		len = 1+(min+max)/2;

		ZERO_STRUCT(w);
		w.in.file.handle = handle;
		w.in.offset      = 0;
		w.in.data        = data_blob_talloc(tmp_ctx, NULL, len);

		for (i=0;i<len;i++) {
			w.in.data.data[i] = i % 256;
		}

		printf("trying to write %d bytes (min=%d max=%d)\n", 
		       len, min, max);

		status = smb2_write(tree, &w);
		if (!NT_STATUS_IS_OK(status)) {
			printf("write failed - %s\n", nt_errstr(status));
			max = len-1;
			status = smb2_util_close(tree, handle);
			if (!NT_STATUS_IS_OK(status)) {
				/* vista bug */
				printf("coping with server disconnect\n");
				talloc_free(tree);
				if (!torture_smb2_connection(mem_ctx, &tree)) {
					printf("failed to reconnect\n");
					return NT_STATUS_NET_WRITE_FAULT;
				}
			}
			handle = torture_smb2_create(tree, FNAME);
			continue;
		} else {
			min = len;
		}

		
		ZERO_STRUCT(r);
		r.in.file.handle = handle;
		r.in.length      = len;
		r.in.offset      = 0;
		
		printf("reading %d bytes\n", len);

		status = smb2_read(tree, tmp_ctx, &r);
		if (!NT_STATUS_IS_OK(status)) {
			printf("read failed - %s\n", nt_errstr(status));
		} else if (w.in.data.length != r.out.data.length ||
		    memcmp(w.in.data.data, r.out.data.data, len) != 0) {
			printf("read data mismatch\n");
		}

		talloc_free(tmp_ctx);
	}

	printf("converged: len=%d\n", max);
	smb2_util_close(tree, handle);
	smb2_util_unlink(tree, FNAME);

	return NT_STATUS_OK;
}
Exemplo n.º 12
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;
}
Exemplo n.º 13
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;
}
Exemplo n.º 14
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;
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
0
/* basic testing of all SMB2 setinfo calls 
   for each call we test that it succeeds, and where possible test 
   for consistency between the calls. 
*/
bool torture_smb2_setinfo(struct torture_context *tctx)
{
	struct smb2_tree *tree;
	bool ret = true;
	struct smb2_handle handle;
	char *fname;
	union smb_fileinfo finfo2;
	union smb_setfileinfo sfinfo;
	struct security_ace ace;
	struct security_descriptor *sd;
	struct dom_sid *test_sid;
	NTSTATUS status, status2=NT_STATUS_OK;
	const char *call_name;
	time_t basetime = (time(NULL) - 86400) & ~1;
	int n = time(NULL) % 100;
	struct ea_struct ea;
	
	ZERO_STRUCT(handle);
	
	fname = talloc_asprintf(tctx, BASEDIR "fnum_test_%d.txt", n);

	if (!torture_smb2_connection(tctx, &tree)) {
		return false;
	}

#define RECREATE_FILE(fname) do { \
	smb2_util_close(tree, handle); \
	status = smb2_create_complex_file(tree, fname, &handle); \
	if (!NT_STATUS_IS_OK(status)) { \
		torture_result(tctx, TORTURE_FAIL, "(%s) ERROR: open of %s failed (%s)\n", \
		       __location__, fname, nt_errstr(status)); \
		ret = false; \
		goto done; \
	}} while (0)

#define RECREATE_BOTH do { \
		RECREATE_FILE(fname); \
	} while (0)

	RECREATE_BOTH;
	
#define CHECK_CALL(call, rightstatus) do { \
	call_name = #call; \
	sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
	sfinfo.generic.in.file.handle = handle; \
	status = smb2_setinfo_file(tree, &sfinfo); \
	if (!NT_STATUS_EQUAL(status, rightstatus)) { \
		torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s (should be %s)\n", __location__, #call, \
			nt_errstr(status), nt_errstr(rightstatus)); \
		ret = false; \
		goto done; \
	} \
	} while (0)

#define CHECK1(call) \
	do { if (NT_STATUS_IS_OK(status)) { \
		finfo2.generic.level = RAW_FILEINFO_ ## call; \
		finfo2.generic.in.file.handle = handle; \
		status2 = smb2_getinfo_file(tree, tctx, &finfo2); \
		if (!NT_STATUS_IS_OK(status2)) { \
			torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__, #call, nt_errstr(status2)); \
		ret = false; \
		goto done; \
		} \
	}} while (0)

#define CHECK_VALUE(call, stype, field, value) do { \
 	CHECK1(call); \
	if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \
		torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
		       call_name, #stype, #field, \
		       (unsigned int)value, (unsigned int)finfo2.stype.out.field); \
		torture_smb2_all_info(tree, handle); \
		ret = false; \
		goto done; \
	}} while (0)

#define CHECK_TIME(call, stype, field, value) do { \
 	CHECK1(call); \
	if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \
		torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
		        call_name, #stype, #field, \
		        (unsigned int)value, \
			(unsigned int)nt_time_to_unix(finfo2.stype.out.field)); \
		torture_warning(tctx, "\t%s", timestring(tctx, value)); \
		torture_warning(tctx, "\t%s\n", nt_time_string(tctx, finfo2.stype.out.field)); \
		torture_smb2_all_info(tree, handle); \
		ret = false; \
		goto done; \
	}} while (0)

#define CHECK_STATUS(status, correct) do { \
	if (!NT_STATUS_EQUAL(status, correct)) { \
		torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \
		       __location__, nt_errstr(status), nt_errstr(correct)); \
		ret = false; \
		goto done; \
	}} while (0)

	torture_smb2_all_info(tree, handle);
	
	torture_comment(tctx, "Test basic_information level\n");
	basetime += 86400;
	unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
	unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
	unix_to_nt_time(&sfinfo.basic_info.in.write_time,  basetime + 300);
	unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time,  basetime + 300);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib,     FILE_ATTRIBUTE_READONLY);

	torture_comment(tctx, "a zero time means don't change\n");
	unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
	unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
	unix_to_nt_time(&sfinfo.basic_info.in.write_time,  0);
	unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time,  basetime + 300);
	CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib,     FILE_ATTRIBUTE_NORMAL);

	torture_comment(tctx, "change the attribute\n");
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN);

	torture_comment(tctx, "zero attrib means don't change\n");
	sfinfo.basic_info.in.attrib = 0;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN);

	torture_comment(tctx, "can't change a file to a directory\n");
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_INVALID_PARAMETER);

	torture_comment(tctx, "restore attribute\n");
	sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
	CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL);

	torture_comment(tctx, "Test disposition_information level\n");
	sfinfo.disposition_info.in.delete_on_close = 1;
	CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 1);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 0);

	sfinfo.disposition_info.in.delete_on_close = 0;
	CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 0);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 1);

	torture_comment(tctx, "Test allocation_information level\n");
	sfinfo.allocation_info.in.alloc_size = 0;
	CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 0);

	sfinfo.allocation_info.in.alloc_size = 4096;
	CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 4096);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0);

	torture_comment(tctx, "Test end_of_file_info level\n");
	sfinfo.end_of_file_info.in.size = 37;
	CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 37);

	sfinfo.end_of_file_info.in.size = 7;
	CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 7);

	torture_comment(tctx, "Test position_information level\n");
	sfinfo.position_information.in.position = 123456;
	CHECK_CALL(POSITION_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, position, 123456);

	torture_comment(tctx, "Test mode_information level\n");
	sfinfo.mode_information.in.mode = 2;
	CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2);
	CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, mode, 2);

	sfinfo.mode_information.in.mode = 1;
	CHECK_CALL(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);

	sfinfo.mode_information.in.mode = 0;
	CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK);
	CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);

	torture_comment(tctx, "Test sec_desc level\n");
	ZERO_STRUCT(finfo2);
	finfo2.query_secdesc.in.secinfo_flags =
		SECINFO_OWNER |
		SECINFO_GROUP |
		SECINFO_DACL;
 	CHECK1(SEC_DESC);
	sd = finfo2.query_secdesc.out.sd;

	test_sid = dom_sid_parse_talloc(tctx, SID_NT_AUTHENTICATED_USERS);
	ZERO_STRUCT(ace);
	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, "add a new ACE to the DACL\n");

	sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags;
	sfinfo.set_secdesc.in.sd = sd;
	CHECK_CALL(SEC_DESC, NT_STATUS_OK);
	FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, handle, sd));

	torture_comment(tctx, "remove it again\n");

	status = security_descriptor_dacl_del(sd, test_sid);
	CHECK_STATUS(status, NT_STATUS_OK);

	sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags;
	sfinfo.set_secdesc.in.sd = sd;
	CHECK_CALL(SEC_DESC, NT_STATUS_OK);
	FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, handle, sd));

	torture_comment(tctx, "Check zero length EA's behavior\n");

	/* Set a new EA. */
	sfinfo.full_ea_information.in.eas.num_eas = 1;
	ea.flags = 0;
	ea.name.private_length = 6;
	ea.name.s = "NewEA";
	ea.value = data_blob_string_const("testme");
	sfinfo.full_ea_information.in.eas.eas = &ea;
	CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK);

	/* Does it still exist ? */
	finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
	finfo2.generic.in.file.handle = handle;
	finfo2.all_eas.in.continue_flags = 1;
	status2 = smb2_getinfo_file(tree, tctx, &finfo2);
	if (!NT_STATUS_IS_OK(status2)) {
		torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__,
			"SMB2_ALL_EAS", nt_errstr(status2));
		ret = false;
		goto done;
	}

	/* Note on Windows EA name is returned capitalized. */
	if (!find_returned_ea(&finfo2, "NewEA", "testme")) {
		torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'NewEA'\n", __location__);
		ret = false;
	}

	/* Now zero it out (should delete it) */
	sfinfo.full_ea_information.in.eas.num_eas = 1;
	ea.flags = 0;
	ea.name.private_length = 6;
	ea.name.s = "NewEA";
	ea.value = data_blob_null;
	sfinfo.full_ea_information.in.eas.eas = &ea;
	CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK);

	/* Does it still exist ? */
	finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
	finfo2.generic.in.file.handle = handle;
	finfo2.all_eas.in.continue_flags = 1;
	status2 = smb2_getinfo_file(tree, tctx, &finfo2);
	if (!NT_STATUS_IS_OK(status2)) {
		torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__,
			"SMB2_ALL_EAS", nt_errstr(status2));
		ret = false;
		goto done;
	}

	if (find_returned_ea(&finfo2, "NewEA", NULL)) {
		torture_result(tctx, TORTURE_FAIL, "(%s) EA 'NewEA' should be deleted\n", __location__);
		ret = false;
	}

	/* Set a zero length EA. */
	sfinfo.full_ea_information.in.eas.num_eas = 1;
	ea.flags = 0;
	ea.name.private_length = 6;
	ea.name.s = "ZeroEA";
	ea.value = data_blob_null;
	sfinfo.full_ea_information.in.eas.eas = &ea;
	CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK);

	/* Does it still exist ? */
	finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
	finfo2.generic.in.file.handle = handle;
	finfo2.all_eas.in.continue_flags = 1;
	status2 = smb2_getinfo_file(tree, tctx, &finfo2);
	if (!NT_STATUS_IS_OK(status2)) {
		torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__,
			"SMB2_ALL_EAS", nt_errstr(status2));
		ret = false;
		goto done;
	}

	/* Over SMB2 ZeroEA should not exist. */
	if (!find_returned_ea(&finfo2, "EAONE", "VALUE1")) {
		torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'EAONE'\n", __location__);
		ret = false;
	}
	if (!find_returned_ea(&finfo2, "SECONDEA", "ValueTwo")) {
		torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'SECONDEA'\n", __location__);
		ret = false;
	}
	if (find_returned_ea(&finfo2, "ZeroEA", NULL)) {
		torture_result(tctx, TORTURE_FAIL, "(%s) Found null EA 'ZeroEA'\n", __location__);
		ret = false;
	}

done:
	status = smb2_util_close(tree, handle);
	if (NT_STATUS_IS_ERR(status)) {
		torture_warning(tctx, "Failed to delete %s - %s\n", fname, nt_errstr(status));
	}
	smb2_util_unlink(tree, fname);

	return ret;
}