static bool test_durable_v2_open_lease_table(struct torture_context *tctx, struct smb2_tree *tree, const char *fname, bool request_persistent, struct durable_open_vs_lease *table, uint8_t num_tests) { bool ret = true; uint8_t i; smb2_util_unlink(tree, fname); for (i = 0; i < num_tests; i++) { ret = test_one_durable_v2_open_lease(tctx, tree, fname, request_persistent, table[i]); if (ret == false) { goto done; } } done: smb2_util_unlink(tree, fname); return ret; }
/** * basic test for doing a durable open * and do a durable reopen on the same connection * while the first open is still active (fails) */ bool test_durable_v2_open_reopen1(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h; struct smb2_handle *h = NULL; struct smb2_create io; struct GUID create_guid = GUID_random(); bool ret = true; /* Choose a random name in case the state is left a little funky. */ snprintf(fname, 256, "durable_v2_open_reopen1_%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); /* try a durable reconnect while the file is still open */ ZERO_STRUCT(io); io.in.fname = ""; io.in.durable_handle_v2 = h; io.in.create_guid = create_guid; status = smb2_create(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); done: if (h != NULL) { smb2_util_close(tree, *h); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; }
static bool test_lease_upgrade2(struct torture_context *tctx, struct smb2_tree *tree) { TALLOC_CTX *mem_ctx = talloc_new(tctx); struct smb2_handle h, hnew; NTSTATUS status; struct smb2_create io; struct smb2_lease ls; const char *fname = "lease.dat"; bool ret = true; int i; uint32_t caps; caps = smb2cli_conn_server_capabilities(tree->session->transport->conn); if (!(caps & SMB2_CAP_LEASING)) { torture_skip(tctx, "leases are not supported"); } for (i = 0; i < NUM_UPGRADE_TESTS; i++) { struct lease_upgrade2_test t = lease_upgrade2_tests[i]; smb2_util_unlink(tree, fname); /* Grab a lease. */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial)); status = smb2_create(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_LEASE(&io, t.initial, true, LEASE1); h = io.out.file.handle; /* Upgrade. */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to)); status = smb2_create(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); CHECK_LEASE(&io, t.expected, true, LEASE1); hnew = io.out.file.handle; smb2_util_close(tree, hnew); smb2_util_close(tree, h); } done: smb2_util_close(tree, h); smb2_util_close(tree, hnew); smb2_util_unlink(tree, fname); talloc_free(mem_ctx); return ret; }
static bool test_one_durable_v2_open_lease(struct torture_context *tctx, struct smb2_tree *tree, const char *fname, bool request_persistent, struct durable_open_vs_lease test) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); struct smb2_handle _h; struct smb2_handle *h = NULL; bool ret = true; struct smb2_create io; struct smb2_lease ls; uint64_t lease; smb2_util_unlink(tree, fname); lease = random(); smb2_lease_create_share(&io, &ls, false /* dir */, fname, smb2_util_share_access(test.share_mode), lease, smb2_util_lease_state(test.type)); io.in.durable_open = false; io.in.durable_open_v2 = true; io.in.persistent_open = request_persistent; io.in.create_guid = GUID_random(); status = smb2_create(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); _h = io.out.file.handle; h = &_h; CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io.out.durable_open, false); CHECK_VAL(io.out.durable_open_v2, test.durable); CHECK_VAL(io.out.persistent_open, test.persistent); 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_util_lease_state(test.type)); done: if (h != NULL) { smb2_util_close(tree, *h); } smb2_util_unlink(tree, fname); talloc_free(mem_ctx); return ret; }
/** * basic test for doing a session reconnect on one connection */ bool test_session_reconnect2(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; uint64_t previous_session_id; bool ret = true; struct smb2_session *session2; union smb_fileinfo qfinfo; /* Add some random component to the file name. */ snprintf(fname, 256, "session_reconnect_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; 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")); /* disconnect, reconnect and then do durable reopen */ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); torture_assert(tctx, torture_smb2_session_setup(tctx, tree->session->transport, previous_session_id, tctx, &session2), "session reconnect (on the same connection) failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); h1 = NULL; done: if (h1 != NULL) { smb2_util_close(tree, *h1); } talloc_free(tree); talloc_free(session2); talloc_free(mem_ctx); return ret; }
static bool test_one_durable_v2_open_oplock(struct torture_context *tctx, struct smb2_tree *tree, const char *fname, bool request_persistent, struct durable_open_vs_oplock test) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); struct smb2_handle _h; struct smb2_handle *h = NULL; bool ret = true; struct smb2_create io; smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io, fname, smb2_util_share_access(test.share_mode), smb2_util_oplock_level(test.level)); io.in.durable_open = false; io.in.durable_open_v2 = true; io.in.persistent_open = request_persistent; io.in.create_guid = GUID_random(); status = smb2_create(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); _h = io.out.file.handle; h = &_h; CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io.out.durable_open, false); CHECK_VAL(io.out.durable_open_v2, test.durable); CHECK_VAL(io.out.persistent_open, test.persistent); CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level)); done: if (h != NULL) { smb2_util_close(tree, *h); } smb2_util_unlink(tree, fname); talloc_free(mem_ctx); return ret; }
/* create a complex file/dir using the SMB2 protocol */ static NTSTATUS smb2_create_complex(struct smb2_tree *tree, const char *fname, struct smb2_handle *handle, bool dir) { TALLOC_CTX *tmp_ctx = talloc_new(tree); char buf[7] = "abc"; struct smb2_create io; union smb_setfileinfo setfile; union smb_fileinfo fileinfo; time_t t = (time(NULL) & ~1); NTSTATUS status; smb2_util_unlink(tree, fname); ZERO_STRUCT(io); io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE| NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE; io.in.create_options = 0; io.in.fname = fname; if (dir) { io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE; io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; io.in.create_disposition = NTCREATEX_DISP_CREATE; } /* it seems vista is now fussier about alignment? */ if (strchr(fname, ':') == NULL) { /* setup some EAs */ io.in.eas.num_eas = 2; io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2); io.in.eas.eas[0].flags = 0; io.in.eas.eas[0].name.s = "EAONE"; io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6); io.in.eas.eas[1].flags = 0; io.in.eas.eas[1].name.s = "SECONDEA"; io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8); }
/* basic testing of SMB2 shadow copy calls */ static bool test_ioctl_get_shadow_copy(struct torture_context *torture, struct smb2_tree *tree) { struct smb2_handle h; uint8_t buf[100]; NTSTATUS status; union smb_ioctl ioctl; TALLOC_CTX *tmp_ctx = talloc_new(tree); smb2_util_unlink(tree, FNAME); status = torture_smb2_testfile(tree, FNAME, &h); if (!NT_STATUS_IS_OK(status)) { printf("create write\n"); return false; } ZERO_ARRAY(buf); status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf)); if (!NT_STATUS_IS_OK(status)) { printf("failed write\n"); return false; } ZERO_STRUCT(ioctl); ioctl.smb2.level = RAW_IOCTL_SMB2; ioctl.smb2.in.file.handle = h; ioctl.smb2.in.function = SMB2_FSCTL_SRV_ENUM_SNAPS; ioctl.smb2.in.max_response_size = 16; ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2); if (!NT_STATUS_IS_OK(status)) { printf("SMB2_FSCTL_SRV_ENUM_SNAPS failed\n"); return false; } return true; }
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_compound_padding(struct torture_context *tctx, struct smb2_tree *tree) { struct smb2_handle h; struct smb2_create cr; struct smb2_read r; const char *fname = "compound_read.dat"; const char *sname = "compound_read.dat:foo"; struct smb2_request *req[3]; NTSTATUS status; bool ret = false; smb2_util_unlink(tree, fname); /* Write file */ ZERO_STRUCT(cr); cr.in.desired_access = SEC_FILE_WRITE_DATA; cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL; cr.in.create_disposition = NTCREATEX_DISP_CREATE; cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; cr.in.fname = fname; cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE| NTCREATEX_SHARE_ACCESS_DELETE; status = smb2_create(tree, tctx, &cr); CHECK_STATUS(status, NT_STATUS_OK); h = cr.out.file.handle; status = smb2_util_write(tree, h, "123", 0, 3); CHECK_STATUS(status, NT_STATUS_OK); smb2_util_close(tree, h); /* Write stream */ ZERO_STRUCT(cr); cr.in.desired_access = SEC_FILE_WRITE_DATA; cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL; cr.in.create_disposition = NTCREATEX_DISP_CREATE; cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; cr.in.fname = sname; cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE| NTCREATEX_SHARE_ACCESS_DELETE; status = smb2_create(tree, tctx, &cr); CHECK_STATUS(status, NT_STATUS_OK); h = cr.out.file.handle; status = smb2_util_write(tree, h, "456", 0, 3); CHECK_STATUS(status, NT_STATUS_OK); smb2_util_close(tree, h); /* Check compound read from basefile */ smb2_transport_compound_start(tree->session->transport, 2); ZERO_STRUCT(cr); cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; cr.in.desired_access = SEC_FILE_READ_DATA; cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL; cr.in.create_disposition = NTCREATEX_DISP_OPEN; cr.in.fname = fname; cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE| NTCREATEX_SHARE_ACCESS_DELETE; req[0] = smb2_create_send(tree, &cr); smb2_transport_compound_set_related(tree->session->transport, true); ZERO_STRUCT(r); h.data[0] = UINT64_MAX; h.data[1] = UINT64_MAX; r.in.file.handle = h; r.in.length = 3; r.in.offset = 0; r.in.min_count = 1; req[1] = smb2_read_send(tree, &r); status = smb2_create_recv(req[0], tree, &cr); CHECK_STATUS(status, NT_STATUS_OK); /* * We must do a manual smb2_request_receive() in order to be * able to check the transport layer info, as smb2_read_recv() * will destroy the req. smb2_read_recv() will call * smb2_request_receive() again, but that's ok. */ if (!smb2_request_receive(req[1]) || !smb2_request_is_ok(req[1])) { torture_fail(tctx, "failed to receive read request"); } /* * size must be 24: 16 byte read response header plus 3 * requested bytes padded to an 8 byte boundary. */ CHECK_VALUE(req[1]->in.body_size, 24); status = smb2_read_recv(req[1], tree, &r); CHECK_STATUS(status, NT_STATUS_OK); smb2_util_close(tree, cr.out.file.handle); /* Check compound read from stream */ smb2_transport_compound_start(tree->session->transport, 2); ZERO_STRUCT(cr); cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; cr.in.desired_access = SEC_FILE_READ_DATA; cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL; cr.in.create_disposition = NTCREATEX_DISP_OPEN; cr.in.fname = sname; cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE| NTCREATEX_SHARE_ACCESS_DELETE; req[0] = smb2_create_send(tree, &cr); smb2_transport_compound_set_related(tree->session->transport, true); ZERO_STRUCT(r); h.data[0] = UINT64_MAX; h.data[1] = UINT64_MAX; r.in.file.handle = h; r.in.length = 3; r.in.offset = 0; r.in.min_count = 1; req[1] = smb2_read_send(tree, &r); status = smb2_create_recv(req[0], tree, &cr); CHECK_STATUS(status, NT_STATUS_OK); /* * We must do a manual smb2_request_receive() in order to be * able to check the transport layer info, as smb2_read_recv() * will destroy the req. smb2_read_recv() will call * smb2_request_receive() again, but that's ok. */ if (!smb2_request_receive(req[1]) || !smb2_request_is_ok(req[1])) { torture_fail(tctx, "failed to receive read request"); } /* * size must be 24: 16 byte read response header plus 3 * requested bytes padded to an 8 byte boundary. */ CHECK_VALUE(req[1]->in.body_size, 24); status = smb2_read_recv(req[1], tree, &r); CHECK_STATUS(status, NT_STATUS_OK); h = cr.out.file.handle; /* Check 2 compound (unrelateated) reads from existing stream handle */ smb2_transport_compound_start(tree->session->transport, 2); ZERO_STRUCT(r); r.in.file.handle = h; r.in.length = 3; r.in.offset = 0; r.in.min_count = 1; req[0] = smb2_read_send(tree, &r); req[1] = smb2_read_send(tree, &r); /* * We must do a manual smb2_request_receive() in order to be * able to check the transport layer info, as smb2_read_recv() * will destroy the req. smb2_read_recv() will call * smb2_request_receive() again, but that's ok. */ if (!smb2_request_receive(req[0]) || !smb2_request_is_ok(req[0])) { torture_fail(tctx, "failed to receive read request"); } if (!smb2_request_receive(req[1]) || !smb2_request_is_ok(req[1])) { torture_fail(tctx, "failed to receive read request"); } /* * size must be 24: 16 byte read response header plus 3 * requested bytes padded to an 8 byte boundary. */ CHECK_VALUE(req[0]->in.body_size, 24); CHECK_VALUE(req[1]->in.body_size, 24); status = smb2_read_recv(req[0], tree, &r); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_read_recv(req[1], tree, &r); CHECK_STATUS(status, NT_STATUS_OK); /* * now try a single read from the stream and verify there's no padding */ ZERO_STRUCT(r); r.in.file.handle = h; r.in.length = 3; r.in.offset = 0; r.in.min_count = 1; req[0] = smb2_read_send(tree, &r); /* * We must do a manual smb2_request_receive() in order to be * able to check the transport layer info, as smb2_read_recv() * will destroy the req. smb2_read_recv() will call * smb2_request_receive() again, but that's ok. */ if (!smb2_request_receive(req[0]) || !smb2_request_is_ok(req[0])) { torture_fail(tctx, "failed to receive read request"); } /* * size must be 19: 16 byte read response header plus 3 * requested bytes without padding. */ CHECK_VALUE(req[0]->in.body_size, 19); status = smb2_read_recv(req[0], tree, &r); CHECK_STATUS(status, NT_STATUS_OK); smb2_util_close(tree, h); status = smb2_util_unlink(tree, fname); CHECK_STATUS(status, NT_STATUS_OK); ret = true; done: return ret; }
/** * do reauth with wrong credentials, * hence triggering the error path in reauth. * The invalid reauth deletes the session. */ bool test_session_reauth6(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; char *corrupted_password; struct cli_credentials *broken_creds; bool ok; bool encrypted; NTSTATUS expected; enum credentials_use_kerberos krb_state; krb_state = cli_credentials_get_kerberos_state(cmdline_credentials); if (krb_state == CRED_MUST_USE_KERBEROS) { torture_skip(tctx, "Can't test failing session setup with kerberos."); } encrypted = smb2cli_tcon_is_encryption_on(tree->smbXcli); /* Add some random component to the file name. */ snprintf(fname, 256, "session_reauth1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; 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")); /* * reauthentication with invalid credentials: */ broken_creds = cli_credentials_shallow_copy(mem_ctx, cmdline_credentials); torture_assert(tctx, (broken_creds != NULL), "talloc error"); corrupted_password = talloc_asprintf(mem_ctx, "%s%s", cli_credentials_get_password(broken_creds), "corrupt"); torture_assert(tctx, (corrupted_password != NULL), "talloc error"); ok = cli_credentials_set_password(broken_creds, corrupted_password, CRED_SPECIFIED); CHECK_VAL(ok, true); status = smb2_session_setup_spnego(tree->session, broken_creds, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE); torture_comment(tctx, "did failed reauth\n"); /* * now verify that the invalid session reauth has closed our session */ if (encrypted) { expected = NT_STATUS_CONNECTION_DISCONNECTED; } else { expected = NT_STATUS_USER_SESSION_DELETED; } 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, expected); done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); 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; }
/** * test getting security descriptor after reauth */ bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; union smb_fileinfo qfinfo; struct cli_credentials *anon_creds = NULL; uint32_t secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_PROTECTED_DACL | SECINFO_UNPROTECTED_DACL; /* Add some random component to the file name. */ snprintf(fname, 256, "session_reauth3_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); 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); /* 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 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); /* 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); /* 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 (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; }
/* recursively descend a tree deleting all files returns the number of files deleted, or -1 on error */ int smb2_deltree(struct smb2_tree *tree, const char *dname) { NTSTATUS status; uint32_t total_deleted = 0; unsigned int count, i; union smb_search_data *list; TALLOC_CTX *tmp_ctx = talloc_new(tree); struct smb2_find f; struct smb2_create create_parm; bool did_delete; /* it might be a file */ status = smb2_util_unlink(tree, dname); if (NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return 1; } if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) || NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_FILE)) { talloc_free(tmp_ctx); return 0; } if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) { /* it could be read-only */ status = smb2_util_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL); status = smb2_util_unlink(tree, dname); } if (NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return 1; } ZERO_STRUCT(create_parm); create_parm.in.desired_access = SEC_FILE_READ_DATA; create_parm.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE; create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; create_parm.in.create_disposition = NTCREATEX_DISP_OPEN; create_parm.in.fname = dname; status = smb2_create(tree, tmp_ctx, &create_parm); if (NT_STATUS_IS_ERR(status)) { DEBUG(2,("Failed to open %s - %s\n", dname, nt_errstr(status))); talloc_free(tmp_ctx); return -1; } do { did_delete = false; ZERO_STRUCT(f); f.in.file.handle = create_parm.out.file.handle; f.in.max_response_size = 0x10000; f.in.level = SMB2_FIND_NAME_INFO; f.in.pattern = "*"; status = smb2_find_level(tree, tmp_ctx, &f, &count, &list); if (NT_STATUS_IS_ERR(status)) { DEBUG(2,("Failed to list %s - %s\n", dname, nt_errstr(status))); smb2_util_close(tree, create_parm.out.file.handle); talloc_free(tmp_ctx); return -1; } for (i=0;i<count;i++) { char *name; if (strcmp(".", list[i].name_info.name.s) == 0 || strcmp("..", list[i].name_info.name.s) == 0) { continue; } name = talloc_asprintf(tmp_ctx, "%s\\%s", dname, list[i].name_info.name.s); status = smb2_util_unlink(tree, name); if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) { /* it could be read-only */ status = smb2_util_setatr(tree, name, FILE_ATTRIBUTE_NORMAL); status = smb2_util_unlink(tree, name); } if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { int ret; ret = smb2_deltree(tree, name); if (ret > 0) total_deleted += ret; } talloc_free(name); if (NT_STATUS_IS_OK(status)) { total_deleted++; did_delete = true; } } } while (did_delete); smb2_util_close(tree, create_parm.out.file.handle); status = smb2_util_rmdir(tree, dname); if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) { /* it could be read-only */ status = smb2_util_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL); status = smb2_util_rmdir(tree, dname); } if (NT_STATUS_IS_ERR(status)) { DEBUG(2,("Failed to delete %s - %s\n", dname, nt_errstr(status))); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return total_deleted; }
/* 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; }
/* 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; }
static bool test_compound_invalid3(struct torture_context *tctx, struct smb2_tree *tree) { struct smb2_handle hd; struct smb2_create cr; NTSTATUS status; const char *fname = "compound_invalid3.dat"; struct smb2_close cl; bool ret = true; struct smb2_request *req[5]; smb2_transport_credits_ask_num(tree->session->transport, 5); smb2_util_unlink(tree, fname); smb2_transport_credits_ask_num(tree->session->transport, 1); ZERO_STRUCT(cr); cr.in.security_flags = 0x00; cr.in.oplock_level = 0; cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; cr.in.create_flags = 0x00000000; cr.in.reserved = 0x00000000; cr.in.desired_access = SEC_RIGHTS_FILE_ALL; cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL; cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF; cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | NTCREATEX_OPTIONS_ASYNC_ALERT | NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | 0x00200000; cr.in.fname = fname; smb2_transport_compound_start(tree->session->transport, 5); req[0] = smb2_create_send(tree, &cr); hd.data[0] = UINT64_MAX; hd.data[1] = UINT64_MAX; ZERO_STRUCT(cl); cl.in.file.handle = hd; req[1] = smb2_close_send(tree, &cl); req[2] = smb2_close_send(tree, &cl); /* flipping the related flag is invalid */ smb2_transport_compound_set_related(tree->session->transport, true); req[3] = smb2_close_send(tree, &cl); req[4] = smb2_close_send(tree, &cl); status = smb2_create_recv(req[0], tree, &cr); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_close_recv(req[1], &cl); CHECK_STATUS(status, NT_STATUS_FILE_CLOSED); status = smb2_close_recv(req[2], &cl); CHECK_STATUS(status, NT_STATUS_FILE_CLOSED); status = smb2_close_recv(req[3], &cl); CHECK_STATUS(status, NT_STATUS_FILE_CLOSED); status = smb2_close_recv(req[4], &cl); CHECK_STATUS(status, NT_STATUS_FILE_CLOSED); smb2_util_unlink(tree, fname); done: return ret; }
static bool test_compound_invalid2(struct torture_context *tctx, struct smb2_tree *tree) { struct smb2_handle hd; struct smb2_create cr; NTSTATUS status; const char *fname = "compound_invalid2.dat"; struct smb2_close cl; bool ret = true; struct smb2_request *req[5]; struct smbXcli_tcon *saved_tcon = tree->smbXcli; struct smbXcli_session *saved_session = tree->session->smbXcli; smb2_transport_credits_ask_num(tree->session->transport, 5); smb2_util_unlink(tree, fname); smb2_transport_credits_ask_num(tree->session->transport, 1); ZERO_STRUCT(cr); cr.in.security_flags = 0x00; cr.in.oplock_level = 0; cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; cr.in.create_flags = 0x00000000; cr.in.reserved = 0x00000000; cr.in.desired_access = SEC_RIGHTS_FILE_ALL; cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL; cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF; cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | NTCREATEX_OPTIONS_ASYNC_ALERT | NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | 0x00200000; cr.in.fname = fname; smb2_transport_compound_start(tree->session->transport, 5); req[0] = smb2_create_send(tree, &cr); hd.data[0] = UINT64_MAX; hd.data[1] = UINT64_MAX; smb2_transport_compound_set_related(tree->session->transport, true); ZERO_STRUCT(cl); cl.in.file.handle = hd; tree->smbXcli = smbXcli_tcon_create(tree); smb2cli_tcon_set_values(tree->smbXcli, NULL, /* session */ 0xFFFFFFFF, /* tcon_id */ 0, /* type */ 0, /* flags */ 0, /* capabilities */ 0 /* maximal_access */); tree->session->smbXcli = smbXcli_session_copy(tree->session, tree->session->smbXcli); smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0); req[1] = smb2_close_send(tree, &cl); /* strange that this is not generating invalid parameter */ smb2_transport_compound_set_related(tree->session->transport, false); req[2] = smb2_close_send(tree, &cl); req[3] = smb2_close_send(tree, &cl); smb2_transport_compound_set_related(tree->session->transport, true); req[4] = smb2_close_send(tree, &cl); status = smb2_create_recv(req[0], tree, &cr); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_close_recv(req[1], &cl); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_close_recv(req[2], &cl); CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); status = smb2_close_recv(req[3], &cl); CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); status = smb2_close_recv(req[4], &cl); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); TALLOC_FREE(tree->smbXcli); tree->smbXcli = saved_tcon; TALLOC_FREE(tree->session->smbXcli); tree->session->smbXcli = saved_session; smb2_util_unlink(tree, fname); done: return ret; }
bool test_session_reauth1(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; union smb_fileinfo qfinfo; /* Add some random component to the file name. */ snprintf(fname, 256, "session_reauth1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); 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")); status = smb2_session_setup_spnego(tree->session, cmdline_credentials, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_OK); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_session_setup_spnego(tree->session, cmdline_credentials, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_OK); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; }
bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1) { const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = cmdline_credentials; NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo; bool ret = false; struct smb2_tree *tree2 = NULL; struct smb2_transport *transport1 = tree1->session->transport; struct smb2_transport *transport2 = NULL; struct smb2_session *session1_1 = tree1->session; struct smb2_session *session1_2 = NULL; struct smb2_session *session2_1 = NULL; struct smb2_session *session2_2 = NULL; uint32_t caps; caps = smb2cli_conn_server_capabilities(transport1->conn); if (!(caps & SMB2_CAP_MULTI_CHANNEL)) { torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n"); } /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_bind1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree1, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree1, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree2, tctx->ev, &transport1->options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); session2_2 = tree2->session; transport2 = tree2->session->transport; /* * Now bind the 2nd transport connection to the 1st session */ session1_2 = smb2_session_channel(transport2, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree2, session1_1); torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session1_2, cmdline_credentials, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* use the 1st connection, 1st session */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; tree1->session = session1_1; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* use the 2nd connection, 1st session */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; tree1->session = session1_2; status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); tree1->session = session1_1; status = smb2_util_close(tree1, *h1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed"); h1 = NULL; /* * Now bind the 1st transport connection to the 2nd session */ session2_1 = smb2_session_channel(transport1, lpcfg_gensec_settings(tctx, tctx->lp_ctx), tree1, session2_2); torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed"); status = smb2_session_setup_spnego(session2_1, cmdline_credentials, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); tree2->session = session2_1; status = smb2_util_unlink(tree2, fname); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_unlink failed"); ret = true; done: talloc_free(tree2); tree1->session = session1_1; if (h1 != NULL) { smb2_util_close(tree1, *h1); } smb2_util_unlink(tree1, fname); talloc_free(tree1); talloc_free(mem_ctx); return ret; }
/** * test setting security descriptor after reauth. */ bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; 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 *sd1; struct security_ace ace; struct dom_sid *extra_sid; /* Add some random component to the file name. */ snprintf(fname, 256, "session_reauth4_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); 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); 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); /* 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_STD_ALL | SEC_FILE_ALL; ace.trustee = *extra_sid; status = security_descriptor_dacl_add(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_DACL; sfinfo.set_secdesc.in.sd = sd1; status = smb2_setinfo_file(tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); /* 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); /* 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); ret = true; done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; }
bool test_session_reauth2(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; union smb_fileinfo qfinfo; struct cli_credentials *anon_creds = NULL; /* Add some random component to the file name. */ snprintf(fname, sizeof(fname), "session_reauth2_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); torture_assert_int_equal(tctx, io1.out.oplock_level, smb2_util_oplock_level("b"), "oplock_level incorrect"); /* 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 */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); /* re-authenticate as original user again */ status = smb2_session_setup_spnego(tree->session, cmdline_credentials, 0 /* previous_session_id */); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_session_setup_spnego failed"); /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; }
/** * basic test for doing a session reconnect */ bool test_session_reconnect1(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_handle _h2; struct smb2_handle *h2 = NULL; struct smb2_create io1, io2; uint64_t previous_session_id; bool ret = true; struct smb2_tree *tree2; union smb_fileinfo qfinfo; /* Add some random component to the file name. */ snprintf(fname, 256, "session_reconnect_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); 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")); /* disconnect, reconnect and then do durable reopen */ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli); if (!torture_smb2_connection_ext(tctx, previous_session_id, &tree->session->transport->options, &tree2)) { torture_warning(tctx, "session reconnect failed\n"); ret = false; goto done; } /* try to access the file via the old handle */ ZERO_STRUCT(qfinfo); qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; qfinfo.generic.in.file.handle = _h1; status = smb2_getinfo_file(tree, mem_ctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); h1 = NULL; smb2_oplock_create_share(&io2, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree2, mem_ctx, &io2); CHECK_STATUS(status, NT_STATUS_OK); CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b")); _h2 = io2.out.file.handle; h2 = &_h2; done: if (h1 != NULL) { smb2_util_close(tree, *h1); } if (h2 != NULL) { smb2_util_close(tree2, *h2); } smb2_util_unlink(tree2, fname); talloc_free(tree); talloc_free(tree2); talloc_free(mem_ctx); return ret; }
/* * Test creating a file with a NULL DACL. */ static bool test_create_null_dacl(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; struct smb2_create io; const char *fname = "nulldacl.txt"; bool ret = true; struct smb2_handle handle; union smb_fileinfo q; union smb_setfileinfo s; struct security_descriptor *sd = security_descriptor_initialise(tctx); struct security_acl dacl; torture_comment(tctx, "TESTING SEC_DESC WITH A NULL DACL\n"); smb2_util_unlink(tree, fname); ZERO_STRUCT(io); io.level = RAW_OPEN_SMB2; io.in.create_flags = 0; io.in.desired_access = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC | SEC_STD_WRITE_OWNER; io.in.create_options = 0; io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.in.alloc_size = 0; io.in.create_disposition = NTCREATEX_DISP_CREATE; io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS; io.in.security_flags = 0; io.in.fname = fname; io.in.sec_desc = sd; /* XXX create_options ? */ io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | NTCREATEX_OPTIONS_ASYNC_ALERT | NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | 0x00200000; torture_comment(tctx, "creating a file with a empty sd\n"); status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); handle = io.out.file.handle; torture_comment(tctx, "get the original sd\n"); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); /* * Testing the created DACL, * the server should add the inherited DACL * when SEC_DESC_DACL_PRESENT isn't specified */ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) { ret = false; torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n"); } if (q.query_secdesc.out.sd->dacl == NULL) { ret = false; torture_fail_goto(tctx, done, "no DACL has been created on the server!\n"); } torture_comment(tctx, "set NULL DACL\n"); sd->type |= SEC_DESC_DACL_PRESENT; s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; s.set_secdesc.in.file.handle = handle; s.set_secdesc.in.secinfo_flags = SECINFO_DACL; s.set_secdesc.in.sd = sd; status = smb2_setinfo_file(tree, &s); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "get the sd\n"); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); /* Testing the modified DACL */ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) { ret = false; torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n"); } if (q.query_secdesc.out.sd->dacl != NULL) { ret = false; torture_fail_goto(tctx, done, "DACL has been created on the server!\n"); } io.in.create_disposition = NTCREATEX_DISP_OPEN; torture_comment(tctx, "try open for read control\n"); io.in.desired_access = SEC_STD_READ_CONTROL; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_STD_READ_CONTROL); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for write\n"); io.in.desired_access = SEC_FILE_WRITE_DATA; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_FILE_WRITE_DATA); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for read\n"); io.in.desired_access = SEC_FILE_READ_DATA; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_FILE_READ_DATA); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for generic write\n"); io.in.desired_access = SEC_GENERIC_WRITE; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_RIGHTS_FILE_WRITE); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for generic read\n"); io.in.desired_access = SEC_GENERIC_READ; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_RIGHTS_FILE_READ); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "set DACL with 0 aces\n"); ZERO_STRUCT(dacl); dacl.revision = SECURITY_ACL_REVISION_NT4; dacl.num_aces = 0; sd->dacl = &dacl; s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; s.set_secdesc.in.file.handle = handle; s.set_secdesc.in.secinfo_flags = SECINFO_DACL; s.set_secdesc.in.sd = sd; status = smb2_setinfo_file(tree, &s); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "get the sd\n"); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); /* Testing the modified DACL */ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) { ret = false; torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n"); } if (q.query_secdesc.out.sd->dacl == NULL) { ret = false; torture_fail_goto(tctx, done, "no DACL has been created on the server!\n"); } if (q.query_secdesc.out.sd->dacl->num_aces != 0) { torture_result(tctx, TORTURE_FAIL, "DACL has %u aces!\n", q.query_secdesc.out.sd->dacl->num_aces); ret = false; goto done; } torture_comment(tctx, "try open for read control\n"); io.in.desired_access = SEC_STD_READ_CONTROL; status = smb2_create(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_STD_READ_CONTROL); smb2_util_close(tree, io.out.file.handle); torture_comment(tctx, "try open for write => access_denied\n"); io.in.desired_access = SEC_FILE_WRITE_DATA; status = smb2_create(tree, tctx, &io); if (torture_setting_bool(tctx, "hide_on_access_denied", false)) { CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "try open for read => access_denied\n"); io.in.desired_access = SEC_FILE_READ_DATA; status = smb2_create(tree, tctx, &io); if (torture_setting_bool(tctx, "hide_on_access_denied", false)) { CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "try open for generic write => access_denied\n"); io.in.desired_access = SEC_GENERIC_WRITE; status = smb2_create(tree, tctx, &io); if (torture_setting_bool(tctx, "hide_on_access_denied", false)) { CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "try open for generic read => access_denied\n"); io.in.desired_access = SEC_GENERIC_READ; status = smb2_create(tree, tctx, &io); if (torture_setting_bool(tctx, "hide_on_access_denied", false)) { CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "set empty sd\n"); sd->type &= ~SEC_DESC_DACL_PRESENT; sd->dacl = NULL; s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; s.set_secdesc.in.file.handle = handle; s.set_secdesc.in.secinfo_flags = SECINFO_DACL; s.set_secdesc.in.sd = sd; status = smb2_setinfo_file(tree, &s); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "get the sd\n"); q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; q.query_secdesc.in.file.handle = handle; q.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; status = smb2_getinfo_file(tree, tctx, &q); CHECK_STATUS(status, NT_STATUS_OK); /* Testing the modified DACL */ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) { ret = false; torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n"); } if (q.query_secdesc.out.sd->dacl != NULL) { ret = false; torture_fail_goto(tctx, done, "DACL has been created on the server!\n"); } done: smb2_util_close(tree, handle); smb2_util_unlink(tree, fname); smb2_tdis(tree); smb2_logoff(tree->session); return ret; }
static bool test_session_expire1(struct torture_context *tctx) { NTSTATUS status; bool ret = false; struct smbcli_options 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 smb2_tree *tree = NULL; enum credentials_use_kerberos use_kerberos; char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo; 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); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); /* Add some random component to the file name. */ snprintf(fname, 256, "session_expire1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree, tctx, &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.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; qfinfo.access_information.in.file.handle = _h1; for (i=0; i < 2; i++) { torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); 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 = smb2_getinfo_file(tree, tctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_NETWORK_SESSION_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 => OK\n"); status = smb2_session_setup_spnego(tree->session, credentials, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_OK); } ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); ret = true; done: if (h1 != NULL) { smb2_util_close(tree, *h1); } talloc_free(tree); lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=0"); 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; }
static bool test_compound_break(struct torture_context *tctx, struct smb2_tree *tree) { const char *fname1 = "some-file.pptx"; NTSTATUS status; bool ret = true; union smb_open io1; struct smb2_create io2; struct smb2_getinfo gf; struct smb2_request *req[2]; struct smb2_handle h1; struct smb2_handle h; tree->session->transport->oplock.handler = torture_oplock_handler; tree->session->transport->oplock.private_data = tree; ZERO_STRUCT(break_info); /* base ntcreatex parms */ ZERO_STRUCT(io1.smb2); io1.generic.level = RAW_OPEN_SMB2; io1.smb2.in.desired_access = (SEC_STD_SYNCHRONIZE| SEC_STD_READ_CONTROL| SEC_FILE_READ_ATTRIBUTE| SEC_FILE_READ_EA| SEC_FILE_READ_DATA); io1.smb2.in.alloc_size = 0; io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE| NTCREATEX_SHARE_ACCESS_DELETE; io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF; io1.smb2.in.create_options = 0; io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; io1.smb2.in.security_flags = 0; io1.smb2.in.fname = fname1; torture_comment(tctx, "TEST2: open a file with an batch " "oplock (share mode: all)\n"); io1.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH; status = smb2_create(tree, tctx, &(io1.smb2)); torture_assert_ntstatus_ok(tctx, status, "Error opening the file"); h1 = io1.smb2.out.file.handle; torture_comment(tctx, "TEST2: Opening second time with compound\n"); ZERO_STRUCT(io2); io2.in.desired_access = (SEC_STD_SYNCHRONIZE| SEC_FILE_READ_ATTRIBUTE| SEC_FILE_READ_EA); io2.in.alloc_size = 0; io2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; io2.in.share_access = NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE| NTCREATEX_SHARE_ACCESS_DELETE; io2.in.create_disposition = NTCREATEX_DISP_OPEN; io2.in.create_options = 0; io2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; io2.in.security_flags = 0; io2.in.fname = fname1; io2.in.oplock_level = 0; smb2_transport_compound_start(tree->session->transport, 2); req[0] = smb2_create_send(tree, &io2); smb2_transport_compound_set_related(tree->session->transport, true); h.data[0] = UINT64_MAX; h.data[1] = UINT64_MAX; ZERO_STRUCT(gf); gf.in.file.handle = h; gf.in.info_type = SMB2_GETINFO_FILE; gf.in.info_class = 0x16; gf.in.output_buffer_length = 0x1000; gf.in.input_buffer_length = 0; req[1] = smb2_getinfo_send(tree, &gf); status = smb2_create_recv(req[0], tree, &io2); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_getinfo_recv(req[1], tree, &gf); CHECK_STATUS(status, NT_STATUS_OK); done: smb2_util_close(tree, h1); smb2_util_unlink(tree, fname1); return ret; }
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; }
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; }
static bool test_compound_related3(struct torture_context *tctx, struct smb2_tree *tree) { struct smb2_handle hd; struct smb2_ioctl io; struct smb2_create cr; struct smb2_close cl; const char *fname = "compound_related3.dat"; struct smb2_request *req[3]; NTSTATUS status; bool ret = false; smb2_util_unlink(tree, fname); ZERO_STRUCT(cr); cr.in.security_flags = 0x00; cr.in.oplock_level = 0; cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; cr.in.create_flags = 0x00000000; cr.in.reserved = 0x00000000; cr.in.desired_access = SEC_RIGHTS_FILE_ALL; cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL; cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF; cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY | NTCREATEX_OPTIONS_ASYNC_ALERT | NTCREATEX_OPTIONS_NON_DIRECTORY_FILE | 0x00200000; cr.in.fname = fname; smb2_transport_compound_start(tree->session->transport, 3); req[0] = smb2_create_send(tree, &cr); hd.data[0] = UINT64_MAX; hd.data[1] = UINT64_MAX; smb2_transport_compound_set_related(tree->session->transport, true); ZERO_STRUCT(io); io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID; io.in.file.handle = hd; io.in.unknown2 = 0; io.in.max_response_size = 64; io.in.flags = 1; req[1] = smb2_ioctl_send(tree, &io); ZERO_STRUCT(cl); cl.in.file.handle = hd; req[2] = smb2_close_send(tree, &cl); status = smb2_create_recv(req[0], tree, &cr); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_ioctl_recv(req[1], tree, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_close_recv(req[2], &cl); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_unlink(tree, fname); CHECK_STATUS(status, NT_STATUS_OK); ret = true; done: return ret; }