bool torture_samba3_rootdirfid(struct torture_context *tctx, struct smbcli_state *cli) { uint16_t dnum; union smb_open io; const char *fname = "testfile"; bool ret = false; smbcli_unlink(cli->tree, fname); ZERO_STRUCT(io); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.access_mask = SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_READ; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.fname = "\\"; torture_assert_ntstatus_equal_goto(tctx, smb_raw_open(cli->tree, tctx, &io), NT_STATUS_OK, ret, done, "smb_open on the directory failed: %s\n"); dnum = io.ntcreatex.out.file.fnum; io.ntcreatex.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; io.ntcreatex.in.root_fid.fnum = dnum; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF; 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.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.fname = fname; torture_assert_ntstatus_equal_goto(tctx, smb_raw_open(cli->tree, tctx, &io), NT_STATUS_OK, ret, done, "smb_open on the file failed"); smbcli_close(cli->tree, io.ntcreatex.out.file.fnum); smbcli_close(cli->tree, dnum); smbcli_unlink(cli->tree, fname); ret = true; done: return ret; }
/* create a directory, returning a handle to it */ NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum) { NTSTATUS status; union smb_open io; TALLOC_CTX *mem_ctx; mem_ctx = talloc_named_const(tree, 0, "create_directory_handle"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = dname; status = smb_raw_open(tree, mem_ctx, &io); talloc_free(mem_ctx); if (NT_STATUS_IS_OK(status)) { *fnum = io.ntcreatex.out.file.fnum; } return status; }
static NTSTATUS raw_smbcli_ntcreate(struct smbcli_tree *tree, const char *fname, int *fnum) { union smb_open io; TALLOC_CTX *mem_ctx; NTSTATUS status; mem_ctx = talloc_init("raw_t2open"); if (!mem_ctx) return NT_STATUS_NO_MEMORY; memset(&io, '\0', sizeof(io)); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; 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_READ | NTCREATEX_SHARE_ACCESS_WRITE; 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; status = smb_raw_open(tree, mem_ctx, &io); talloc_free(mem_ctx); if (fnum && NT_STATUS_IS_OK(status)) { *fnum = io.openx.out.file.fnum; } return status; }
bool torture_samba3_oplock_logoff(struct torture_context *tctx, struct smbcli_state *cli) { union smb_open io; const char *fname = "testfile"; bool ret = false; struct smbcli_request *req; struct smb_echo echo_req; smbcli_unlink(cli->tree, fname); ZERO_STRUCT(io); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.access_mask = SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE; 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_OPEN_IF; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.fname = "testfile"; torture_assert_ntstatus_equal_goto(tctx, smb_raw_open(cli->tree, tctx, &io), NT_STATUS_OK, ret, done, "first smb_open on the file failed"); /* * Create a conflicting open, causing the one-second delay */ torture_assert_goto(tctx, req = smb_raw_open_send(cli->tree, &io), ret, done, "smb_raw_open_send on the file failed"); /* * Pull the VUID from under that request. As of Nov 3, 2008 all Samba3 * versions (3.0, 3.2 and master) would spin sending ERRinvuid errors * as long as the client is still connected. */ torture_assert_ntstatus_equal_goto(tctx, smb_raw_ulogoff(cli->session), NT_STATUS_OK, ret, done, "ulogoff failed failed"); echo_req.in.repeat_count = 1; echo_req.in.size = 1; echo_req.in.data = discard_const_p(uint8_t, ""); torture_assert_ntstatus_equal_goto(tctx, smb_raw_echo(cli->session->transport, &echo_req), NT_STATUS_OK, ret, done, "smb_raw_echo failed"); ret = true; done: return ret; }
/* open a file N times on the server and just hold them open used for testing performance when there are N file handles alopenn */ bool torture_holdopen(struct torture_context *tctx, struct smbcli_state *cli) { int i, fnum; const char *fname = "\\holdopen.dat"; NTSTATUS status; smbcli_unlink(cli->tree, fname); fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); if (fnum == -1) { torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); return false; } smbcli_close(cli->tree, fnum); for (i=0;i<torture_numops;i++) { union smb_open op; op.generic.level = RAW_OPEN_NTCREATEX; op.ntcreatex.in.root_fid.fnum = 0; op.ntcreatex.in.flags = 0; op.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; op.ntcreatex.in.create_options = 0; op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; op.ntcreatex.in.alloc_size = 0; op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; op.ntcreatex.in.security_flags = 0; op.ntcreatex.in.fname = fname; status = smb_raw_open(cli->tree, tctx, &op); if (!NT_STATUS_IS_OK(status)) { torture_warning(tctx, "open %d failed\n", i); continue; } if (torture_setting_bool(tctx, "progress", true)) { torture_comment(tctx, "opened %d file\r", i); fflush(stdout); } } torture_comment(tctx, "\nStarting pings\n"); while (1) { struct smb_echo ec; status = smb_raw_echo(cli->transport, &ec); torture_comment(tctx, "."); fflush(stdout); sleep(15); } return true; }
/* open a file using a set of unicode code points for the name the prefix BASEDIR is added before the name */ static NTSTATUS unicode_open(struct torture_context *tctx, struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, uint32_t open_disposition, const uint32_t *u_name, size_t u_name_len) { union smb_open io; char *fname, *fname2=NULL, *ucs_name; int i; NTSTATUS status; ucs_name = talloc_size(mem_ctx, (1+u_name_len)*2); if (!ucs_name) { printf("Failed to create UCS2 Name - talloc() failure\n"); return NT_STATUS_NO_MEMORY; } for (i=0;i<u_name_len;i++) { SSVAL(ucs_name, i*2, u_name[i]); } SSVAL(ucs_name, i*2, 0); i = convert_string_talloc(ucs_name, CH_UTF16, CH_UNIX, ucs_name, (1+u_name_len)*2, (void **)&fname); if (i == -1) { torture_comment(tctx, "Failed to convert UCS2 Name into unix - convert_string_talloc() failure\n"); talloc_free(ucs_name); return NT_STATUS_NO_MEMORY; } fname2 = talloc_asprintf(ucs_name, "%s%s", BASEDIR, fname); if (!fname2) { talloc_free(ucs_name); return NT_STATUS_NO_MEMORY; } io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.root_fid = 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 = fname2; io.ntcreatex.in.open_disposition = open_disposition; status = smb_raw_open(tree, mem_ctx, &io); talloc_free(ucs_name); return status; }
/* This test checks that 1) the server does not allow an unlink on a file that is open */ BOOL torture_unlinktest(struct torture_context *tctx, struct smbcli_state *cli) { const char *fname = BASEDIR "\\unlink.tst"; int fnum; BOOL correct = True; union smb_open io; NTSTATUS status; torture_assert(tctx, torture_setup_dir(cli, BASEDIR), talloc_asprintf(tctx, "Failed setting up %s", BASEDIR)); cli->session->pid = 1; torture_comment(tctx, "Opening a file\n"); fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, "open of %s failed (%s)", fname, smbcli_errstr(cli->tree))); torture_comment(tctx, "Unlinking a open file\n"); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlink(cli->tree, fname)), "server allowed unlink on an open file"); correct = check_error(__location__, cli, ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); smbcli_close(cli->tree, fnum); smbcli_unlink(cli->tree, fname); torture_comment(tctx, "testing unlink after ntcreatex with DELETE access\n"); io.ntcreatex.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE; io.ntcreatex.in.file_attr = 0; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; status = smb_raw_open(cli->tree, cli, &io); torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "failed to open %s", fname)); torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlink(cli->tree, fname)), "server allowed unlink on an open file"); correct = check_error(__location__, cli, ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); return correct; }
/* open a file */ static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_open *io) { struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; struct ntvfs_handle *h; struct cvfs_file *f; NTSTATUS status; SETUP_PID; if (io->generic.level != RAW_OPEN_GENERIC && p->map_generic) { return ntvfs_map_open(ntvfs, req, io); } status = ntvfs_handle_new(ntvfs, req, &h); NT_STATUS_NOT_OK_RETURN(status); f = talloc_zero(h, struct cvfs_file); NT_STATUS_HAVE_NO_MEMORY(f); f->h = h; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { union smb_handle *file; status = smb_raw_open(p->tree, req, io); NT_STATUS_NOT_OK_RETURN(status); SMB_OPEN_OUT_FILE(io, file); f->fnum = file->fnum; file->ntvfs = NULL; status = ntvfs_handle_set_backend_data(f->h, p->ntvfs, f); NT_STATUS_NOT_OK_RETURN(status); file->ntvfs = f->h; DLIST_ADD(p->files, f); return NT_STATUS_OK; } c_req = smb_raw_open_send(p->tree, io); ASYNC_RECV_TAIL_F(io, async_open, f); }
bool torture_raw_qfileinfo_pipe(struct torture_context *torture, struct smbcli_state *cli) { bool ret = true; int fnum; const char *fname = "\\lsass"; union smb_open op; NTSTATUS status; op.ntcreatex.level = RAW_OPEN_NTCREATEX; op.ntcreatex.in.flags = 0; op.ntcreatex.in.root_fid.fnum = 0; op.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL | SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_EA | SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA; op.ntcreatex.in.file_attr = 0; op.ntcreatex.in.alloc_size = 0; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; op.ntcreatex.in.create_options = 0; op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION; op.ntcreatex.in.security_flags = 0; op.ntcreatex.in.fname = fname; status = smb_raw_open(cli->tree, torture, &op); torture_assert_ntstatus_ok(torture, status, "smb_raw_open failed"); fnum = op.ntcreatex.out.file.fnum; ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, true /* is_ipc */); smbcli_close(cli->tree, fnum); return ret; }
/* test disconnect after async open */ static bool test_disconnect_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_open io; struct smbcli_request *req1, *req2; NTSTATUS status; printf("trying open/disconnect\n"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = BASEDIR "\\open.dat"; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); io.ntcreatex.in.share_access = 0; req1 = smb_raw_open_send(cli->tree, &io); req2 = smb_raw_open_send(cli->tree, &io); if (!req1 || !req2) { printf("test_disconnect_open: smb_raw_open_send() " "returned NULL\n"); return false; } status = smbcli_chkpath(cli->tree, "\\"); CHECK_STATUS(status, NT_STATUS_OK); talloc_free(cli); return true; }
static bool test_osxrename(struct torture_context *tctx, struct smbcli_state *cli) { union smb_rename io; union smb_unlink io_un; NTSTATUS status; bool ret = true; int fnum = -1; const char *fname1 = BASEDIR "\\test1"; const char *FNAME1 = BASEDIR "\\TEST1"; union smb_fileinfo finfo; union smb_open op; torture_comment(tctx, "\nTesting OSX Rename\n"); if (!torture_setup_dir(cli, BASEDIR)) { return false; } op.generic.level = RAW_OPEN_NTCREATEX; op.ntcreatex.in.root_fid.fnum = 0; op.ntcreatex.in.flags = 0; op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; op.ntcreatex.in.create_options = 0; op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; op.ntcreatex.in.alloc_size = 0; op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; op.ntcreatex.in.security_flags = 0; op.ntcreatex.in.fname = fname1; status = smb_raw_open(cli->tree, tctx, &op); CHECK_STATUS(status, NT_STATUS_OK); fnum = op.ntcreatex.out.file.fnum; io.generic.level = RAW_RENAME_RENAME; io.rename.in.attrib = 0; smbcli_close(cli->tree, fnum); /* Rename by changing case. First check for the * existence of the file with the "newname". * If we find one and both the output and input are same case, * delete it. */ torture_comment(tctx, "Checking os X rename (case changing)\n"); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.path = FNAME1; torture_comment(tctx, "Looking for file %s \n",FNAME1); status = smb_raw_pathinfo(cli->tree, tctx, &finfo); if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) { torture_comment(tctx, "Name of the file found %s \n", finfo.all_info.out.fname.s); if (strcmp(finfo.all_info.out.fname.s, finfo.all_info.in.file.path) == 0) { /* If file is found with the same case delete it */ torture_comment(tctx, "Deleting File %s \n", finfo.all_info.out.fname.s); io_un.unlink.in.pattern = finfo.all_info.out.fname.s; io_un.unlink.in.attrib = 0; status = smb_raw_unlink(cli->tree, &io_un); CHECK_STATUS(status, NT_STATUS_OK); } } io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = FNAME1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "File name after rename %s \n",finfo.all_info.out.fname.s); done: smbcli_close(cli->tree, fnum); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
static NTSTATUS raw_smbcli_t2open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum) { union smb_open io; unsigned int openfn=0; unsigned int accessmode=0; TALLOC_CTX *mem_ctx; NTSTATUS status; mem_ctx = talloc_init("raw_t2open"); if (!mem_ctx) return NT_STATUS_NO_MEMORY; if (flags & O_CREAT) { openfn |= OPENX_OPEN_FUNC_CREATE; } if (!(flags & O_EXCL)) { if (flags & O_TRUNC) { openfn |= OPENX_OPEN_FUNC_TRUNC; } else { openfn |= OPENX_OPEN_FUNC_OPEN; } } accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT); if ((flags & O_ACCMODE) == O_RDWR) { accessmode |= OPENX_MODE_ACCESS_RDWR; } else if ((flags & O_ACCMODE) == O_WRONLY) { accessmode |= OPENX_MODE_ACCESS_WRITE; } else if ((flags & O_ACCMODE) == O_RDONLY) { accessmode |= OPENX_MODE_ACCESS_READ; } #if defined(O_SYNC) if ((flags & O_SYNC) == O_SYNC) { accessmode |= OPENX_MODE_WRITE_THRU; } #endif if (share_mode == DENY_FCB) { accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB; } memset(&io, '\0', sizeof(io)); io.t2open.level = RAW_OPEN_T2OPEN; io.t2open.in.flags = 0; io.t2open.in.open_mode = accessmode; io.t2open.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; io.t2open.in.file_attrs = 0; io.t2open.in.write_time = 0; io.t2open.in.open_func = openfn; io.t2open.in.size = 0; io.t2open.in.timeout = 0; io.t2open.in.fname = fname; io.t2open.in.num_eas = 1; io.t2open.in.eas = talloc_array(mem_ctx, struct ea_struct, io.t2open.in.num_eas); io.t2open.in.eas[0].flags = 0; io.t2open.in.eas[0].name.s = ".CLASSINFO"; io.t2open.in.eas[0].value = data_blob_talloc(mem_ctx, "first value", 11); status = smb_raw_open(tree, mem_ctx, &io); talloc_free(mem_ctx); if (fnum && NT_STATUS_IS_OK(status)) { *fnum = io.openx.out.file.fnum; } return status; }
/* test tree ops */ static bool test_tree(struct smbcli_state *cli, struct torture_context *tctx) { NTSTATUS status; bool ret = true; const char *share, *host; struct smbcli_tree *tree; union smb_tcon tcon; union smb_open io; union smb_write wr; union smb_close cl; int fnum; const char *fname = BASEDIR "\\test.txt"; uint8_t c = 1; printf("TESTING TREE HANDLING\n"); if (!torture_setup_dir(cli, BASEDIR)) { return false; } share = torture_setting_string(tctx, "share", NULL); host = torture_setting_string(tctx, "host", NULL); printf("create a second tree context on the same session\n"); tree = smbcli_tree_init(cli->session, tctx, false); tcon.generic.level = RAW_TCON_TCONX; tcon.tconx.in.flags = 0; tcon.tconx.in.password = data_blob(NULL, 0); tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share); tcon.tconx.in.device = "A:"; status = smb_raw_tcon(tree, tctx, &tcon); CHECK_STATUS(status, NT_STATUS_OK); tree->tid = tcon.tconx.out.tid; printf("tid1=%d tid2=%d\n", cli->tree->tid, tree->tid); printf("try a tconx with a bad device type\n"); tcon.tconx.in.device = "FOO"; status = smb_raw_tcon(tree, tctx, &tcon); CHECK_STATUS(status, NT_STATUS_BAD_DEVICE_TYPE); printf("create a file using the new tid\n"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; status = smb_raw_open(tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; printf("write using the old tid\n"); wr.generic.level = RAW_WRITE_WRITEX; wr.writex.in.file.fnum = fnum; wr.writex.in.offset = 0; wr.writex.in.wmode = 0; wr.writex.in.remaining = 0; wr.writex.in.count = 1; wr.writex.in.data = &c; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("write with the new tid\n"); status = smb_raw_write(tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("disconnect the new tid\n"); status = smb_tree_disconnect(tree); CHECK_STATUS(status, NT_STATUS_OK); printf("the new tid should not now be accessible\n"); status = smb_raw_write(tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("the fnum should have been auto-closed\n"); cl.close.level = RAW_CLOSE_CLOSE; cl.close.in.file.fnum = fnum; cl.close.in.write_time = 0; status = smb_raw_close(cli->tree, &cl); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); /* close down the new tree */ talloc_free(tree); done: return ret; }
bool torture_samba3_checkfsp(struct torture_context *torture, struct smbcli_state *cli) { const char *fname = "test.txt"; const char *dirname = "testdir"; int fnum; NTSTATUS status; bool ret = true; TALLOC_CTX *mem_ctx; ssize_t nread; char buf[16]; struct smbcli_tree *tree2; torture_assert(torture, mem_ctx = talloc_init("torture_samba3_checkfsp"), "talloc_init failed\n"); torture_assert_ntstatus_equal(torture, torture_second_tcon(torture, cli->session, torture_setting_string(torture, "share", NULL), &tree2), NT_STATUS_OK, "creating second tcon"); /* Try a read on an invalid FID */ nread = smbcli_read(cli->tree, 4711, buf, 0, sizeof(buf)); CHECK_STATUS(torture, smbcli_nt_error(cli->tree), NT_STATUS_INVALID_HANDLE); /* Try a read on a directory handle */ torture_assert(torture, torture_setup_dir(cli, dirname), "creating test directory"); /* Open the directory */ { union smb_open io; io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_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_OPEN; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.fname = dirname; status = smb_raw_open(cli->tree, mem_ctx, &io); if (!NT_STATUS_IS_OK(status)) { torture_result(torture, TORTURE_FAIL, "smb_open on the directory failed: %s\n", nt_errstr(status)); ret = false; goto done; } fnum = io.ntcreatex.out.file.fnum; } /* Try a read on the directory */ nread = smbcli_read(cli->tree, fnum, buf, 0, sizeof(buf)); if (nread >= 0) { torture_result(torture, TORTURE_FAIL, "smbcli_read on a directory succeeded, expected " "failure\n"); ret = false; } CHECK_STATUS(torture, smbcli_nt_error(cli->tree), NT_STATUS_INVALID_DEVICE_REQUEST); /* Same test on the second tcon */ nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf)); if (nread >= 0) { torture_result(torture, TORTURE_FAIL, "smbcli_read on a directory succeeded, expected " "failure\n"); ret = false; } CHECK_STATUS(torture, smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE); smbcli_close(cli->tree, fnum); /* Try a normal file read on a second tcon */ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); if (fnum == -1) { torture_result(torture, TORTURE_FAIL, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); ret = false; goto done; } nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf)); CHECK_STATUS(torture, smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE); smbcli_close(cli->tree, fnum); done: smbcli_deltree(cli->tree, dirname); talloc_free(mem_ctx); return ret; }
static NTSTATUS raw_smbcli_open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum) { union smb_open open_parms; unsigned int openfn=0; unsigned int accessmode=0; TALLOC_CTX *mem_ctx; NTSTATUS status; mem_ctx = talloc_init("raw_open"); if (!mem_ctx) return NT_STATUS_NO_MEMORY; if (flags & O_CREAT) { openfn |= OPENX_OPEN_FUNC_CREATE; } if (!(flags & O_EXCL)) { if (flags & O_TRUNC) { openfn |= OPENX_OPEN_FUNC_TRUNC; } else { openfn |= OPENX_OPEN_FUNC_OPEN; } } accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT); if ((flags & O_ACCMODE) == O_RDWR) { accessmode |= OPENX_MODE_ACCESS_RDWR; } else if ((flags & O_ACCMODE) == O_WRONLY) { accessmode |= OPENX_MODE_ACCESS_WRITE; } else if ((flags & O_ACCMODE) == O_RDONLY) { accessmode |= OPENX_MODE_ACCESS_READ; } #if defined(O_SYNC) if ((flags & O_SYNC) == O_SYNC) { accessmode |= OPENX_MODE_WRITE_THRU; } #endif if (share_mode == DENY_FCB) { accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB; } open_parms.openx.level = RAW_OPEN_OPENX; open_parms.openx.in.flags = 0; open_parms.openx.in.open_mode = accessmode; open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; open_parms.openx.in.file_attrs = 0; open_parms.openx.in.write_time = 0; open_parms.openx.in.open_func = openfn; open_parms.openx.in.size = 0; open_parms.openx.in.timeout = 0; open_parms.openx.in.fname = fname; status = smb_raw_open(tree, mem_ctx, &open_parms); talloc_free(mem_ctx); if (fnum && NT_STATUS_IS_OK(status)) { *fnum = open_parms.openx.out.file.fnum; } return status; }
/* test pid ops with 2 tcons */ static BOOL test_pid_2tcon(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { NTSTATUS status; BOOL ret = True; const char *share, *host; struct smbcli_tree *tree; union smb_tcon tcon; union smb_open io; union smb_write wr; union smb_close cl; int fnum1, fnum2; const char *fname1 = BASEDIR "\\test1.txt"; const char *fname2 = BASEDIR "\\test2.txt"; uint8_t c = 1; uint16_t tid1, tid2; printf("TESTING PID HANDLING WITH 2 TCONS\n"); if (!torture_setup_dir(cli, BASEDIR)) { return False; } share = lp_parm_string(-1, "torture", "share"); host = lp_parm_string(-1, "torture", "host"); printf("create a second tree context on the same session\n"); tree = smbcli_tree_init(cli->session, mem_ctx, False); tcon.generic.level = RAW_TCON_TCONX; tcon.tconx.in.flags = 0; tcon.tconx.in.password = data_blob(NULL, 0); tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", host, share); tcon.tconx.in.device = "A:"; status = smb_raw_tcon(tree, mem_ctx, &tcon); CHECK_STATUS(status, NT_STATUS_OK); tree->tid = tcon.tconx.out.tid; tid1 = cli->tree->tid; tid2 = tree->tid; printf("tid1=%d tid2=%d\n", tid1, tid2); printf("create a file using the tid1\n"); cli->tree->tid = tid1; io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname1; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum1 = io.ntcreatex.out.file.fnum; printf("write using the tid1\n"); wr.generic.level = RAW_WRITE_WRITEX; wr.writex.in.file.fnum = fnum1; wr.writex.in.offset = 0; wr.writex.in.wmode = 0; wr.writex.in.remaining = 0; wr.writex.in.count = 1; wr.writex.in.data = &c; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("create a file using the tid2\n"); cli->tree->tid = tid2; io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname2; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum2 = io.ntcreatex.out.file.fnum; printf("write using the tid2\n"); wr.generic.level = RAW_WRITE_WRITEX; wr.writex.in.file.fnum = fnum2; wr.writex.in.offset = 0; wr.writex.in.wmode = 0; wr.writex.in.remaining = 0; wr.writex.in.count = 1; wr.writex.in.data = &c; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("exit the pid\n"); status = smb_raw_exit(cli->session); CHECK_STATUS(status, NT_STATUS_OK); printf("the fnum1 on tid1 should not be accessible\n"); cli->tree->tid = tid1; wr.writex.in.file.fnum = fnum1; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("the fnum1 on tid1 should have been auto-closed\n"); cl.close.level = RAW_CLOSE_CLOSE; cl.close.in.file.fnum = fnum1; cl.close.in.write_time = 0; status = smb_raw_close(cli->tree, &cl); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("the fnum2 on tid2 should not be accessible\n"); cli->tree->tid = tid2; wr.writex.in.file.fnum = fnum2; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("the fnum2 on tid2 should have been auto-closed\n"); cl.close.level = RAW_CLOSE_CLOSE; cl.close.in.file.fnum = fnum2; cl.close.in.write_time = 0; status = smb_raw_close(cli->tree, &cl); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); done: return ret; }
/* * Test for maximum ea size - more than one ea name is checked. * * Additional parameters can be passed, to allow further testing: * * default * maxeasize 65536 limit the max. size for a single EA name * maxeanames 101 limit of the number of tested names * maxeastart 1 this EA size is used to test for the 1st EA (atm) * maxeadebug 0 if set true, further debug output is done - in addition * the testfile is not deleted for further inspection! * * Set some/all of these options on the cmdline with: * --option torture:maxeasize=1024 --option torture:maxeadebug=1 ... * */ static bool test_max_eas(struct smbcli_state *cli, struct torture_context *tctx) { NTSTATUS status; union smb_open io; const char *fname = BASEDIR "\\ea_max.txt"; int fnum = -1; bool ret = true; bool err = false; int i, j, k, last, total; DATA_BLOB eablob; char *eaname = NULL; int maxeasize; int maxeanames; int maxeastart; torture_comment(tctx, "TESTING SETFILEINFO MAX. EA_SET\n"); maxeasize = torture_setting_int(tctx, "maxeasize", 65536); maxeanames = torture_setting_int(tctx, "maxeanames", 101); maxeastart = torture_setting_int(tctx, "maxeastart", 1); maxeadebug = torture_setting_int(tctx, "maxeadebug", 0); /* Do some sanity check on possibly passed parms */ if (maxeasize <= 0) { torture_comment(tctx, "Invalid parameter 'maxeasize=%d'",maxeasize); err = true; } if (maxeanames <= 0) { torture_comment(tctx, "Invalid parameter 'maxeanames=%d'",maxeanames); err = true; } if (maxeastart <= 0) { torture_comment(tctx, "Invalid parameter 'maxeastart=%d'",maxeastart); err = true; } if (maxeadebug < 0) { torture_comment(tctx, "Invalid parameter 'maxeadebug=%d'",maxeadebug); err = true; } if (err) { torture_comment(tctx, "\n\n"); goto done; } if (maxeastart > maxeasize) { maxeastart = maxeasize; torture_comment(tctx, "'maxeastart' outside range - corrected to %d\n", maxeastart); } torture_comment(tctx, "MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d" " maxeadebug=%d\n", maxeasize, maxeanames, maxeastart, maxeadebug); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; status = smb_raw_open(cli->tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; eablob = data_blob_talloc(tctx, NULL, maxeasize); if (eablob.data == NULL) { goto done; } /* * Fill in some EA data - the offset could be easily checked * during a hexdump. */ for (i = 0, k = 0; i < eablob.length / 4; i++, k+=4) { eablob.data[k] = k & 0xff; eablob.data[k+1] = (k >> 8) & 0xff; eablob.data[k+2] = (k >> 16) & 0xff; eablob.data[k+3] = (k >> 24) & 0xff; } i = eablob.length % 4; if (i-- > 0) { eablob.data[k] = k & 0xff; if (i-- > 0) { eablob.data[k+1] = (k >> 8) & 0xff; if (i-- > 0) { eablob.data[k+2] = (k >> 16) & 0xff; }
bool torture_samba3_oplock_logoff(struct torture_context *tctx) { struct smbcli_state *cli; NTSTATUS status; uint16_t fnum1; union smb_open io; const char *fname = "testfile"; bool ret = false; struct smbcli_request *req; struct smb_echo echo_req; if (!torture_open_connection(&cli, tctx, 0)) { ret = false; goto done; } smbcli_unlink(cli->tree, fname); ZERO_STRUCT(io); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.access_mask = SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE; 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_OPEN_IF; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.fname = "testfile"; status = smb_raw_open(cli->tree, tctx, &io); if (!NT_STATUS_IS_OK(status)) { d_printf("first smb_open failed: %s\n", nt_errstr(status)); ret = false; goto done; } fnum1 = io.ntcreatex.out.file.fnum; /* * Create a conflicting open, causing the one-second delay */ req = smb_raw_open_send(cli->tree, &io); if (req == NULL) { d_printf("smb_raw_open_send failed\n"); ret = false; goto done; } /* * Pull the VUID from under that request. As of Nov 3, 2008 all Samba3 * versions (3.0, 3.2 and master) would spin sending ERRinvuid errors * as long as the client is still connected. */ status = smb_raw_ulogoff(cli->session); if (!NT_STATUS_IS_OK(status)) { d_printf("ulogoff failed: %s\n", nt_errstr(status)); ret = false; goto done; } echo_req.in.repeat_count = 1; echo_req.in.size = 1; echo_req.in.data = discard_const_p(uint8_t, ""); status = smb_raw_echo(cli->session->transport, &echo_req); if (!NT_STATUS_IS_OK(status)) { d_printf("smb_raw_echo returned %s\n", nt_errstr(status)); ret = false; goto done; } ret = true; done: return ret; }
/* test pid ops with 2 sessions */ static BOOL test_pid_2sess(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { NTSTATUS status; BOOL ret = True; struct smbcli_session *session; struct smb_composite_sesssetup setup; union smb_open io; union smb_write wr; union smb_close cl; int fnum; const char *fname = BASEDIR "\\test.txt"; uint8_t c = 1; uint16_t vuid1, vuid2; printf("TESTING PID HANDLING WITH 2 SESSIONS\n"); if (!torture_setup_dir(cli, BASEDIR)) { return False; } printf("create a second security context on the same transport\n"); session = smbcli_session_init(cli->transport, mem_ctx, False); setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */ setup.in.workgroup = lp_workgroup(); setup.in.credentials = cmdline_credentials; status = smb_composite_sesssetup(session, &setup); CHECK_STATUS(status, NT_STATUS_OK); session->vuid = setup.out.vuid; vuid1 = cli->session->vuid; vuid2 = session->vuid; printf("vuid1=%d vuid2=%d\n", vuid1, vuid2); printf("create a file using the vuid1\n"); cli->session->vuid = vuid1; io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; printf("write using the vuid1 (fnum=%d)\n", fnum); cli->session->vuid = vuid1; wr.generic.level = RAW_WRITE_WRITEX; wr.writex.in.file.fnum = fnum; wr.writex.in.offset = 0; wr.writex.in.wmode = 0; wr.writex.in.remaining = 0; wr.writex.in.count = 1; wr.writex.in.data = &c; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("exit the pid with vuid2\n"); cli->session->vuid = vuid2; status = smb_raw_exit(cli->session); CHECK_STATUS(status, NT_STATUS_OK); printf("the fnum should still be accessible\n"); cli->session->vuid = vuid1; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("exit the pid with vuid1\n"); cli->session->vuid = vuid1; status = smb_raw_exit(cli->session); CHECK_STATUS(status, NT_STATUS_OK); printf("the fnum should not now be accessible\n"); status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("the fnum should have been auto-closed\n"); cl.close.level = RAW_CLOSE_CLOSE; cl.close.in.file.fnum = fnum; cl.close.in.write_time = 0; status = smb_raw_close(cli->tree, &cl); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); done: return ret; }
/* test dir rename. */ static bool test_dir_rename(struct torture_context *tctx, struct smbcli_state *cli) { union smb_open io; union smb_rename ren_io; NTSTATUS status; const char *dname1 = BASEDIR "\\dir_for_rename"; const char *dname2 = BASEDIR "\\renamed_dir"; const char *dname1_long = BASEDIR "\\dir_for_rename_long"; const char *fname = BASEDIR "\\dir_for_rename\\file.txt"; const char *sname = BASEDIR "\\renamed_dir:a stream:$DATA"; bool ret = true; int fnum = -1; torture_comment(tctx, "Checking rename on a directory containing an open file.\n"); if (!torture_setup_dir(cli, BASEDIR)) { return false; } /* create a directory */ smbcli_rmdir(cli->tree, dname1); smbcli_rmdir(cli->tree, dname2); smbcli_rmdir(cli->tree, dname1_long); smbcli_unlink(cli->tree, dname1); smbcli_unlink(cli->tree, dname2); smbcli_unlink(cli->tree, dname1_long); ZERO_STRUCT(io); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; io.ntcreatex.in.fname = dname1; status = smb_raw_open(cli->tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; smbcli_close(cli->tree, fnum); /* create the longname directory */ io.ntcreatex.in.fname = dname1_long; status = smb_raw_open(cli->tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; smbcli_close(cli->tree, fnum); /* Now create and hold open a file. */ ZERO_STRUCT(io); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE; 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; /* Create the file. */ status = smb_raw_open(cli->tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; /* Now try and rename the directory. */ ZERO_STRUCT(ren_io); ren_io.generic.level = RAW_RENAME_RENAME; ren_io.rename.in.pattern1 = dname1; ren_io.rename.in.pattern2 = dname2; ren_io.rename.in.attrib = 0; status = smb_raw_rename(cli->tree, &ren_io); CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); /* Close the file and try the rename. */ smbcli_close(cli->tree, fnum); status = smb_raw_rename(cli->tree, &ren_io); CHECK_STATUS(status, NT_STATUS_OK); /* * Now try just holding a second handle on the directory and holding * it open across a rename. This should be allowed. */ io.ntcreatex.in.fname = dname2; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL | SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_EA | SEC_FILE_READ_DATA; status = smb_raw_open(cli->tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; ren_io.generic.level = RAW_RENAME_RENAME; ren_io.rename.in.pattern1 = dname2; ren_io.rename.in.pattern2 = dname1; ren_io.rename.in.attrib = 0; status = smb_raw_rename(cli->tree, &ren_io); CHECK_STATUS(status, NT_STATUS_OK); /* close our handle to the directory. */ smbcli_close(cli->tree, fnum); /* Open a handle on the long name, and then * try a rename. This would catch a regression * in bug #6781. */ io.ntcreatex.in.fname = dname1_long; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL | SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_EA | SEC_FILE_READ_DATA; status = smb_raw_open(cli->tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; ren_io.generic.level = RAW_RENAME_RENAME; ren_io.rename.in.pattern1 = dname1; ren_io.rename.in.pattern2 = dname2; ren_io.rename.in.attrib = 0; status = smb_raw_rename(cli->tree, &ren_io); CHECK_STATUS(status, NT_STATUS_OK); /* close our handle to the longname directory. */ smbcli_close(cli->tree, fnum); /* * Now try opening a stream on the directory and holding it open * across a rename. This should be allowed. */ io.ntcreatex.in.fname = sname; status = smb_raw_open(cli->tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; ren_io.generic.level = RAW_RENAME_RENAME; ren_io.rename.in.pattern1 = dname2; ren_io.rename.in.pattern2 = dname1; ren_io.rename.in.attrib = 0; status = smb_raw_rename(cli->tree, &ren_io); CHECK_STATUS(status, NT_STATUS_OK); done: if (fnum != -1) { smbcli_close(cli->tree, fnum); } smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
static bool test_eas(struct smbcli_state *cli, struct torture_context *tctx) { NTSTATUS status; union smb_setfileinfo setfile; union smb_open io; const char *fname = BASEDIR "\\ea.txt"; bool ret = true; int fnum = -1; torture_comment(tctx, "TESTING SETFILEINFO EA_SET\n"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; status = smb_raw_open(cli->tree, tctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; ret &= check_ea(cli, fname, "EAONE", NULL); torture_comment(tctx, "Adding first two EAs\n"); setfile.generic.level = RAW_SFILEINFO_EA_SET; setfile.generic.in.file.fnum = fnum; setfile.ea_set.in.num_eas = 2; setfile.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2); setfile.ea_set.in.eas[0].flags = 0; setfile.ea_set.in.eas[0].name.s = "EAONE"; setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1"); setfile.ea_set.in.eas[1].flags = 0; setfile.ea_set.in.eas[1].name.s = "SECONDEA"; setfile.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo"); status = smb_raw_setfileinfo(cli->tree, &setfile); CHECK_STATUS(status, NT_STATUS_OK); ret &= check_ea(cli, fname, "EAONE", "VALUE1"); ret &= check_ea(cli, fname, "SECONDEA", "ValueTwo"); torture_comment(tctx, "Modifying 2nd EA\n"); setfile.ea_set.in.num_eas = 1; setfile.ea_set.in.eas[0].name.s = "SECONDEA"; setfile.ea_set.in.eas[0].value = data_blob_string_const(" Changed Value"); status = smb_raw_setfileinfo(cli->tree, &setfile); CHECK_STATUS(status, NT_STATUS_OK); ret &= check_ea(cli, fname, "EAONE", "VALUE1"); ret &= check_ea(cli, fname, "SECONDEA", " Changed Value"); torture_comment(tctx, "Setting a NULL EA\n"); setfile.ea_set.in.eas[0].value = data_blob(NULL, 0); setfile.ea_set.in.eas[0].name.s = "NULLEA"; status = smb_raw_setfileinfo(cli->tree, &setfile); CHECK_STATUS(status, NT_STATUS_OK); ret &= check_ea(cli, fname, "EAONE", "VALUE1"); ret &= check_ea(cli, fname, "SECONDEA", " Changed Value"); ret &= check_ea(cli, fname, "NULLEA", NULL); torture_comment(tctx, "Deleting first EA\n"); setfile.ea_set.in.eas[0].flags = 0; setfile.ea_set.in.eas[0].name.s = "EAONE"; setfile.ea_set.in.eas[0].value = data_blob(NULL, 0); status = smb_raw_setfileinfo(cli->tree, &setfile); CHECK_STATUS(status, NT_STATUS_OK); ret &= check_ea(cli, fname, "EAONE", NULL); ret &= check_ea(cli, fname, "SECONDEA", " Changed Value"); torture_comment(tctx, "Deleting second EA\n"); setfile.ea_set.in.eas[0].flags = 0; setfile.ea_set.in.eas[0].name.s = "SECONDEA"; setfile.ea_set.in.eas[0].value = data_blob(NULL, 0); status = smb_raw_setfileinfo(cli->tree, &setfile); CHECK_STATUS(status, NT_STATUS_OK); ret &= check_ea(cli, fname, "EAONE", NULL); ret &= check_ea(cli, fname, "SECONDEA", NULL); done: smbcli_close(cli->tree, fnum); return ret; }
/** * Test both the snia cifs RAW_SFILEINFO_END_OF_FILE_INFO and the undocumented * pass-through RAW_SFILEINFO_END_OF_FILE_INFORMATION in the context of * trans2setpathinfo. */ static bool torture_raw_sfileinfo_eof(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) { const char *fname = BASEDIR "\\test_sfileinfo_end_of_file.dat"; NTSTATUS status; bool ret = true; union smb_open io; union smb_setfileinfo sfi; union smb_fileinfo qfi; uint16_t fnum = 0; if (!torture_setup_dir(cli1, BASEDIR)) { return false; } /* cleanup */ smbcli_unlink(cli1->tree, fname); 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_OPEN_IF; 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; /* Open the file sharing none. */ status = smb_raw_open(cli1->tree, tctx, &io); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); fnum = io.ntcreatex.out.file.fnum; /* Try to sfileinfo to extend the file. */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO; sfi.generic.in.file.path = fname; sfi.end_of_file_info.in.size = 100; status = smb_raw_setpathinfo(cli2->tree, &sfi); /* There should be share mode contention in this case. */ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "Status should be " "SHARING_VIOLATION"); /* Make sure the size is still 0. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli2->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 0, "alloc_size should be 0 since the setpathinfo failed."); /* Try again with the pass through instead of documented version. */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; sfi.generic.in.file.path = fname; sfi.end_of_file_info.in.size = 100; status = smb_raw_setpathinfo(cli2->tree, &sfi); /* * Looks like a windows bug: * http://lists.samba.org/archive/cifs-protocol/2009-November/001130.html */ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) { /* It succeeds! This is just weird! */ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); /* Verify that the file was actually extended to 100. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli2->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 100, "alloc_size should be 100 since the setpathinfo " "succeeded."); } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done, "Status should be " "SHARING_VIOLATION"); } /* close the first file. */ smbcli_close(cli1->tree, fnum); fnum = 0; /* Try to sfileinfo to extend the file again (non-pass-through). */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO; sfi.generic.in.file.path = fname; sfi.end_of_file_info.in.size = 200; status = smb_raw_setpathinfo(cli2->tree, &sfi); /* This should cause the client to retun invalid level. */ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) { /* * Windows sends back an invalid packet that smbclient sees * and returns INTERNAL_ERROR. */ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INTERNAL_ERROR, ret, done, "Status should be " "INTERNAL_ERROR"); } else { torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_LEVEL, ret, done, "Status should be " "INVALID_LEVEL"); } /* Try to extend the file now with the passthrough level. */ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; status = smb_raw_setpathinfo(cli2->tree, &sfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); /* Verify that the file was actually extended to 200. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli2->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 200, "alloc_size should be 200 since the setpathinfo succeeded."); /* Open the file so end of file can be set by handle. */ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_WRITE; status = smb_raw_open(cli1->tree, tctx, &io); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); fnum = io.ntcreatex.out.file.fnum; /* Try sfileinfo to extend the file by handle (non-pass-through). */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO; sfi.generic.in.file.fnum = fnum; sfi.end_of_file_info.in.size = 300; status = smb_raw_setfileinfo(cli1->tree, &sfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); /* Verify that the file was actually extended to 300. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli1->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 300, "alloc_size should be 300 since the setpathinfo succeeded."); /* Try sfileinfo to extend the file by handle (pass-through). */ ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; sfi.generic.in.file.fnum = fnum; sfi.end_of_file_info.in.size = 400; status = smb_raw_setfileinfo(cli1->tree, &sfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); /* Verify that the file was actually extended to 300. */ ZERO_STRUCT(qfi); qfi.generic.level = RAW_FILEINFO_STANDARD_INFO; qfi.generic.in.file.path = fname; status = smb_raw_pathinfo(cli1->tree, tctx, &qfi); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "Status should be OK"); torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 400, "alloc_size should be 400 since the setpathinfo succeeded."); done: if (fnum > 0) { smbcli_close(cli1->tree, fnum); fnum = 0; } smb_raw_exit(cli1->session); smb_raw_exit(cli2->session); smbcli_deltree(cli1->tree, BASEDIR); return ret; }
static bool torture_raw_sfileinfo_eof_access(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) { const char *fname = BASEDIR "\\test_exclusive3.dat"; NTSTATUS status, expected_status; bool ret = true; union smb_open io; union smb_setfileinfo sfi; uint16_t fnum=0; uint32_t access_mask = 0; if (!torture_setup_dir(cli1, BASEDIR)) { return false; } /* cleanup */ smbcli_unlink(cli1->tree, fname); /* * base ntcreatex parms */ io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; 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_OVERWRITE_IF; 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; for (access_mask = 1; access_mask <= 0x00001FF; access_mask++) { io.ntcreatex.in.access_mask = access_mask; status = smb_raw_open(cli1->tree, tctx, &io); if (!NT_STATUS_IS_OK(status)) { continue; } fnum = io.ntcreatex.out.file.fnum; ZERO_STRUCT(sfi); sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO; sfi.generic.in.file.fnum = fnum; sfi.end_of_file_info.in.size = 100; status = smb_raw_setfileinfo(cli1->tree, &sfi); expected_status = (access_mask & SEC_FILE_WRITE_DATA) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; if (!NT_STATUS_EQUAL(expected_status, status)) { torture_comment(tctx, "0x%x wrong\n", access_mask); } torture_assert_ntstatus_equal_goto(tctx, status, expected_status, ret, done, "Status Wrong"); smbcli_close(cli1->tree, fnum); } done: smb_raw_exit(cli1->session); smb_raw_exit(cli2->session); smbcli_deltree(cli1->tree, BASEDIR); 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 nb_do_createx(struct ftable *f, const char *fname, unsigned int create_options, unsigned int create_disposition, int handle, NTSTATUS status, bool retry) { union smb_open io; uint32_t desired_access; NTSTATUS ret; TALLOC_CTX *mem_ctx; unsigned int flags = 0; mem_ctx = talloc_init("raw_open"); if (create_options & NTCREATEX_OPTIONS_DIRECTORY) { desired_access = SEC_FILE_READ_DATA; } else { desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_READ_ATTRIBUTE | SEC_FILE_WRITE_ATTRIBUTE; flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; } io.ntcreatex.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = flags; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.access_mask = desired_access; io.ntcreatex.in.file_attr = 0; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.open_disposition = create_disposition; io.ntcreatex.in.create_options = create_options; io.ntcreatex.in.impersonation = 0; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; if (retry) { /* Reopening after a disconnect. */ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; } else if (f != NULL && f->cp.create_disposition == NTCREATEX_DISP_CREATE && NT_STATUS_IS_OK(status)) { /* Reopening after nb_createx() error. */ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; } ret = smb_raw_open(c->tree, mem_ctx, &io); talloc_free(mem_ctx); if (!check_status("NTCreateX", status, ret)) return false; if (!NT_STATUS_IS_OK(ret)) return true; if (f == NULL) { f = talloc (NULL, struct ftable); f->locks = NULL; nb_set_createx_params(f, fname, create_options, create_disposition, handle); DLIST_ADD_END(ftable, f); }
/* test tree with ulogoff this demonstrates that a tcon isn't autoclosed by a ulogoff the tcon can be reused using any other valid session later */ static BOOL test_tree_ulogoff(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { NTSTATUS status; BOOL ret = True; const char *share, *host; struct smbcli_session *session1; struct smbcli_session *session2; struct smb_composite_sesssetup setup; struct smbcli_tree *tree; union smb_tcon tcon; union smb_open io; union smb_write wr; int fnum1, fnum2; const char *fname1 = BASEDIR "\\test1.txt"; const char *fname2 = BASEDIR "\\test2.txt"; uint8_t c = 1; printf("TESTING TREE with ulogoff\n"); if (!torture_setup_dir(cli, BASEDIR)) { return False; } share = lp_parm_string(-1, "torture", "share"); host = lp_parm_string(-1, "torture", "host"); printf("create the first new sessions\n"); session1 = smbcli_session_init(cli->transport, mem_ctx, False); setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; setup.in.workgroup = lp_workgroup(); setup.in.credentials = cmdline_credentials; status = smb_composite_sesssetup(session1, &setup); CHECK_STATUS(status, NT_STATUS_OK); session1->vuid = setup.out.vuid; printf("vuid1=%d\n", session1->vuid); printf("create a tree context on the with vuid1\n"); tree = smbcli_tree_init(session1, mem_ctx, False); tcon.generic.level = RAW_TCON_TCONX; tcon.tconx.in.flags = 0; tcon.tconx.in.password = data_blob(NULL, 0); tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", host, share); tcon.tconx.in.device = "A:"; status = smb_raw_tcon(tree, mem_ctx, &tcon); CHECK_STATUS(status, NT_STATUS_OK); tree->tid = tcon.tconx.out.tid; printf("tid=%d\n", tree->tid); printf("create a file using vuid1\n"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname1; status = smb_raw_open(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum1 = io.ntcreatex.out.file.fnum; printf("write using vuid1\n"); wr.generic.level = RAW_WRITE_WRITEX; wr.writex.in.file.fnum = fnum1; wr.writex.in.offset = 0; wr.writex.in.wmode = 0; wr.writex.in.remaining = 0; wr.writex.in.count = 1; wr.writex.in.data = &c; status = smb_raw_write(tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("ulogoff the vuid1\n"); status = smb_raw_ulogoff(session1); CHECK_STATUS(status, NT_STATUS_OK); printf("create the second new sessions\n"); session2 = smbcli_session_init(cli->transport, mem_ctx, False); setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; setup.in.workgroup = lp_workgroup(); setup.in.credentials = cmdline_credentials; status = smb_composite_sesssetup(session2, &setup); CHECK_STATUS(status, NT_STATUS_OK); session2->vuid = setup.out.vuid; printf("vuid2=%d\n", session2->vuid); printf("use the existing tree with vuid2\n"); tree->session = session2; printf("create a file using vuid2\n"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname2; status = smb_raw_open(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum2 = io.ntcreatex.out.file.fnum; printf("write using vuid2\n"); wr.generic.level = RAW_WRITE_WRITEX; wr.writex.in.file.fnum = fnum2; wr.writex.in.offset = 0; wr.writex.in.wmode = 0; wr.writex.in.remaining = 0; wr.writex.in.count = 1; wr.writex.in.data = &c; status = smb_raw_write(tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("ulogoff the vuid2\n"); status = smb_raw_ulogoff(session2); CHECK_STATUS(status, NT_STATUS_OK); /* this also demonstrates that SMBtdis doesn't need a valid vuid */ printf("disconnect the existing tree connection\n"); status = smb_tree_disconnect(tree); CHECK_STATUS(status, NT_STATUS_OK); printf("disconnect the existing tree connection\n"); status = smb_tree_disconnect(tree); CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV,ERRinvnid)); /* close down the new tree */ talloc_free(tree); done: return ret; }
/* test SMBmv ops */ static bool test_mv(struct torture_context *tctx, struct smbcli_state *cli) { union smb_rename io; NTSTATUS status; bool ret = true; int fnum = -1; const char *fname1 = BASEDIR "\\test1.txt"; const char *fname2 = BASEDIR "\\test2.txt"; const char *Fname1 = BASEDIR "\\Test1.txt"; union smb_fileinfo finfo; union smb_open op; torture_comment(tctx, "Testing SMBmv\n"); if (!torture_setup_dir(cli, BASEDIR)) { return false; } torture_comment(tctx, "Trying simple rename\n"); op.generic.level = RAW_OPEN_NTCREATEX; op.ntcreatex.in.root_fid.fnum = 0; op.ntcreatex.in.flags = 0; op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; op.ntcreatex.in.create_options = 0; op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; op.ntcreatex.in.alloc_size = 0; op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; op.ntcreatex.in.security_flags = 0; op.ntcreatex.in.fname = fname1; status = smb_raw_open(cli->tree, tctx, &op); CHECK_STATUS(status, NT_STATUS_OK); fnum = op.ntcreatex.out.file.fnum; io.generic.level = RAW_RENAME_RENAME; io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = fname2; io.rename.in.attrib = 0; torture_comment(tctx, "trying rename while first file open\n"); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); smbcli_close(cli->tree, fnum); op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; status = smb_raw_open(cli->tree, tctx, &op); CHECK_STATUS(status, NT_STATUS_OK); fnum = op.ntcreatex.out.file.fnum; torture_comment(tctx, "trying rename while first file open with SHARE_ACCESS_DELETE\n"); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); io.rename.in.pattern1 = fname2; io.rename.in.pattern2 = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying case-changing rename\n"); io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = Fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); if (strcmp(finfo.all_info.out.fname.s, Fname1) != 0) { torture_warning(tctx, "(%s) Incorrect filename [%s] after case-changing " "rename, should be [%s]\n", __location__, finfo.all_info.out.fname.s, Fname1); } io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = fname2; torture_comment(tctx, "trying rename while not open\n"); smb_raw_exit(cli->session); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying self rename\n"); io.rename.in.pattern1 = fname2; io.rename.in.pattern2 = fname2; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); io.rename.in.pattern1 = fname1; io.rename.in.pattern2 = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); torture_comment(tctx, "trying wildcard rename\n"); io.rename.in.pattern1 = BASEDIR "\\*.txt"; io.rename.in.pattern2 = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "and again\n"); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying extension change\n"); io.rename.in.pattern1 = BASEDIR "\\*.txt"; io.rename.in.pattern2 = BASEDIR "\\*.bak"; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE); torture_comment(tctx, "Checking attrib handling\n"); torture_set_file_attribute(cli->tree, BASEDIR "\\test1.bak", FILE_ATTRIBUTE_HIDDEN); io.rename.in.pattern1 = BASEDIR "\\test1.bak"; io.rename.in.pattern2 = BASEDIR "\\*.txt"; io.rename.in.attrib = 0; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE); io.rename.in.attrib = FILE_ATTRIBUTE_HIDDEN; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); done: smbcli_close(cli->tree, fnum); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* test pid ops this test demonstrates that exit() only sees the PID used for the open() calls */ static BOOL test_pid_exit_only_sees_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { NTSTATUS status; BOOL ret = True; union smb_open io; union smb_write wr; union smb_close cl; int fnum; const char *fname = BASEDIR "\\test.txt"; uint8_t c = 1; uint16_t pid1, pid2; printf("TESTING PID HANDLING exit() only cares about open() PID\n"); if (!torture_setup_dir(cli, BASEDIR)) { return False; } pid1 = cli->session->pid; pid2 = pid1 + 1; printf("pid1=%d pid2=%d\n", pid1, pid2); printf("create a file using pid1\n"); cli->session->pid = pid1; io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; printf("write using pid2\n"); cli->session->pid = pid2; wr.generic.level = RAW_WRITE_WRITEX; wr.writex.in.file.fnum = fnum; wr.writex.in.offset = 0; wr.writex.in.wmode = 0; wr.writex.in.remaining = 0; wr.writex.in.count = 1; wr.writex.in.data = &c; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("exit pid2\n"); cli->session->pid = pid2; status = smb_raw_exit(cli->session); CHECK_STATUS(status, NT_STATUS_OK); printf("the fnum should still be accessible via pid2\n"); cli->session->pid = pid2; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("exit pid2\n"); cli->session->pid = pid2; status = smb_raw_exit(cli->session); CHECK_STATUS(status, NT_STATUS_OK); printf("the fnum should still be accessible via pid1 and pid2\n"); cli->session->pid = pid1; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); cli->session->pid = pid2; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("exit pid1\n"); cli->session->pid = pid1; status = smb_raw_exit(cli->session); CHECK_STATUS(status, NT_STATUS_OK); printf("the fnum should not now be accessible via pid1 or pid2\n"); cli->session->pid = pid1; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); cli->session->pid = pid2; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("the fnum should have been auto-closed\n"); cli->session->pid = pid1; cl.close.level = RAW_CLOSE_CLOSE; cl.close.in.file.fnum = fnum; cl.close.in.write_time = 0; status = smb_raw_close(cli->tree, &cl); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); done: return ret; }
/* test the delayed reply to a open that leads to a sharing violation */ static bool test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_open io; NTSTATUS status; int fnum1, fnum2; bool ret = true; struct smbcli_request *req1, *req2; struct timeval tv; double d; printf("Testing multiplexed open/open/close\n"); printf("send first open\n"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = BASEDIR "\\open.dat"; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum1 = io.ntcreatex.out.file.fnum; printf("send 2nd open, non-conflicting\n"); io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum2 = io.ntcreatex.out.file.fnum; tv = timeval_current(); printf("send 3rd open, conflicting\n"); io.ntcreatex.in.share_access = 0; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); d = timeval_elapsed(&tv); if (d < 0.5 || d > 1.5) { printf("bad timeout for conflict - %.2f should be 1.0\n", d); } else { printf("open delay %.2f\n", d); } printf("send async open, conflicting\n"); tv = timeval_current(); req1 = smb_raw_open_send(cli->tree, &io); printf("send 2nd async open, conflicting\n"); tv = timeval_current(); req2 = smb_raw_open_send(cli->tree, &io); printf("close first sync open\n"); smbcli_close(cli->tree, fnum1); printf("cancel 2nd async open (should be ignored)\n"); smb_raw_ntcancel(req2); d = timeval_elapsed(&tv); if (d > 0.25) { printf("bad timeout after cancel - %.2f should be <0.25\n", d); ret = false; } printf("close the 2nd sync open\n"); smbcli_close(cli->tree, fnum2); printf("see if the 1st async open now succeeded\n"); status = smb_raw_open_recv(req1, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); d = timeval_elapsed(&tv); if (d > 0.25) { printf("bad timeout for async conflict - %.2f should be <0.25\n", d); ret = false; } else { printf("async open delay %.2f\n", d); } printf("2nd async open should have timed out\n"); status = smb_raw_open_recv(req2, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); d = timeval_elapsed(&tv); if (d < 0.8) { printf("bad timeout for async conflict - %.2f should be 1.0\n", d); } printf("close the 1st async open\n"); smbcli_close(cli->tree, io.ntcreatex.out.file.fnum); done: return ret; }
/* test session ops */ static BOOL test_session(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { NTSTATUS status; BOOL ret = True; struct smbcli_session *session; struct smbcli_session *session2; struct smbcli_session *session3; struct smbcli_session *session4; struct cli_credentials *anon_creds; struct smbcli_session *sessions[15]; struct composite_context *composite_contexts[15]; struct smbcli_tree *tree; struct smb_composite_sesssetup setup; struct smb_composite_sesssetup setups[15]; union smb_open io; union smb_write wr; union smb_close cl; int fnum; const char *fname = BASEDIR "\\test.txt"; uint8_t c = 1; int i; printf("TESTING SESSION HANDLING\n"); if (!torture_setup_dir(cli, BASEDIR)) { return False; } printf("create a second security context on the same transport\n"); session = smbcli_session_init(cli->transport, mem_ctx, False); setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */ setup.in.workgroup = lp_workgroup(); setup.in.credentials = cmdline_credentials; status = smb_composite_sesssetup(session, &setup); CHECK_STATUS(status, NT_STATUS_OK); session->vuid = setup.out.vuid; printf("create a third security context on the same transport, with vuid set\n"); session2 = smbcli_session_init(cli->transport, mem_ctx, False); session2->vuid = session->vuid; setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */ setup.in.workgroup = lp_workgroup(); setup.in.credentials = cmdline_credentials; status = smb_composite_sesssetup(session2, &setup); CHECK_STATUS(status, NT_STATUS_OK); session2->vuid = setup.out.vuid; printf("vuid1=%d vuid2=%d vuid3=%d\n", cli->session->vuid, session->vuid, session2->vuid); if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) { /* Samba4 currently fails this - we need to determine if this insane behaviour is important */ if (session2->vuid == session->vuid) { printf("server allows the user to re-use an existing vuid in session setup \n"); } } else { CHECK_NOT_VALUE(session2->vuid, session->vuid); } talloc_free(session2); if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) { printf("create a fourth security context on the same transport, without extended security\n"); session3 = smbcli_session_init(cli->transport, mem_ctx, False); session3->vuid = session->vuid; setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */ setup.in.workgroup = lp_workgroup(); setup.in.credentials = cmdline_credentials; status = smb_composite_sesssetup(session3, &setup); CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE); printf("create a fouth anonymous security context on the same transport, without extended security\n"); session4 = smbcli_session_init(cli->transport, mem_ctx, False); session4->vuid = session->vuid; setup.in.sesskey = cli->transport->negotiate.sesskey; setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */ setup.in.workgroup = lp_workgroup(); anon_creds = cli_credentials_init(mem_ctx); cli_credentials_set_conf(anon_creds); cli_credentials_set_anonymous(anon_creds); setup.in.credentials = anon_creds; status = smb_composite_sesssetup(session3, &setup); CHECK_STATUS(status, NT_STATUS_OK); talloc_free(session4); } printf("use the same tree as the existing connection\n"); tree = smbcli_tree_init(session, mem_ctx, False); tree->tid = cli->tree->tid; printf("create a file using the new vuid\n"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = fname; status = smb_raw_open(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; printf("write using the old vuid\n"); wr.generic.level = RAW_WRITE_WRITEX; wr.writex.in.file.fnum = fnum; wr.writex.in.offset = 0; wr.writex.in.wmode = 0; wr.writex.in.remaining = 0; wr.writex.in.count = 1; wr.writex.in.data = &c; status = smb_raw_write(cli->tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("write with the new vuid\n"); status = smb_raw_write(tree, &wr); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(wr.writex.out.nwritten, 1); printf("logoff the new vuid\n"); status = smb_raw_ulogoff(session); CHECK_STATUS(status, NT_STATUS_OK); printf("the new vuid should not now be accessible\n"); status = smb_raw_write(tree, &wr); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("second logoff for the new vuid should fail\n"); status = smb_raw_ulogoff(session); CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid)); talloc_free(session); printf("the fnum should have been auto-closed\n"); cl.close.level = RAW_CLOSE_CLOSE; cl.close.in.file.fnum = fnum; cl.close.in.write_time = 0; status = smb_raw_close(cli->tree, &cl); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("create %d secondary security contexts on the same transport\n", (int)ARRAY_SIZE(sessions)); for (i=0; i <ARRAY_SIZE(sessions); i++) { setups[i].in.sesskey = cli->transport->negotiate.sesskey; setups[i].in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */ setups[i].in.workgroup = lp_workgroup(); setups[i].in.credentials = cmdline_credentials; sessions[i] = smbcli_session_init(cli->transport, mem_ctx, False); composite_contexts[i] = smb_composite_sesssetup_send(sessions[i], &setups[i]); } /* flush the queue */ for (i=0; i < ARRAY_SIZE(sessions); i++) { event_loop_once(composite_contexts[0]->event_ctx); } printf("finishing %d secondary security contexts on the same transport\n", (int)ARRAY_SIZE(sessions)); for (i=0; i< ARRAY_SIZE(sessions); i++) { status = smb_composite_sesssetup_recv(composite_contexts[i]); CHECK_STATUS(status, NT_STATUS_OK); sessions[i]->vuid = setups[i].out.vuid; printf("VUID: %d\n", sessions[i]->vuid); status = smb_raw_ulogoff(sessions[i]); CHECK_STATUS(status, NT_STATUS_OK); } talloc_free(tree); done: return ret; }