/* query info on a open file */ static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fileinfo *io) { struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID_AND_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_fileinfo(p->tree, req, io); } c_req = smb_raw_fileinfo_send(p->tree, io); ASYNC_RECV_TAIL(io, async_qfileinfo); }
static bool query_file_path_info2(void *mem_ctx, struct torture_context *torture, struct smbcli_state *cli, int fnum, const char *fname, struct unix_info2 *info2) { NTSTATUS result; union smb_fileinfo finfo; finfo.generic.level = RAW_FILEINFO_UNIX_INFO2; if (fname) { finfo.generic.in.file.path = fname; result = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); } else { finfo.generic.in.file.fnum = fnum; result = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); } torture_assert_ntstatus_equal(torture, result, NT_STATUS_OK, smbcli_errstr(cli->tree)); info2->end_of_file = finfo.unix_info2.out.end_of_file; info2->num_bytes = finfo.unix_info2.out.num_bytes; info2->status_change_time = finfo.unix_info2.out.status_change_time; info2->access_time = finfo.unix_info2.out.access_time; info2->change_time = finfo.unix_info2.out.change_time; info2->uid = finfo.unix_info2.out.uid; info2->gid = finfo.unix_info2.out.gid; info2->file_type = finfo.unix_info2.out.file_type; info2->dev_major = finfo.unix_info2.out.dev_major; info2->dev_minor = finfo.unix_info2.out.dev_minor; info2->unique_id = finfo.unix_info2.out.unique_id; info2->permissions = finfo.unix_info2.out.permissions; info2->nlink = finfo.unix_info2.out.nlink; info2->create_time = finfo.unix_info2.out.create_time; info2->file_flags = finfo.unix_info2.out.file_flags; info2->flags_mask = finfo.unix_info2.out.flags_mask; if (!check_unix_info2(torture, info2)) { return false; } return true; }
/* test seek ops */ static BOOL test_seek(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_seek io; union smb_fileinfo finfo; union smb_setfileinfo sfinfo; NTSTATUS status; BOOL ret = True; int fnum, fnum2; const char *fname = BASEDIR "\\test.txt"; uint8_t c[2]; if (!torture_setup_dir(cli, BASEDIR)) { return False; } fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE); if (fnum == -1) { printf("Failed to open test.txt - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; printf("Trying bad handle\n"); io.lseek.in.file.fnum = fnum+1; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("Trying simple seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = 17; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 17); status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("Trying relative seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = -3; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 14); printf("Trying end seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_END; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, finfo.all_info.out.size); printf("Trying max seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = -1; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 0xffffffff); printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("Trying max overflow\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = 1000; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 999); printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("trying write to update offset\n"); ZERO_STRUCT(c); if (smbcli_write(cli->tree, fnum, 0, c, 0, 2) != 2) { printf("Write failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 2); if (smbcli_read(cli->tree, fnum, c, 0, 1) != 1) { printf("Read failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 1); status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 1); printf("Testing position information\n"); fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE); if (fnum2 == -1) { printf("2nd open failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; sfinfo.position_information.in.file.fnum = fnum2; sfinfo.position_information.in.position = 25; status = smb_raw_setfileinfo(cli->tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum2; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 25); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 1); printf("position_information via paths\n"); sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; sfinfo.position_information.in.file.path = fname; sfinfo.position_information.in.position = 32; status = smb_raw_setpathinfo(cli->tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum2; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 25); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); done: smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* basic testing of all RAW_FILEINFO_* calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ static bool torture_raw_qfileinfo_internals(struct torture_context *torture, TALLOC_CTX *mem_ctx, struct smbcli_tree *tree, int fnum, const char *fname, bool is_ipc) { int i; bool ret = true; int count; union smb_fileinfo *s1, *s2; NTTIME correct_time; uint64_t correct_size; uint32_t correct_attrib; const char *correct_name; bool skip_streams = false; /* scan all the fileinfo and pathinfo levels */ for (i=0; levels[i].name; i++) { if (!levels[i].only_paths) { levels[i].fnum_finfo.generic.level = levels[i].level; levels[i].fnum_finfo.generic.in.file.fnum = fnum; levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx, &levels[i].fnum_finfo); } if (!levels[i].only_handles) { levels[i].fname_finfo.generic.level = levels[i].level; levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname); levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx, &levels[i].fname_finfo); } } /* check for completely broken levels */ for (count=i=0; levels[i].name; i++) { uint32_t cap = tree->session->transport->negotiate.capabilities; /* see if this server claims to support this level */ if ((cap & levels[i].capability_mask) != levels[i].capability_mask) { continue; } if (is_ipc) { if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) { } else if (!levels[i].only_handles && NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_SUPPORTED)) { torture_warning(torture, "fname level %s %s", levels[i].name, nt_errstr(levels[i].fname_status)); continue; } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) { printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n", levels[i].name, nt_errstr(levels[i].fname_status)); count++; } if (!levels[i].only_paths && (NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fnum level %s %s", levels[i].name, nt_errstr(levels[i].fnum_status)); continue; } if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) { printf("ERROR: fnum level %s failed, expected %s - %s\n", levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status), nt_errstr(levels[i].fnum_status)); count++; } } else { if (!levels[i].only_paths && (NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fnum level %s %s", levels[i].name, nt_errstr(levels[i].fnum_status)); continue; } if (!levels[i].only_handles && (NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fname level %s %s", levels[i].name, nt_errstr(levels[i].fname_status)); continue; } if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) { printf("ERROR: fnum level %s failed - %s\n", levels[i].name, nt_errstr(levels[i].fnum_status)); count++; } if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) { printf("ERROR: fname level %s failed - %s\n", levels[i].name, nt_errstr(levels[i].fname_status)); count++; } } } if (count != 0) { ret = false; printf("%d levels failed\n", count); if (count > 35) { torture_fail(torture, "too many level failures - giving up"); } } /* see if we can do streams */ s1 = fnum_find("STREAM_INFO"); if (!s1 || s1->stream_info.out.num_streams == 0) { if (!is_ipc) { printf("STREAM_INFO broken (%d) - skipping streams checks\n", s1 ? s1->stream_info.out.num_streams : -1); } skip_streams = true; } /* this code is incredibly repititive but doesn't lend itself to loops, so we use lots of macros to make it less painful */ /* first off we check the levels that are supposed to be aliases. It will be quite rare for this code to fail, but we need to check it for completeness */ #define ALIAS_CHECK(sname1, sname2) \ do { \ s1 = fnum_find(sname1); s2 = fnum_find(sname2); \ if (s1 && s2) { INFO_CHECK } \ s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2) { INFO_CHECK } \ s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2) { INFO_CHECK } \ } while (0) #define INFO_CHECK \ STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \ STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \ STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \ STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \ VAL_EQUAL (basic_info, attrib, basic_info, attrib); ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \ VAL_EQUAL(standard_info, size, standard_info, size); \ VAL_EQUAL(standard_info, nlink, standard_info, nlink); \ VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \ VAL_EQUAL(standard_info, directory, standard_info, directory); ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(ea_info, ea_size, ea_info, ea_size); ALIAS_CHECK("EA_INFO", "EA_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STR_EQUAL(name_info, fname, name_info, fname); ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STRUCT_EQUAL(all_info, create_time, all_info, create_time); \ STRUCT_EQUAL(all_info, access_time, all_info, access_time); \ STRUCT_EQUAL(all_info, write_time, all_info, write_time); \ STRUCT_EQUAL(all_info, change_time, all_info, change_time); \ VAL_EQUAL(all_info, attrib, all_info, attrib); \ VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \ VAL_EQUAL(all_info, size, all_info, size); \ VAL_EQUAL(all_info, nlink, all_info, nlink); \ VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \ VAL_EQUAL(all_info, directory, all_info, directory); \ VAL_EQUAL(all_info, ea_size, all_info, ea_size); \ STR_EQUAL(all_info, fname, all_info, fname); ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \ VAL_EQUAL(compression_info, format, compression_info, format); \ VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \ VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \ VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift); ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STR_EQUAL(alt_name_info, fname, alt_name_info, fname); ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION"); #define TIME_CHECK_NT(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ nt_time_string(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ nt_time_string(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #define TIME_CHECK_DOS(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #if 0 /* unused */ #define TIME_CHECK_UNX(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #endif /* now check that all the times that are supposed to be equal are correct */ s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.create_time; torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time); TIME_CHECK_DOS("GETATTRE", getattre, create_time); TIME_CHECK_DOS("STANDARD", standard, create_time); TIME_CHECK_DOS("EA_SIZE", ea_size, create_time); TIME_CHECK_NT ("ALL_INFO", all_info, create_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.access_time; torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time); TIME_CHECK_DOS("GETATTRE", getattre, access_time); TIME_CHECK_DOS("STANDARD", standard, access_time); TIME_CHECK_DOS("EA_SIZE", ea_size, access_time); TIME_CHECK_NT ("ALL_INFO", all_info, access_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.write_time; torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time); TIME_CHECK_DOS("GETATTR", getattr, write_time); TIME_CHECK_DOS("GETATTRE", getattre, write_time); TIME_CHECK_DOS("STANDARD", standard, write_time); TIME_CHECK_DOS("EA_SIZE", ea_size, write_time); TIME_CHECK_NT ("ALL_INFO", all_info, write_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.change_time; torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time); TIME_CHECK_NT ("ALL_INFO", all_info, change_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time); #define SIZE_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != correct_size) { \ printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_size); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != correct_size) { \ printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_size); \ ret = false; \ }} while (0) s1 = fnum_find("STANDARD_INFO"); correct_size = s1->standard_info.out.size; torture_comment(torture, "size: %u\n", (unsigned int)correct_size); SIZE_CHECK("GETATTR", getattr, size); SIZE_CHECK("GETATTRE", getattre, size); SIZE_CHECK("STANDARD", standard, size); SIZE_CHECK("EA_SIZE", ea_size, size); SIZE_CHECK("STANDARD_INFO", standard_info, size); SIZE_CHECK("STANDARD_INFORMATION", standard_info, size); SIZE_CHECK("ALL_INFO", all_info, size); SIZE_CHECK("ALL_INFORMATION", all_info, size); SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size); SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size); SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size); if (!skip_streams) { SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size); SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size); } s1 = fnum_find("STANDARD_INFO"); correct_size = s1->standard_info.out.alloc_size; torture_comment(torture, "alloc_size: %u\n", (unsigned int)correct_size); SIZE_CHECK("GETATTRE", getattre, alloc_size); SIZE_CHECK("STANDARD", standard, alloc_size); SIZE_CHECK("EA_SIZE", ea_size, alloc_size); SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size); SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size); SIZE_CHECK("ALL_INFO", all_info, alloc_size); SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size); SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size); if (!skip_streams) { SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size); SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size); } #define ATTRIB_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != correct_attrib) { \ printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_attrib); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != correct_attrib) { \ printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_attrib); \ ret = false; \ }} while (0) s1 = fnum_find("BASIC_INFO"); correct_attrib = s1->basic_info.out.attrib; torture_comment(torture, "attrib: 0x%x\n", (unsigned int)correct_attrib); ATTRIB_CHECK("GETATTR", getattr, attrib); if (!is_ipc) { ATTRIB_CHECK("GETATTRE", getattre, attrib); ATTRIB_CHECK("STANDARD", standard, attrib); ATTRIB_CHECK("EA_SIZE", ea_size, attrib); } ATTRIB_CHECK("BASIC_INFO", basic_info, attrib); ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib); ATTRIB_CHECK("ALL_INFO", all_info, attrib); ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib); ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib); ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib); correct_name = fname; torture_comment(torture, "name: %s\n", correct_name); #define NAME_CHECK(sname, stype, tfield, flags) do { \ s1 = fnum_find(sname); \ if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \ wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \ printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \ s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \ wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \ printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \ s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \ ret = false; \ }} while (0) NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE); NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE); /* the ALL_INFO file name is the full path on the filesystem */ s1 = fnum_find("ALL_INFO"); if (s1 && !s1->all_info.out.fname.s) { torture_fail(torture, "ALL_INFO didn't give a filename"); } if (s1 && s1->all_info.out.fname.s) { char *p = strrchr(s1->all_info.out.fname.s, '\\'); if (!p) { printf("Not a full path in all_info/fname? - '%s'\n", s1->all_info.out.fname.s); ret = false; } else { if (strcmp_safe(correct_name, p) != 0) { printf("incorrect basename in all_info/fname - '%s'\n", s1->all_info.out.fname.s); ret = false; } } if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) { printf("Should not null terminate all_info/fname\n"); ret = false; } } s1 = fnum_find("ALT_NAME_INFO"); if (s1) { correct_name = s1->alt_name_info.out.fname.s; } if (!correct_name) { torture_comment(torture, "no alternate name information\n"); } else { torture_comment(torture, "alt_name: %s\n", correct_name); NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE); NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE); /* and make sure we can open by alternate name */ smbcli_close(tree, fnum); fnum = smbcli_nt_create_full(tree, correct_name, 0, SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_DELETE| NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0); if (fnum == -1) { printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree)); ret = false; } if (!skip_streams) { correct_name = "::$DATA"; torture_comment(torture, "stream_name: %s\n", correct_name); NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE); NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE); } } /* make sure the EAs look right */ s1 = fnum_find("ALL_EAS"); s2 = fnum_find("ALL_INFO"); if (s1) { for (i=0;i<s1->all_eas.out.num_eas;i++) { printf(" flags=%d %s=%*.*s\n", s1->all_eas.out.eas[i].flags, s1->all_eas.out.eas[i].name.s, (int)s1->all_eas.out.eas[i].value.length, (int)s1->all_eas.out.eas[i].value.length, s1->all_eas.out.eas[i].value.data); } } if (s1 && s2) { if (s1->all_eas.out.num_eas == 0) { if (s2->all_info.out.ea_size != 0) { printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n", s2->all_info.out.ea_size); } } else { if (s2->all_info.out.ea_size != ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) { printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n", (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas), (int)s2->all_info.out.ea_size); } } } s2 = fname_find(is_ipc, "ALL_EAS"); if (s2) { VAL_EQUAL(all_eas, num_eas, all_eas, num_eas); for (i=0;i<s1->all_eas.out.num_eas;i++) { VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags); STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name); VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length); } } #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \ s1 = fnum_find(sname1); s2 = fnum_find(sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ }} while (0) VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, "ALL_INFO", all_info, delete_pending); VAL_CHECK("STANDARD_INFO", standard_info, directory, "ALL_INFO", all_info, directory); VAL_CHECK("STANDARD_INFO", standard_info, nlink, "ALL_INFO", all_info, nlink); s1 = fnum_find("BASIC_INFO"); if (s1 && is_ipc) { if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) { printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, (int)FILE_ATTRIBUTE_NORMAL); ret = false; } } s1 = fnum_find("STANDARD_INFO"); if (s1 && is_ipc) { if (s1->standard_info.out.nlink != 1) { printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink); ret = false; } if (s1->standard_info.out.delete_pending != 1) { printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending); ret = false; } } VAL_CHECK("EA_INFO", ea_info, ea_size, "ALL_INFO", all_info, ea_size); if (!is_ipc) { VAL_CHECK("EA_SIZE", ea_size, ea_size, "ALL_INFO", all_info, ea_size); } #define NAME_PATH_CHECK(sname, stype, field) do { \ s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \ if (s1 && s2) { \ VAL_EQUAL(stype, field, stype, field); \ } \ } while (0) s1 = fnum_find("INTERNAL_INFORMATION"); if (s1) { torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id); } NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id); NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position); if (s1 && s2) { printf("fnum pos = %.0f, fname pos = %.0f\n", (double)s2->position_information.out.position, (double)s1->position_information.out.position ); } NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode); NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement); NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib); NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag); #if 0 /* these are expected to differ */ NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags); #endif #if 0 /* unused */ #define UNKNOWN_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != 0) { \ printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \ #stype, #tfield, \ (unsigned int)s1->stype.out.tfield); \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != 0) { \ printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \ #stype, #tfield, \ (unsigned int)s1->stype.out.tfield); \ }} while (0) #endif /* now get a bit fancier .... */ /* when we set the delete disposition then the link count should drop to 0 and delete_pending should be 1 */ return ret; }
static bool torture_raw_sfileinfo_archive(struct torture_context *tctx, struct smbcli_state *cli) { const char *fname = BASEDIR "\\test_archive.dat"; NTSTATUS status; bool ret = true; union smb_open io; union smb_setfileinfo sfinfo; union smb_fileinfo finfo; uint16_t fnum=0; if (!torture_setup_dir(cli, BASEDIR)) { return false; } /* cleanup */ smbcli_unlink(cli->tree, fname); /* * create a normal file, verify archive bit */ io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; io.ntcreatex.in.flags = 0; status = smb_raw_open(cli->tree, tctx, &io); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "open failed"); fnum = io.ntcreatex.out.file.fnum; torture_assert_int_equal(tctx, io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_ARCHIVE, "archive bit not set"); /* * try to turn off archive bit */ ZERO_STRUCT(sfinfo); sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO; sfinfo.generic.in.file.fnum = fnum; sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; status = smb_raw_setfileinfo(cli->tree, &sfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "setfileinfo failed"); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, tctx, &finfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "fileinfo failed"); torture_assert_int_equal(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_NORMAL, "archive bit set"); status = smbcli_close(cli->tree, fnum); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "close failed"); status = smbcli_unlink(cli->tree, fname); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "unlink failed"); /* * create a directory, verify no archive bit */ io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.access_mask = SEC_RIGHTS_DIR_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; io.ntcreatex.in.flags = 0; status = smb_raw_open(cli->tree, tctx, &io); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "directory open failed"); fnum = io.ntcreatex.out.file.fnum; torture_assert_int_equal(tctx, io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_DIRECTORY, "archive bit set"); /* * verify you can turn on archive bit */ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO; sfinfo.generic.in.file.fnum = fnum; sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE; status = smb_raw_setfileinfo(cli->tree, &sfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "setfileinfo failed"); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, tctx, &finfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "fileinfo failed"); torture_assert_int_equal(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE, "archive bit not set"); /* * and try to turn it back off */ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO; sfinfo.generic.in.file.fnum = fnum; sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY; status = smb_raw_setfileinfo(cli->tree, &sfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "setfileinfo failed"); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, tctx, &finfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "fileinfo failed"); torture_assert_int_equal(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_DIRECTORY, "archive bit set"); status = smbcli_close(cli->tree, fnum); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "close failed"); done: smbcli_close(cli->tree, fnum); smbcli_deltree(cli->tree, BASEDIR); return ret; }
static bool test_session_reauth2(struct torture_context *tctx, struct smbcli_state *cli) { char *random_string; char *fname; union smb_open io_open; struct smb_composite_sesssetup io_sesssetup; union smb_fileinfo io_qsecdesc; struct smbcli_request *req; struct cli_credentials *anon_creds; NTSTATUS status; uint16_t fnum; ssize_t nwritten; uint16_t vuid1 = cli->session->vuid; random_string = generate_random_str(tctx, 8); torture_assert(tctx, (random_string != NULL), "memory allocation failed"); fname = talloc_asprintf(tctx, "raw_session_reauth2_%s.dat", random_string); talloc_free(random_string); torture_assert(tctx, (fname != NULL), "memory allocation failed"); smbcli_unlink(cli->tree, fname); smbcli_oplock_handler(cli->transport, test_session_reauth2_oplock_timeout, cli->tree); /* base ntcreatex parms */ ZERO_STRUCT(io_open); io_open.generic.level = RAW_OPEN_NTCREATEX; io_open.ntcreatex.in.root_fid.fnum = 0; io_open.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE; io_open.ntcreatex.in.alloc_size = 0; io_open.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io_open.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io_open.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io_open.ntcreatex.in.create_options = 0; io_open.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io_open.ntcreatex.in.security_flags = 0; io_open.ntcreatex.in.fname = fname; torture_comment(tctx, "open with batch oplock\n"); io_open.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; status = smb_raw_open(cli->tree, tctx, &io_open); torture_assert_ntstatus_ok(tctx, status, "smb_raw_open failed"); fnum = io_open.ntcreatex.out.file.fnum; torture_assert( tctx, (io_open.ntcreatex.out.oplock_level == BATCH_OPLOCK_RETURN), "did not get batch oplock"); io_open.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; req = smb_raw_open_send(cli->tree, &io_open); torture_assert(tctx, (req != NULL), "memory allocation failed"); /* * Make sure the open went through */ status = smbcli_chkpath(cli->tree, "\\"); torture_assert_ntstatus_ok(tctx, status, "smb_chkpath failed"); status = smbcli_nt_delete_on_close(cli->tree, fnum, true); torture_assert_ntstatus_ok(tctx, status, "could not set delete on " "close"); anon_creds = cli_credentials_init_anon(tctx); torture_assert(tctx, (anon_creds != NULL), "memory allocation failed"); ZERO_STRUCT(io_sesssetup); io_sesssetup.in.sesskey = cli->transport->negotiate.sesskey; io_sesssetup.in.capabilities = cli->transport->negotiate.capabilities; io_sesssetup.in.credentials = anon_creds; io_sesssetup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx); io_sesssetup.in.gensec_settings = lpcfg_gensec_settings( tctx, tctx->lp_ctx); status = smb_composite_sesssetup(cli->session, &io_sesssetup); torture_assert_ntstatus_ok(tctx, status, "setup2 failed"); torture_assert_int_equal(tctx, io_sesssetup.out.vuid, vuid1, "setup2"); status = smbcli_close(cli->tree, fnum); torture_assert_ntstatus_ok(tctx, status, "close failed"); status = smb_raw_open_recv(req, tctx, &io_open); torture_assert_ntstatus_ok(tctx, status, "2nd open failed"); fnum = io_open.ntcreatex.out.file.fnum; nwritten = smbcli_write(cli->tree, fnum, 0, fname, 0, strlen(fname)); torture_assert(tctx, (nwritten == strlen(fname)), "smbcli_write failed"); ZERO_STRUCT(io_qsecdesc); io_qsecdesc.query_secdesc.level = RAW_FILEINFO_SEC_DESC; io_qsecdesc.query_secdesc.in.file.fnum = fnum; io_qsecdesc.query_secdesc.in.secinfo_flags = SECINFO_OWNER; status = smb_raw_fileinfo(cli->tree, tctx, &io_qsecdesc); torture_assert_ntstatus_equal( tctx, status, NT_STATUS_ACCESS_DENIED, "anon qsecdesc did not return ACCESS_DENIED"); ZERO_STRUCT(io_sesssetup); io_sesssetup.in.sesskey = cli->transport->negotiate.sesskey; io_sesssetup.in.capabilities = cli->transport->negotiate.capabilities; io_sesssetup.in.credentials = cmdline_credentials; io_sesssetup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx); io_sesssetup.in.gensec_settings = lpcfg_gensec_settings( tctx, tctx->lp_ctx); status = smb_composite_sesssetup(cli->session, &io_sesssetup); torture_assert_ntstatus_ok(tctx, status, "setup3 failed"); torture_assert_int_equal(tctx, io_sesssetup.out.vuid, vuid1, "setup2"); status = smb_raw_fileinfo(cli->tree, tctx, &io_qsecdesc); torture_assert_ntstatus_ok(tctx, status, "2nd qsecdesc failed"); status = smbcli_nt_delete_on_close(cli->tree, fnum, true); torture_assert_ntstatus_ok(tctx, status, "could not set delete on " "close"); status = smbcli_close(cli->tree, fnum); torture_assert_ntstatus_ok(tctx, status, "close failed"); return true; }
static bool test_session_expire1(struct torture_context *tctx) { NTSTATUS status; bool ret = false; struct smbcli_options options; struct smbcli_session_options session_options; const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = cmdline_credentials; struct smbcli_state *cli = NULL; enum credentials_use_kerberos use_kerberos; char fname[256]; union smb_fileinfo qfinfo; uint16_t vuid; uint16_t fnum = 0; struct smb_composite_sesssetup io_sesssetup; size_t i; use_kerberos = cli_credentials_get_kerberos_state(credentials); if (use_kerberos != CRED_MUST_USE_KERBEROS) { torture_warning(tctx, "smb2.session.expire1 requires -k yes!"); torture_skip(tctx, "smb2.session.expire1 requires -k yes!"); } torture_assert_int_equal(tctx, use_kerberos, CRED_MUST_USE_KERBEROS, "please use -k yes"); lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=4"); lpcfg_smbcli_options(tctx->lp_ctx, &options); lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options); status = smbcli_full_connection(tctx, &cli, host, lpcfg_smb_ports(tctx->lp_ctx), share, NULL, lpcfg_socket_options(tctx->lp_ctx), credentials, lpcfg_resolve_context(tctx->lp_ctx), tctx->ev, &options, &session_options, lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smbcli_full_connection failed"); vuid = cli->session->vuid; /* Add some random component to the file name. */ snprintf(fname, 256, "session_expire1_%s.dat", generate_random_str(tctx, 8)); smbcli_unlink(cli->tree, fname); fnum = smbcli_nt_create_full(cli->tree, fname, 0, SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0); torture_assert_ntstatus_ok_goto(tctx, smbcli_nt_error(cli->tree), ret, done, "create file"); torture_assert_goto(tctx, fnum > 0, ret, done, "create file"); /* get the access information */ ZERO_STRUCT(qfinfo); qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; qfinfo.access_information.in.file.fnum = fnum; for (i=0; i < 2; i++) { torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); torture_comment(tctx, "sleep 5 seconds\n"); smb_msleep(5*1000); } /* * the krb5 library may not handle expired creds * well, lets start with an empty ccache. */ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); /* * now with CAP_DYNAMIC_REAUTH * * This should trigger NT_STATUS_NETWORK_SESSION_EXPIRED */ ZERO_STRUCT(io_sesssetup); io_sesssetup.in.sesskey = cli->transport->negotiate.sesskey; io_sesssetup.in.capabilities = cli->transport->negotiate.capabilities; io_sesssetup.in.capabilities |= CAP_DYNAMIC_REAUTH; io_sesssetup.in.credentials = credentials; io_sesssetup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx); io_sesssetup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx); torture_comment(tctx, "reauth with CAP_DYNAMIC_REAUTH => OK\n"); ZERO_STRUCT(io_sesssetup.out); status = smb_composite_sesssetup(cli->session, &io_sesssetup); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "reauth failed"); torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid, ret, done, "reauth"); for (i=0; i < 2; i++) { torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); torture_comment(tctx, "sleep 5 seconds\n"); smb_msleep(5*1000); torture_comment(tctx, "query info => EXPIRED\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "raw_fileinfo expired"); /* * the krb5 library may not handle expired creds * well, lets start with an empty ccache. */ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); torture_comment(tctx, "reauth with CAP_DYNAMIC_REAUTH => OK\n"); ZERO_STRUCT(io_sesssetup.out); status = smb_composite_sesssetup(cli->session, &io_sesssetup); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "reauth failed"); torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid, ret, done, "reauth"); } torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); /* * the krb5 library may not handle expired creds * well, lets start with an empty ccache. */ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); /* * now without CAP_DYNAMIC_REAUTH * * This should not trigger NT_STATUS_NETWORK_SESSION_EXPIRED */ torture_comment(tctx, "reauth without CAP_DYNAMIC_REAUTH => OK\n"); io_sesssetup.in.capabilities &= ~CAP_DYNAMIC_REAUTH; ZERO_STRUCT(io_sesssetup.out); status = smb_composite_sesssetup(cli->session, &io_sesssetup); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "reauth failed"); torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid, ret, done, "reauth"); for (i=0; i < 2; i++) { torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); torture_comment(tctx, "sleep 5 seconds\n"); smb_msleep(5*1000); } torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); ret = true; done: if (fnum > 0) { smbcli_close(cli->tree, fnum); } talloc_free(cli); lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=0"); return ret; }