/* test fileinfo levels */ static bool torture_smb2_fileinfo(struct torture_context *tctx, struct smb2_tree *tree) { struct smb2_handle hfile, hdir; NTSTATUS status; int i; status = torture_smb2_testfile(tree, FNAME, &hfile); if (!NT_STATUS_IS_OK(status)) { printf(__location__ " Unable to create test file '%s' - %s\n", FNAME, nt_errstr(status)); goto failed; } status = torture_smb2_testdir(tree, DNAME, &hdir); if (!NT_STATUS_IS_OK(status)) { printf(__location__ " Unable to create test directory '%s' - %s\n", DNAME, nt_errstr(status)); goto failed; } printf("Testing file info levels\n"); torture_smb2_all_info(tree, hfile); torture_smb2_all_info(tree, hdir); for (i=0;i<ARRAY_SIZE(file_levels);i++) { if (file_levels[i].level == RAW_FILEINFO_SEC_DESC) { file_levels[i].finfo.query_secdesc.in.secinfo_flags = 0x7; file_levels[i].dinfo.query_secdesc.in.secinfo_flags = 0x7; } if (file_levels[i].level == RAW_FILEINFO_SMB2_ALL_EAS) { file_levels[i].finfo.all_eas.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART; file_levels[i].dinfo.all_eas.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART; } file_levels[i].finfo.generic.level = file_levels[i].level; file_levels[i].finfo.generic.in.file.handle = hfile; file_levels[i].fstatus = smb2_getinfo_file(tree, tree, &file_levels[i].finfo); if (!NT_STATUS_IS_OK(file_levels[i].fstatus)) { printf("(%s) %s failed on file - %s\n", __location__, file_levels[i].name, nt_errstr(file_levels[i].fstatus)); goto failed; } file_levels[i].dinfo.generic.level = file_levels[i].level; file_levels[i].dinfo.generic.in.file.handle = hdir; file_levels[i].dstatus = smb2_getinfo_file(tree, tree, &file_levels[i].dinfo); if (!NT_STATUS_IS_OK(file_levels[i].dstatus)) { printf("(%s) %s failed on dir - %s\n", __location__, file_levels[i].name, nt_errstr(file_levels[i].dstatus)); goto failed; } } return true; failed: return false; }
static bool test_read_dir(struct torture_context *torture, struct smb2_tree *tree) { bool ret = true; NTSTATUS status; struct smb2_handle h; struct smb2_read rd; TALLOC_CTX *tmp_ctx = talloc_new(tree); status = torture_smb2_testdir(tree, DNAME, &h); if (!NT_STATUS_IS_OK(status)) { printf(__location__ " Unable to create test directory '%s' - %s\n", DNAME, nt_errstr(status)); return false; } ZERO_STRUCT(rd); rd.in.file.handle = h; rd.in.length = 10; rd.in.offset = 0; rd.in.min_count = 1; status = smb2_read(tree, tmp_ctx, &rd); CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST); rd.in.min_count = 11; status = smb2_read(tree, tmp_ctx, &rd); CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST); rd.in.length = 0; rd.in.min_count = 2592; status = smb2_read(tree, tmp_ctx, &rd); if (torture_setting_bool(torture, "windows", false)) { CHECK_STATUS(status, NT_STATUS_END_OF_FILE); } else { CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST); } rd.in.length = 0; rd.in.min_count = 0; rd.in.channel = 0; status = smb2_read(tree, tmp_ctx, &rd); if (torture_setting_bool(torture, "windows", false)) { CHECK_STATUS(status, NT_STATUS_OK); } else { CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST); } done: talloc_free(tmp_ctx); return ret; }
static bool test_default_acl_posix(struct torture_context *tctx, struct smb2_tree *tree_unused) { struct smb2_tree *tree = NULL; NTSTATUS status; bool ok; bool ret = true; const char *dname = BASEDIR "\\testdir"; const char *fname = BASEDIR "\\testdir\\testfile"; struct smb2_handle fhandle = {{0}}; struct smb2_handle dhandle = {{0}}; union smb_fileinfo q; union smb_setfileinfo set; struct security_descriptor *sd = NULL; struct security_descriptor *exp_sd = NULL; char *owner_sid = NULL; char *group_sid = NULL; ok = torture_smb2_con_share(tctx, "acl_xattr_ign_sysacl_posix", &tree); torture_assert_goto(tctx, ok == true, ret, done, "Unable to connect to 'acl_xattr_ign_sysacl_posix'\n"); ok = smb2_util_setup_dir(tctx, tree, BASEDIR); torture_assert_goto(tctx, ok == true, ret, done, "Unable to setup testdir\n"); ZERO_STRUCT(dhandle); status = torture_smb2_testdir(tree, dname, &dhandle); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n"); torture_comment(tctx, "Get the original sd\n"); ZERO_STRUCT(q); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = dhandle; q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP; status = smb2_getinfo_file(tree, tctx, &q); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n"); sd = q.query_secdesc.out.sd; owner_sid = dom_sid_string(tctx, sd->owner_sid); group_sid = dom_sid_string(tctx, sd->group_sid); torture_comment(tctx, "owner [%s] group [%s]\n", owner_sid, group_sid); torture_comment(tctx, "Set ACL with no inheritable ACE\n"); sd = security_descriptor_dacl_create(tctx, 0, NULL, NULL, owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_DIR_ALL, 0, NULL); ZERO_STRUCT(set); set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; set.set_secdesc.in.file.handle = dhandle; set.set_secdesc.in.secinfo_flags = SECINFO_DACL; set.set_secdesc.in.sd = sd; status = smb2_setinfo_file(tree, &set); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file\n"); TALLOC_FREE(sd); smb2_util_close(tree, dhandle); torture_comment(tctx, "Create file\n"); ZERO_STRUCT(fhandle); status = torture_smb2_testfile(tree, fname, &fhandle); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_complex_file\n"); torture_comment(tctx, "Query file SD\n"); ZERO_STRUCT(q); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = fhandle; q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP; status = smb2_getinfo_file(tree, tctx, &q); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n"); sd = q.query_secdesc.out.sd; smb2_util_close(tree, fhandle); ZERO_STRUCT(fhandle); torture_comment(tctx, "Checking actual file SD against expected SD\n"); exp_sd = security_descriptor_dacl_create( tctx, 0, owner_sid, group_sid, owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0, group_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, FILE_GENERIC_READ|FILE_GENERIC_WRITE|FILE_GENERIC_EXECUTE, 0, SID_WORLD, SEC_ACE_TYPE_ACCESS_ALLOWED, FILE_GENERIC_READ|FILE_GENERIC_WRITE|FILE_GENERIC_EXECUTE, 0, SID_NT_SYSTEM, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0, NULL); CHECK_SECURITY_DESCRIPTOR(sd, exp_sd); done: if (!smb2_util_handle_empty(fhandle)) { smb2_util_close(tree, fhandle); } if (!smb2_util_handle_empty(dhandle)) { smb2_util_close(tree, dhandle); } if (tree != NULL) { smb2_deltree(tree, BASEDIR); smb2_tdis(tree); } return ret; }
/** * test renaming after reauth. * compare security descriptors before and after rename/reauth */ bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char dname[256]; char fname[256]; char fname2[256]; struct smb2_handle _dh1; struct smb2_handle *dh1 = NULL; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; bool ok; union smb_fileinfo qfinfo; union smb_setfileinfo sfinfo; struct cli_credentials *anon_creds = NULL; uint32_t secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_PROTECTED_DACL | SECINFO_UNPROTECTED_DACL; struct security_descriptor *f_sd1; struct security_descriptor *d_sd1 = NULL; struct security_ace ace; struct dom_sid *extra_sid; /* Add some random component to the file name. */ snprintf(dname, 256, "session_reauth5_%s.d", generate_random_str(tctx, 8)); snprintf(fname, 256, "%s\\file.dat", dname); ok = smb2_util_setup_dir(tctx, tree, dname); CHECK_VAL(ok, true); status = torture_smb2_testdir(tree, dname, &_dh1); CHECK_STATUS(status, NT_STATUS_OK); dh1 = &_dh1; smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, 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")); /* get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); f_sd1 = qfinfo.query_secdesc.out.sd; /* re-authenticate as anonymous */ anon_creds = cli_credentials_init_anon(mem_ctx); torture_assert(tctx, (anon_creds != NULL), "talloc error"); status = smb2_session_setup_spnego(tree->session, anon_creds, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_OK); /* try to rename the file: fails */ snprintf(fname2, 256, "%s\\file2.dat", dname); smb2_util_unlink(tree, fname2); ZERO_STRUCT(sfinfo); sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; sfinfo.rename_information.in.file.handle = _h1; sfinfo.rename_information.in.overwrite = true; sfinfo.rename_information.in.new_name = fname2; status = smb2_setinfo_file(tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); /* re-authenticate as original user again */ status = smb2_session_setup_spnego(tree->session, cmdline_credentials, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_OK); /* give full access on the file to anonymous */ extra_sid = dom_sid_parse_talloc(tctx, SID_NT_ANONYMOUS); ZERO_STRUCT(ace); ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.access_mask = SEC_RIGHTS_FILE_ALL; ace.trustee = *extra_sid; status = security_descriptor_dacl_add(f_sd1, &ace); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(sfinfo); sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; sfinfo.set_secdesc.in.file.handle = _h1; sfinfo.set_secdesc.in.secinfo_flags = secinfo_flags; sfinfo.set_secdesc.in.sd = f_sd1; status = smb2_setinfo_file(tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); /* re-get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); /* re-authenticate as anonymous - again */ anon_creds = cli_credentials_init_anon(mem_ctx); torture_assert(tctx, (anon_creds != NULL), "talloc error"); status = smb2_session_setup_spnego(tree->session, anon_creds, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_OK); /* try to rename the file: fails */ ZERO_STRUCT(sfinfo); sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; sfinfo.rename_information.in.file.handle = _h1; sfinfo.rename_information.in.overwrite = true; sfinfo.rename_information.in.new_name = fname2; status = smb2_setinfo_file(tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); /* give full access on the parent dir to anonymous */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _dh1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); d_sd1 = qfinfo.query_secdesc.out.sd; ZERO_STRUCT(ace); ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.access_mask = SEC_RIGHTS_FILE_ALL; ace.trustee = *extra_sid; status = security_descriptor_dacl_add(d_sd1, &ace); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(sfinfo); sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; sfinfo.set_secdesc.in.file.handle = _dh1; sfinfo.set_secdesc.in.secinfo_flags = secinfo_flags; sfinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL; sfinfo.set_secdesc.in.sd = d_sd1; status = smb2_setinfo_file(tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _dh1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); smb2_util_close(tree, _dh1); dh1 = NULL; /* try to rename the file: still fails */ ZERO_STRUCT(sfinfo); sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; sfinfo.rename_information.in.file.handle = _h1; sfinfo.rename_information.in.overwrite = true; sfinfo.rename_information.in.new_name = fname2; status = smb2_setinfo_file(tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); /* re-authenticate as original user - again */ status = smb2_session_setup_spnego(tree->session, cmdline_credentials, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_OK); /* rename the file - for verification that it works */ ZERO_STRUCT(sfinfo); sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; sfinfo.rename_information.in.file.handle = _h1; sfinfo.rename_information.in.overwrite = true; sfinfo.rename_information.in.new_name = fname2; status = smb2_setinfo_file(tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); /* closs the file, check it is gone and reopen under the new name */ smb2_util_close(tree, _h1); ZERO_STRUCT(io1); smb2_generic_create_share(&io1, NULL /* lease */, false /* dir */, fname, NTCREATEX_DISP_OPEN, smb2_util_share_access(""), smb2_util_oplock_level("b"), 0 /* leasekey */, 0 /* leasestate */); status = smb2_create(tree, mem_ctx, &io1); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); ZERO_STRUCT(io1); smb2_generic_create_share(&io1, NULL /* lease */, false /* dir */, fname2, NTCREATEX_DISP_OPEN, smb2_util_share_access(""), smb2_util_oplock_level("b"), 0 /* leasekey */, 0 /* leasestate */); status = smb2_create(tree, mem_ctx, &io1); CHECK_STATUS(status, NT_STATUS_OK); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b")); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; qfinfo.query_secdesc.in.file.handle = _h1; qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); done: if (dh1 != NULL) { smb2_util_close(tree, *dh1); } if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_deltree(tree, dname); talloc_free(tree); talloc_free(mem_ctx); return ret; }
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; }
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; }
/* 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; }
/* basic testing of all File Information Classes using a single file */ static bool test_one_file(struct torture_context *tctx, struct smb2_tree *tree) { TALLOC_CTX *mem_ctx = talloc_new(tctx); bool ret = true; const char *fname = "torture_search.txt"; NTSTATUS status; int i; unsigned int count; union smb_fileinfo all_info2, alt_info, internal_info; union smb_search_data *s; union smb_search_data d; struct smb2_handle h, h2; status = torture_smb2_testdir(tree, DNAME, &h); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ""); status = smb2_create_complex_file(tree, DNAME "\\torture_search.txt", &h2); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ""); /* call all the File Information Classes */ for (i=0;i<ARRAY_SIZE(levels);i++) { torture_comment(tctx, "testing %s %d\n", levels[i].name, levels[i].level); levels[i].status = torture_single_file_search(tree, mem_ctx, fname, levels[i].level, levels[i].data_level, i, &d, &count, &h); torture_assert_ntstatus_ok_goto(tctx, levels[i].status, ret, done, ""); } /* get the all_info file into to check against */ all_info2.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION; all_info2.generic.in.file.handle = h2; status = smb2_getinfo_file(tree, tctx, &all_info2); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "RAW_FILEINFO_ALL_INFO failed"); alt_info.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION; alt_info.generic.in.file.handle = h2; status = smb2_getinfo_file(tree, tctx, &alt_info); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "RAW_FILEINFO_ALT_NAME_INFO failed"); internal_info.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION; internal_info.generic.in.file.handle = h2; status = smb2_getinfo_file(tree, tctx, &internal_info); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "RAW_FILEINFO_INTERNAL_INFORMATION " "failed"); #define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if ((s->sname1.field1) != (v.sname2.out.field2)) { \ torture_result(tctx, TORTURE_FAIL, \ "(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \ __location__, \ #sname1, #field1, (int)s->sname1.field1, \ #sname2, #field2, (int)v.sname2.out.field2); \ ret = false; \ } \ }} while (0) #define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (s->sname1.field1 != \ (~1 & nt_time_to_unix(v.sname2.out.field2))) { \ torture_result(tctx, TORTURE_FAIL, \ "(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, \ timestring(tctx, s->sname1.field1), \ #sname2, #field2, \ nt_time_string(tctx, v.sname2.out.field2)); \ ret = false; \ } \ }} while (0) #define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (s->sname1.field1 != v.sname2.out.field2) { \ torture_result(tctx, TORTURE_FAIL, \ "(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, \ nt_time_string(tctx, s->sname1.field1), \ #sname2, #field2, \ nt_time_string(tctx, v.sname2.out.field2)); \ ret = false; \ } \ }} while (0) #define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1 || \ strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \ torture_result(tctx, TORTURE_FAIL, \ "(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, s->sname1.field1, \ #sname2, #field2, v.sname2.out.field2.s); \ ret = false; \ } \ }} while (0) #define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1.s || \ strcmp(s->sname1.field1.s, v.sname2.out.field2.s)) { \ torture_result(tctx, TORTURE_FAIL, \ "(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, s->sname1.field1.s, \ #sname2, #field2, v.sname2.out.field2.s); \ ret = false; \ } \ }} while (0) #define CHECK_NAME(name, sname1, field1, fname, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1.s || \ strcmp(s->sname1.field1.s, fname)) { \ torture_result(tctx, TORTURE_FAIL, \ "(%s) %s/%s [%s] != %s\n", \ __location__, \ #sname1, #field1, s->sname1.field1.s, fname); \ ret = false; \ } \ }} while (0) #define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1 || \ strcmp(s->sname1.field1, fname)) { \ torture_result(tctx, TORTURE_FAIL, \ "(%s) %s/%s [%s] != %s\n", \ __location__, \ #sname1, #field1, s->sname1.field1, fname); \ ret = false; \ } \ }} while (0) /* check that all the results are as expected */ CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info, attrib, all_info2, all_info2, attrib); CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, attrib, all_info2, all_info2, attrib); CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, attrib, all_info2, all_info2, attrib); CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, attrib, all_info2, all_info2, attrib); CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, attrib, all_info2, all_info2, attrib); CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info, write_time, all_info2, all_info2, write_time); CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, write_time, all_info2, all_info2, write_time); CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, write_time, all_info2, all_info2, write_time); CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, write_time, all_info2, all_info2, write_time); CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, write_time, all_info2, all_info2, write_time); CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info, create_time, all_info2, all_info2, create_time); CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, create_time, all_info2, all_info2, create_time); CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, create_time, all_info2, all_info2, create_time); CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, create_time, all_info2, all_info2, create_time); CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, create_time, all_info2, all_info2, create_time); CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info, access_time, all_info2, all_info2, access_time); CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, access_time, all_info2, all_info2, access_time); CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, access_time, all_info2, all_info2, access_time); CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, access_time, all_info2, all_info2, access_time); CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, access_time, all_info2, all_info2, access_time); CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info, change_time, all_info2, all_info2, change_time); CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, change_time, all_info2, all_info2, change_time); CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, change_time, all_info2, all_info2, change_time); CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, change_time, all_info2, all_info2, change_time); CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, change_time, all_info2, all_info2, change_time); CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info, size, all_info2, all_info2, size); CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, size, all_info2, all_info2, size); CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, size, all_info2, all_info2, size); CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, size, all_info2, all_info2, size); CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, size, all_info2, all_info2, size); CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info, alloc_size, all_info2, all_info2, alloc_size); CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, alloc_size, all_info2, all_info2, alloc_size); CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, alloc_size, all_info2, all_info2, alloc_size); CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, alloc_size, all_info2, all_info2, alloc_size); CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, alloc_size, all_info2, all_info2, alloc_size); CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, ea_size, all_info2, all_info2, ea_size); CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, ea_size, all_info2, all_info2, ea_size); CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, ea_size, all_info2, all_info2, ea_size); CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, ea_size, all_info2, all_info2, ea_size); CHECK_NAME("SMB2_FIND_DIRECTORY_INFO", directory_info, name, fname, STR_TERMINATE_ASCII); CHECK_NAME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, name, fname, STR_TERMINATE_ASCII); CHECK_NAME("SMB2_FIND_NAME_INFO", name_info, name, fname, STR_TERMINATE_ASCII); CHECK_NAME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, name, fname, STR_TERMINATE_ASCII); CHECK_NAME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, name, fname, STR_TERMINATE_ASCII); CHECK_NAME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, name, fname, STR_TERMINATE_ASCII); CHECK_WSTR("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, short_name, alt_info, alt_name_info, fname, STR_UNICODE); CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, file_id, internal_info, internal_information, file_id); CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, file_id, internal_info, internal_information, file_id); done: smb2_util_close(tree, h); smb2_util_unlink(tree, fname); talloc_free(mem_ctx); return ret; }