/* basic testing of session/tree context calls */ static BOOL torture_raw_context_int(void) { struct smbcli_state *cli; BOOL ret = True; TALLOC_CTX *mem_ctx; if (!torture_open_connection(&cli, 0)) { return False; } mem_ctx = talloc_init("torture_raw_context"); ret &= test_session(cli, mem_ctx); ret &= test_tree(cli, mem_ctx); ret &= test_tree_ulogoff(cli, mem_ctx); ret &= test_pid_exit_only_sees_open(cli, mem_ctx); ret &= test_pid_2sess(cli, mem_ctx); ret &= test_pid_2tcon(cli, mem_ctx); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); torture_close_connection(cli); talloc_free(mem_ctx); return ret; }
/* basic testing of streams calls */ BOOL torture_raw_streams(struct torture_context *torture) { struct smbcli_state *cli; BOOL ret = True; TALLOC_CTX *mem_ctx; if (!torture_open_connection(&cli, 0)) { return False; } mem_ctx = talloc_init("torture_raw_streams"); if (!torture_setup_dir(cli, BASEDIR)) { return False; } ret &= test_stream_io(cli, mem_ctx); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); torture_close_connection(cli); talloc_free(mem_ctx); return ret; }
/** setup a directory ready for a test */ _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname) { smb_raw_exit(cli->session); if (smbcli_deltree(cli->tree, dname) == -1 || NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) { printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree)); return false; } return true; }
/* basic testing of multiplexing notify */ bool torture_raw_mux(struct torture_context *torture, struct smbcli_state *cli) { bool ret = true; torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR); ret &= test_mux_open(cli, torture); ret &= test_mux_write(cli, torture); ret &= test_mux_lock(cli, torture); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* exit - closing files open by the pid */ static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req) { struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_exit(p->tree->session); } c_req = smb_raw_exit_send(p->tree->session); SIMPLE_ASYNC_TAIL; }
/* basic testing of session/tree context calls */ static bool torture_raw_context_int(struct torture_context *tctx, struct smbcli_state *cli) { bool ret = true; ret &= test_session(cli, tctx); ret &= test_tree(cli, tctx); ret &= test_tree_ulogoff(cli, tctx); ret &= test_pid_exit_only_sees_open(cli, tctx); ret &= test_pid_2sess(cli, tctx); ret &= test_pid_2tcon(cli, tctx); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* basic testing of disconnects */ bool torture_disconnect(struct torture_context *torture) { bool ret = true; TALLOC_CTX *mem_ctx; int i; extern int torture_numops; struct smbcli_state *cli; mem_ctx = talloc_init("torture_raw_mux"); if (!torture_open_connection(&cli, torture, 0)) { return false; } if (!torture_setup_dir(cli, BASEDIR)) { return false; } for (i=0;i<torture_numops;i++) { ret &= test_disconnect_lock(cli, mem_ctx); if (!torture_open_connection(&cli, torture, 0)) { return false; } ret &= test_disconnect_open(cli, mem_ctx); if (!torture_open_connection(&cli, torture, 0)) { return false; } if (torture_setting_bool(torture, "samba3", false)) { /* * In Samba3 it might happen that the old smbd from * test_disconnect_lock is not scheduled before the * new process comes in. Try to get rid of the random * failures in the build farm. */ smb_msleep(200); } } smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); talloc_free(mem_ctx); return ret; }
/* basic testing of libcli composite calls */ bool torture_raw_composite(struct torture_context *tctx, struct smbcli_state *cli) { bool ret = true; if (!torture_setup_dir(cli, BASEDIR)) { return false; } ret &= test_fetchfile(cli, tctx); ret &= test_loadfile(cli, tctx); ret &= test_appendacl(cli, tctx); ret &= test_fsinfo(cli, tctx); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* benchmark locking calls */ bool torture_bench_lock(struct torture_context *torture) { bool ret = true; TALLOC_CTX *mem_ctx = talloc_new(torture); int i, j; int timelimit = torture_setting_int(torture, "timelimit", 10); struct timeval tv; struct benchlock_state *state; int total = 0, minops=0; struct smbcli_state *cli; bool progress; off_t offset; int initial_locks = torture_setting_int(torture, "initial_locks", 0); progress = torture_setting_bool(torture, "progress", true); nprocs = torture_setting_int(torture, "nprocs", 4); state = talloc_zero_array(mem_ctx, struct benchlock_state, nprocs); printf("Opening %d connections\n", nprocs); for (i=0;i<nprocs;i++) { state[i].tctx = torture; state[i].mem_ctx = talloc_new(state); state[i].client_num = i; state[i].ev = torture->ev; if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) { return false; } talloc_steal(mem_ctx, state); state[i].tree = cli->tree; state[i].dest_host = talloc_strdup(state[i].mem_ctx, cli->tree->session->transport->socket->hostname); state[i].dest_ports = talloc_array(state[i].mem_ctx, const char *, 2); state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports, "%u", cli->tree->session->transport->socket->port); state[i].dest_ports[1] = NULL; state[i].called_name = talloc_strdup(state[i].mem_ctx, cli->tree->session->transport->called.name); state[i].service_type = talloc_strdup(state[i].mem_ctx, cli->tree->device); } num_connected = i; if (!torture_setup_dir(cli, BASEDIR)) { goto failed; } for (i=0;i<nprocs;i++) { state[i].fnum = smbcli_open(state[i].tree, FNAME, O_RDWR|O_CREAT, DENY_NONE); if (state[i].fnum == -1) { printf("Failed to open %s on connection %d\n", FNAME, i); goto failed; } /* Optionally, lock initial_locks for each proc beforehand. */ if (i == 0 && initial_locks > 0) { printf("Initializing %d locks on each proc.\n", initial_locks); } for (j = 0; j < initial_locks; j++) { offset = (0xFFFFFED8LLU * (i+2)) + j; if (!NT_STATUS_IS_OK(smbcli_lock64(state[i].tree, state[i].fnum, offset, 1, 0, WRITE_LOCK))) { printf("Failed initializing, lock=%d\n", j); goto failed; } } state[i].stage = LOCK_INITIAL; lock_send(&state[i]); } tv = timeval_current(); if (progress) { event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state); } printf("Running for %d seconds\n", timelimit); while (timeval_elapsed(&tv) < timelimit) { event_loop_once(torture->ev); if (lock_failed) { DEBUG(0,("locking failed\n")); goto failed; } } printf("%.2f ops/second\n", total/timeval_elapsed(&tv)); minops = state[0].count; for (i=0;i<nprocs;i++) { printf("[%d] %u ops\n", i, state[i].count); if (state[i].count < minops) minops = state[i].count; } if (minops < 0.5*total/nprocs) { printf("Failed: unbalanced locking\n"); goto failed; } for (i=0;i<nprocs;i++) { talloc_free(state[i].req); smb_raw_exit(state[i].tree->session); } smbcli_deltree(state[0].tree, BASEDIR); talloc_free(mem_ctx); printf("\n"); return ret; failed: smbcli_deltree(state[0].tree, BASEDIR); talloc_free(mem_ctx); return false; }
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; }
/* 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 writex ops */ static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_write io; NTSTATUS status; BOOL ret = True; int fnum, i; uint8_t *buf; const int maxsize = 90000; const char *fname = BASEDIR "\\test.txt"; uint_t seed = time(NULL); union smb_fileinfo finfo; int max_bits=63; if (!lp_parm_bool(-1, "torture", "dangerous", False)) { max_bits=33; printf("dangerous not set - limiting range of test to 2^%d\n", max_bits); } buf = talloc_zero_size(mem_ctx, maxsize); if (!torture_setup_dir(cli, BASEDIR)) { return False; } printf("Testing RAW_WRITE_WRITEX\n"); io.generic.level = RAW_WRITE_WRITEX; fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); if (fnum == -1) { printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Trying zero write\n"); io.writex.in.file.fnum = fnum; io.writex.in.offset = 0; io.writex.in.wmode = 0; io.writex.in.remaining = 0; io.writex.in.count = 0; io.writex.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.writex.out.nwritten, 0); setup_buffer(buf, seed, maxsize); printf("Trying small write\n"); io.writex.in.count = 9; io.writex.in.offset = 4; io.writex.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count); memset(buf, 0, maxsize); if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) { printf("read failed at %s\n", __location__); ret = False; goto done; } CHECK_BUFFER(buf+4, seed, 9); CHECK_VALUE(IVAL(buf,0), 0); setup_buffer(buf, seed, maxsize); printf("Trying large write\n"); io.writex.in.count = 4000; io.writex.in.offset = 0; io.writex.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.writex.out.nwritten, 4000); memset(buf, 0, maxsize); if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) { printf("read failed at %s\n", __location__); ret = False; goto done; } CHECK_BUFFER(buf, seed, 4000); printf("Trying bad fnum\n"); io.writex.in.file.fnum = fnum+1; io.writex.in.count = 4000; io.writex.in.offset = 0; io.writex.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("Testing wmode\n"); io.writex.in.file.fnum = fnum; io.writex.in.count = 1; io.writex.in.offset = 0; io.writex.in.wmode = 1; io.writex.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count); io.writex.in.wmode = 2; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count); printf("Trying locked region\n"); cli->session->pid++; if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) { printf("Failed to lock file at %s\n", __location__); ret = False; goto done; } cli->session->pid--; io.writex.in.wmode = 0; io.writex.in.count = 4; io.writex.in.offset = 0; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); printf("Setting file as sparse\n"); status = torture_set_sparse(cli->tree, fnum); CHECK_STATUS(status, NT_STATUS_OK); if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) { printf("skipping large file tests - CAP_LARGE_FILES not set\n"); goto done; } printf("Trying 2^32 offset\n"); setup_buffer(buf, seed, maxsize); io.writex.in.file.fnum = fnum; io.writex.in.count = 4000; io.writex.in.offset = 0xFFFFFFFF - 2000; io.writex.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.writex.out.nwritten, 4000); CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size); memset(buf, 0, maxsize); if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) { printf("read failed at %s\n", __location__); ret = False; goto done; } CHECK_BUFFER(buf, seed, 4000); for (i=33;i<max_bits;i++) { printf("Trying 2^%d offset\n", i); setup_buffer(buf, seed+1, maxsize); io.writex.in.file.fnum = fnum; io.writex.in.count = 4000; io.writex.in.offset = ((uint64_t)1) << i; io.writex.in.data = buf; status = smb_raw_write(cli->tree, &io); if (i>33 && NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { break; } CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.writex.out.nwritten, 4000); CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size); memset(buf, 0, maxsize); if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) { printf("read failed at %s\n", __location__); ret = False; goto done; } CHECK_BUFFER(buf, seed+1, 4000); } printf("limit is 2^%d\n", i); setup_buffer(buf, seed, maxsize); 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 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 a lock that conflicts with an existing lock */ static bool test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_lock io; NTSTATUS status; int fnum; bool ret = true; struct smbcli_request *req; struct smb_lock_entry lock[1]; struct timeval t; printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n"); fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree)); ret = false; goto done; } printf("establishing a lock\n"); io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.file.fnum = fnum; io.lockx.in.mode = 0; io.lockx.in.timeout = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.ulock_cnt = 0; lock[0].pid = 1; lock[0].offset = 0; lock[0].count = 4; io.lockx.in.locks = &lock[0]; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); printf("the second lock will conflict with the first\n"); lock[0].pid = 2; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); printf("this will too, but we'll unlock while waiting\n"); t = timeval_current(); req = smb_raw_lock_send(cli->tree, &io); printf("unlock the first range\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; io.lockx.in.timeout = 0; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); printf("recv the async reply\n"); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_OK); printf("async lock took %.2f msec\n", timeval_elapsed(&t) * 1000); if (timeval_elapsed(&t) > 0.1) { printf("failed to trigger early lock retry\n"); return false; } printf("reopening with an exit\n"); smb_raw_exit(cli->session); fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE); printf("Now trying with a cancel\n"); io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.file.fnum = fnum; io.lockx.in.mode = 0; io.lockx.in.timeout = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.ulock_cnt = 0; lock[0].pid = 1; lock[0].offset = 0; lock[0].count = 4; io.lockx.in.locks = &lock[0]; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); lock[0].pid = 2; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); req = smb_raw_lock_send(cli->tree, &io); /* cancel the blocking lock */ smb_raw_ntcancel(req); printf("sending 2nd cancel\n"); /* the 2nd cancel is totally harmless, but tests the server trying to cancel an already cancelled request */ smb_raw_ntcancel(req); printf("sent 2nd cancel\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; io.lockx.in.timeout = 0; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); printf("cancel a lock using exit to close file\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); t = timeval_current(); lock[0].pid = 2; req = smb_raw_lock_send(cli->tree, &io); smb_raw_exit(cli->session); smb_raw_exit(cli->session); smb_raw_exit(cli->session); smb_raw_exit(cli->session); printf("recv the async reply\n"); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); printf("async lock exit took %.2f msec\n", timeval_elapsed(&t) * 1000); if (timeval_elapsed(&t) > 0.1) { printf("failed to trigger early lock failure\n"); return false; } 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 *fname = BASEDIR "\\dir_for_rename\\file.txt"; bool ret = true; int fnum = -1; printf("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_unlink(cli->tree, dname1); smbcli_unlink(cli->tree, dname2); 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); /* 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 = 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); done: if (fnum != -1) { smbcli_close(cli->tree, fnum); } smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* * basic testing of all RAW_SFILEINFO_RENAME call */ static bool torture_raw_sfileinfo_rename(struct torture_context *torture, struct smbcli_state *cli) { bool ret = true; int fnum_saved, d_fnum, fnum2, fnum = -1; char *fnum_fname; char *fnum_fname_new; char *path_fname; char *path_fname_new; char *path_dname; char *path_dname_new; char *saved_name; char *saved_name_new; union smb_fileinfo finfo1, finfo2; union smb_setfileinfo sfinfo; NTSTATUS status, status2; const char *call_name; bool check_fnum; int n = time(NULL) % 100; asprintf(&path_fname, BASEDIR "\\fname_test_%d.txt", n); asprintf(&path_fname_new, BASEDIR "\\fname_test_new_%d.txt", n); asprintf(&fnum_fname, BASEDIR "\\fnum_test_%d.txt", n); asprintf(&fnum_fname_new, BASEDIR "\\fnum_test_new_%d.txt", n); asprintf(&path_dname, BASEDIR "\\dname_test_%d", n); asprintf(&path_dname_new, BASEDIR "\\dname_test_new_%d", n); if (!torture_setup_dir(cli, BASEDIR)) { return false; } RECREATE_BOTH; ZERO_STRUCT(sfinfo); smbcli_close(cli->tree, create_complex_file(cli, torture, fnum_fname_new)); smbcli_close(cli->tree, create_complex_file(cli, torture, path_fname_new)); sfinfo.rename_information.in.overwrite = 0; sfinfo.rename_information.in.root_fid = 0; sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OBJECT_NAME_COLLISION); sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1; CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OBJECT_NAME_COLLISION); sfinfo.rename_information.in.new_name = fnum_fname_new; sfinfo.rename_information.in.overwrite = 1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_NOT_SUPPORTED); sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new); printf("Trying rename with dest file open\n"); fnum2 = create_complex_file(cli, torture, fnum_fname); sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_ACCESS_DENIED); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new); fnum_saved = fnum; fnum = fnum2; sfinfo.disposition_info.in.delete_on_close = 1; CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK); fnum = fnum_saved; printf("Trying rename with dest file open and delete_on_close\n"); sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_ACCESS_DENIED); smbcli_close(cli->tree, fnum2); CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname); printf("Trying rename with source file open twice\n"); sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname); fnum2 = create_complex_file(cli, torture, fnum_fname); sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 0; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new); smbcli_close(cli->tree, fnum2); sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 0; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname); sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 1; CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new); sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname); sfinfo.rename_information.in.new_name = path_fname+strlen(BASEDIR)+1; CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, path_fname); printf("Trying rename with a root fid\n"); status = create_directory_handle(cli->tree, BASEDIR, &d_fnum); CHECK_STATUS(status, NT_STATUS_OK); sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1; sfinfo.rename_information.in.root_fid = d_fnum; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_INVALID_PARAMETER); CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname); smbcli_close(cli->tree, d_fnum); printf("Trying rename directory\n"); if (!torture_setup_dir(cli, path_dname)) { ret = false; goto done; } saved_name = path_fname; saved_name_new = path_fname_new; path_fname = path_dname; path_fname_new = path_dname_new; sfinfo.rename_information.in.new_name = path_dname_new+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 0; sfinfo.rename_information.in.root_fid = 0; CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); path_fname = saved_name; path_fname_new = saved_name_new; if (torture_setting_bool(torture, "samba3", false)) { printf("SKIP: Trying rename directory with a handle\n"); printf("SKIP: Trying rename by path while a handle is open\n"); printf("SKIP: Trying rename directory by path while a handle is open\n"); goto done; } printf("Trying rename directory with a handle\n"); status = create_directory_handle(cli->tree, path_dname_new, &d_fnum); fnum_saved = fnum; fnum = d_fnum; saved_name = fnum_fname; saved_name_new = fnum_fname_new; fnum_fname = path_dname; fnum_fname_new = path_dname_new; sfinfo.rename_information.in.new_name = path_dname+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 0; sfinfo.rename_information.in.root_fid = 0; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); smbcli_close(cli->tree, d_fnum); fnum = fnum_saved; fnum_fname = saved_name; fnum_fname_new = saved_name_new; printf("Trying rename by path while a handle is open\n"); fnum_saved = fnum; fnum = create_complex_file(cli, torture, path_fname); sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 0; sfinfo.rename_information.in.root_fid = 0; CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new); /* check that the handle returns the same name */ check_fnum = true; CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new); /* rename it back on the handle */ sfinfo.rename_information.in.new_name = path_fname+strlen(BASEDIR)+1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, path_fname); check_fnum = false; CHECK_STR(NAME_INFO, name_info, fname.s, path_fname); smbcli_close(cli->tree, fnum); fnum = fnum_saved; printf("Trying rename directory by path while a handle is open\n"); status = create_directory_handle(cli->tree, path_dname, &d_fnum); fnum_saved = fnum; fnum = d_fnum; saved_name = path_fname; saved_name_new = path_fname_new; path_fname = path_dname; path_fname_new = path_dname_new; sfinfo.rename_information.in.new_name = path_dname_new+strlen(BASEDIR)+1; sfinfo.rename_information.in.overwrite = 0; sfinfo.rename_information.in.root_fid = 0; CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); path_fname = saved_name; path_fname_new = saved_name_new; saved_name = fnum_fname; saved_name_new = fnum_fname_new; fnum_fname = path_dname; fnum_fname_new = path_dname_new; /* check that the handle returns the same name */ check_fnum = true; CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new); /* rename it back on the handle */ sfinfo.rename_information.in.new_name = path_dname+strlen(BASEDIR)+1; CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK); CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); fnum_fname = saved_name; fnum_fname_new = saved_name_new; saved_name = path_fname; saved_name_new = path_fname_new; path_fname = path_dname; path_fname_new = path_dname_new; check_fnum = false; CHECK_STR(NAME_INFO, name_info, fname.s, path_dname); smbcli_close(cli->tree, d_fnum); fnum = fnum_saved; path_fname = saved_name; path_fname_new = saved_name_new; done: smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); 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; }
/* basic testing of all RAW_SFILEINFO_* calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ static bool torture_raw_sfileinfo_base(struct torture_context *torture, struct smbcli_state *cli) { bool ret = true; int fnum = -1; char *fnum_fname; char *fnum_fname_new; char *path_fname; char *path_fname_new; union smb_fileinfo finfo1, finfo2; union smb_setfileinfo sfinfo; NTSTATUS status, status2; const char *call_name; time_t basetime = (time(NULL) - 86400) & ~1; bool check_fnum; int n = time(NULL) % 100; asprintf(&path_fname, BASEDIR "\\fname_test_%d.txt", n); asprintf(&path_fname_new, BASEDIR "\\fname_test_new_%d.txt", n); asprintf(&fnum_fname, BASEDIR "\\fnum_test_%d.txt", n); asprintf(&fnum_fname_new, BASEDIR "\\fnum_test_new_%d.txt", n); if (!torture_setup_dir(cli, BASEDIR)) { return false; } #define RECREATE_FILE(fname) do { \ if (fnum != -1) smbcli_close(cli->tree, fnum); \ fnum = create_complex_file(cli, torture, fname); \ if (fnum == -1) { \ printf("(%s) ERROR: open of %s failed (%s)\n", \ __location__, fname, smbcli_errstr(cli->tree)); \ ret = false; \ goto done; \ }} while (0) #define RECREATE_BOTH do { \ RECREATE_FILE(path_fname); \ smbcli_close(cli->tree, fnum); \ RECREATE_FILE(fnum_fname); \ } while (0) RECREATE_BOTH; #define CHECK_CALL_FNUM(call, rightstatus) do { \ check_fnum = true; \ call_name = #call; \ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \ sfinfo.generic.in.file.fnum = fnum; \ status = smb_raw_setfileinfo(cli->tree, &sfinfo); \ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \ torture_warning(torture, \ "(%s) %s - %s", __location__, #call, \ nt_errstr(status)); \ } else if (!NT_STATUS_EQUAL(status, rightstatus)) { \ printf("(%s) %s - %s (should be %s)\n", __location__, #call, \ nt_errstr(status), nt_errstr(rightstatus)); \ ret = false; \ } \ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \ finfo1.generic.in.file.fnum = fnum; \ status2 = smb_raw_fileinfo(cli->tree, torture, &finfo1); \ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \ torture_warning(torture, \ "(%s) %s - %s", __location__, #call, \ nt_errstr(status)); \ } else if (!NT_STATUS_IS_OK(status2)) { \ printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \ ret = false; \ }} while (0) #define CHECK_CALL_PATH(call, rightstatus) do { \ check_fnum = false; \ call_name = #call; \ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \ sfinfo.generic.in.file.path = path_fname; \ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \ sfinfo.generic.in.file.path = path_fname_new; \ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \ } \ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \ torture_warning(torture, \ "(%s) %s - %s", __location__, #call, \ nt_errstr(status)); \ } else if (!NT_STATUS_EQUAL(status, rightstatus)) { \ printf("(%s) %s - %s (should be %s)\n", __location__, #call, \ nt_errstr(status), nt_errstr(rightstatus)); \ ret = false; \ } \ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \ finfo1.generic.in.file.path = path_fname; \ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo1); \ if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \ finfo1.generic.in.file.path = path_fname_new; \ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo1); \ } \ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \ torture_warning(torture, \ "(%s) %s - %s", __location__, #call, \ nt_errstr(status)); \ } else if (!NT_STATUS_IS_OK(status2)) { \ printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status2)); \ ret = false; \ }} while (0) #define CHECK1(call) \ do { if (NT_STATUS_IS_OK(status)) { \ finfo2.generic.level = RAW_FILEINFO_ ## call; \ if (check_fnum) { \ finfo2.generic.in.file.fnum = fnum; \ status2 = smb_raw_fileinfo(cli->tree, torture, &finfo2); \ } else { \ finfo2.generic.in.file.path = path_fname; \ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo2); \ if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \ finfo2.generic.in.file.path = path_fname_new; \ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo2); \ } \ } \ if (!NT_STATUS_IS_OK(status2)) { \ printf("%s - %s\n", #call, nt_errstr(status2)); \ ret = false; \ } \ }} 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, \ (unsigned int)value, (unsigned int)finfo2.stype.out.field); \ dump_all_info(torture, &finfo1); \ ret = false; \ }} 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, \ (unsigned int)value, \ (unsigned int)nt_time_to_unix(finfo2.stype.out.field)); \ printf("\t%s", timestring(torture, value)); \ printf("\t%s\n", nt_time_string(torture, finfo2.stype.out.field)); \ dump_all_info(torture, &finfo1); \ ret = false; \ }} while (0) #define CHECK_STR(call, stype, field, value) do { \ CHECK1(call); \ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && strcmp(finfo2.stype.out.field, value) != 0) { \ printf("(%s) %s - %s/%s should be '%s' - '%s'\n", __location__, \ call_name, #stype, #field, \ value, \ finfo2.stype.out.field); \ dump_all_info(torture, &finfo1); \ ret = false; \ }} 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) printf("Test setattr\n"); sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY; sfinfo.setattr.in.write_time = basetime; CHECK_CALL_PATH(SETATTR, NT_STATUS_OK); CHECK_VALUE (ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY); CHECK_TIME (ALL_INFO, all_info, write_time, basetime); printf("setting to NORMAL doesn't do anything\n"); sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_NORMAL; sfinfo.setattr.in.write_time = 0; CHECK_CALL_PATH(SETATTR, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY); CHECK_TIME (ALL_INFO, all_info, write_time, basetime); printf("a zero write_time means don't change\n"); sfinfo.setattr.in.attrib = 0; sfinfo.setattr.in.write_time = 0; CHECK_CALL_PATH(SETATTR, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); CHECK_TIME (ALL_INFO, all_info, write_time, basetime); printf("Test setattre\n"); sfinfo.setattre.in.create_time = basetime + 20; sfinfo.setattre.in.access_time = basetime + 30; sfinfo.setattre.in.write_time = basetime + 40; CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40); sfinfo.setattre.in.create_time = 0; sfinfo.setattre.in.access_time = 0; sfinfo.setattre.in.write_time = 0; CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40); printf("Test standard level\n"); sfinfo.standard.in.create_time = basetime + 100; sfinfo.standard.in.access_time = basetime + 200; sfinfo.standard.in.write_time = basetime + 300; CHECK_CALL_FNUM(STANDARD, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); printf("Test basic_info 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_FNUM(BASIC_INFO, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, 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 = 0; CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY); 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_NORMAL; CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); torture_comment(torture, "try to change a file to a directory\n"); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY; CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_INVALID_PARAMETER); 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_FNUM(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); /* interesting - w2k3 leaves change_time as current time for 0 change time in setpathinfo CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); */ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); printf("Test disposition_info level\n"); sfinfo.disposition_info.in.delete_on_close = 1; CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1); CHECK_VALUE(ALL_INFO, all_info, nlink, 0); sfinfo.disposition_info.in.delete_on_close = 0; CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0); CHECK_VALUE(ALL_INFO, all_info, nlink, 1); printf("Test disposition_information level\n"); sfinfo.disposition_info.in.delete_on_close = 1; CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1); CHECK_VALUE(ALL_INFO, all_info, nlink, 0); /* this would delete the file! */ /* CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1); CHECK_VALUE(ALL_INFO, all_info, nlink, 0); */ sfinfo.disposition_info.in.delete_on_close = 0; CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0); CHECK_VALUE(ALL_INFO, all_info, nlink, 1); CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0); CHECK_VALUE(ALL_INFO, all_info, nlink, 1); printf("Test allocation_info level\n"); sfinfo.allocation_info.in.alloc_size = 0; CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 0); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0); sfinfo.allocation_info.in.alloc_size = 4096; CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096); CHECK_VALUE(ALL_INFO, all_info, size, 0); RECREATE_BOTH; sfinfo.allocation_info.in.alloc_size = 0; CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 0); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0); CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 0); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0); sfinfo.allocation_info.in.alloc_size = 4096; CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096); CHECK_VALUE(ALL_INFO, all_info, size, 0); /* setting the allocation size up via setpathinfo seems to be broken in w2k3 */ CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0); CHECK_VALUE(ALL_INFO, all_info, size, 0); printf("Test end_of_file_info level\n"); sfinfo.end_of_file_info.in.size = 37; CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 37); sfinfo.end_of_file_info.in.size = 7; CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 7); sfinfo.end_of_file_info.in.size = 37; CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 37); CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 37); sfinfo.end_of_file_info.in.size = 7; CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 7); CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 7); printf("Test position_information level\n"); sfinfo.position_information.in.position = 123456; CHECK_CALL_FNUM(POSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456); CHECK_CALL_PATH(POSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(POSITION_INFORMATION, position_information, position, 0); printf("Test mode_information level\n"); sfinfo.mode_information.in.mode = 2; CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2); CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); sfinfo.mode_information.in.mode = 1; CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER); CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER); sfinfo.mode_information.in.mode = 0; CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); #if 0 printf("Test unix_basic level\n"); CHECK_CALL_FNUM(UNIX_BASIC, NT_STATUS_OK); CHECK_CALL_PATH(UNIX_BASIC, NT_STATUS_OK); printf("Test unix_link level\n"); CHECK_CALL_FNUM(UNIX_LINK, NT_STATUS_OK); CHECK_CALL_PATH(UNIX_LINK, NT_STATUS_OK); #endif done: smb_raw_exit(cli->session); smbcli_close(cli->tree, fnum); if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fnum_fname))) { printf("Failed to delete %s - %s\n", fnum_fname, smbcli_errstr(cli->tree)); } if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, path_fname))) { printf("Failed to delete %s - %s\n", path_fname, smbcli_errstr(cli->tree)); } return ret; }
/* test read ops */ static BOOL test_read(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_read io; NTSTATUS status; BOOL ret = True; int fnum; uint8_t *buf; const int maxsize = 90000; const char *fname = BASEDIR "\\test.txt"; const char *test_data = "TEST DATA"; uint_t seed = time(NULL); buf = talloc_zero_size(mem_ctx, maxsize); if (!torture_setup_dir(cli, BASEDIR)) { return False; } printf("Testing RAW_READ_READ\n"); io.generic.level = RAW_READ_READ; fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); if (fnum == -1) { printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Trying empty file read\n"); io.read.in.file.fnum = fnum; io.read.in.count = 1; io.read.in.offset = 0; io.read.in.remaining = 0; io.read.out.data = buf; status = smb_raw_read(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.read.out.nread, 0); printf("Trying zero file read\n"); io.read.in.count = 0; status = smb_raw_read(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.read.out.nread, 0); printf("Trying bad fnum\n"); io.read.in.file.fnum = fnum+1; status = smb_raw_read(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); io.read.in.file.fnum = fnum; smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data)); printf("Trying small read\n"); io.read.in.file.fnum = fnum; io.read.in.offset = 0; io.read.in.remaining = 0; io.read.in.count = strlen(test_data); status = smb_raw_read(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.read.out.nread, strlen(test_data)); if (memcmp(buf, test_data, strlen(test_data)) != 0) { ret = False; printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf); goto done; } printf("Trying short read\n"); io.read.in.offset = 1; io.read.in.count = strlen(test_data); status = smb_raw_read(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.read.out.nread, strlen(test_data)-1); if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) { ret = False; printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf); goto done; } if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) { printf("Trying max offset\n"); io.read.in.offset = ~0; io.read.in.count = strlen(test_data); status = smb_raw_read(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.read.out.nread, 0); } setup_buffer(buf, seed, maxsize); smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize); memset(buf, 0, maxsize); printf("Trying large read\n"); io.read.in.offset = 0; io.read.in.count = ~0; status = smb_raw_read(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_BUFFER(buf, seed, io.read.out.nread); printf("Trying locked region\n"); cli->session->pid++; if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) { printf("Failed to lock file at %d\n", __LINE__); ret = False; goto done; } cli->session->pid--; memset(buf, 0, maxsize); io.read.in.offset = 0; io.read.in.count = ~0; status = smb_raw_read(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); done: smbcli_close(cli->tree, fnum); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* test write ops */ static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_write io; NTSTATUS status; BOOL ret = True; int fnum; uint8_t *buf; const int maxsize = 90000; const char *fname = BASEDIR "\\test.txt"; uint_t seed = time(NULL); union smb_fileinfo finfo; buf = talloc_zero_size(mem_ctx, maxsize); if (!torture_setup_dir(cli, BASEDIR)) { return False; } printf("Testing RAW_WRITE_WRITE\n"); io.generic.level = RAW_WRITE_WRITE; fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); if (fnum == -1) { printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Trying zero write\n"); io.write.in.file.fnum = fnum; io.write.in.count = 0; io.write.in.offset = 0; io.write.in.remaining = 0; io.write.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.write.out.nwritten, 0); setup_buffer(buf, seed, maxsize); printf("Trying small write\n"); io.write.in.count = 9; io.write.in.offset = 4; io.write.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.write.out.nwritten, io.write.in.count); memset(buf, 0, maxsize); if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) { printf("read failed at %s\n", __location__); ret = False; goto done; } CHECK_BUFFER(buf+4, seed, 9); CHECK_VALUE(IVAL(buf,0), 0); setup_buffer(buf, seed, maxsize); printf("Trying large write\n"); io.write.in.count = 4000; io.write.in.offset = 0; io.write.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.write.out.nwritten, 4000); memset(buf, 0, maxsize); if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) { printf("read failed at %s\n", __location__); ret = False; goto done; } CHECK_BUFFER(buf, seed, 4000); printf("Trying bad fnum\n"); io.write.in.file.fnum = fnum+1; io.write.in.count = 4000; io.write.in.offset = 0; io.write.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("Setting file as sparse\n"); status = torture_set_sparse(cli->tree, fnum); CHECK_STATUS(status, NT_STATUS_OK); if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) { printf("skipping large file tests - CAP_LARGE_FILES not set\n"); goto done; } if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) { printf("skipping large file tests - CAP_LARGE_FILES not set\n"); goto done; } printf("Trying 2^32 offset\n"); setup_buffer(buf, seed, maxsize); io.write.in.file.fnum = fnum; io.write.in.count = 4000; io.write.in.offset = 0xFFFFFFFF - 2000; io.write.in.data = buf; status = smb_raw_write(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.write.out.nwritten, 4000); CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size); memset(buf, 0, maxsize); if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) { printf("read failed at %s\n", __location__); ret = False; goto done; } CHECK_BUFFER(buf, seed, 4000); done: smbcli_close(cli->tree, fnum); smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* test SMBntrename ops */ static bool test_ntrename(struct torture_context *tctx, struct smbcli_state *cli) { union smb_rename io; NTSTATUS status; bool ret = true; int fnum, i; const char *fname1 = BASEDIR "\\test1.txt"; const char *fname2 = BASEDIR "\\test2.txt"; union smb_fileinfo finfo; torture_comment(tctx, "Testing SMBntrename\n"); if (!torture_setup_dir(cli, BASEDIR)) { return false; } torture_comment(tctx, "Trying simple rename\n"); fnum = create_complex_file(cli, tctx, fname1); io.generic.level = RAW_RENAME_NTRENAME; io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.cluster_size = 0; io.ntrename.in.flags = RENAME_FLAG_RENAME; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); smbcli_close(cli->tree, fnum); status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying self rename\n"); io.ntrename.in.old_name = fname2; io.ntrename.in.new_name = fname2; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = 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.ntrename.in.old_name = BASEDIR "\\*.txt"; io.ntrename.in.new_name = fname1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); torture_comment(tctx, "Checking attrib handling\n"); torture_set_file_attribute(cli->tree, fname2, FILE_ATTRIBUTE_HIDDEN); io.ntrename.in.old_name = fname2; io.ntrename.in.new_name = fname1; io.ntrename.in.attrib = 0; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE); io.ntrename.in.attrib = FILE_ATTRIBUTE_HIDDEN; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL); torture_comment(tctx, "Checking hard link\n"); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.flags = RENAME_FLAG_HARD_LINK; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname2; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 2); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM); finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 2); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL); smbcli_unlink(cli->tree, fname2); finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL); torture_comment(tctx, "Checking copy\n"); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.flags = RENAME_FLAG_COPY; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname2; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname2; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL); finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM); torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL); smbcli_unlink(cli->tree, fname2); finfo.generic.in.file.path = fname1; status = smb_raw_pathinfo(cli->tree, tctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.all_info.out.nlink, 1); torture_comment(tctx, "Checking invalid flags\n"); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.flags = 0; status = smb_raw_rename(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) { CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } io.ntrename.in.flags = 300; status = smb_raw_rename(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) { CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } io.ntrename.in.flags = 0x106; status = smb_raw_rename(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) { CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); } else { CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); } torture_comment(tctx, "Checking unknown field\n"); io.ntrename.in.old_name = fname1; io.ntrename.in.new_name = fname2; io.ntrename.in.attrib = 0; io.ntrename.in.flags = RENAME_FLAG_RENAME; io.ntrename.in.cluster_size = 0xff; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "Trying RENAME_FLAG_MOVE_CLUSTER_INFORMATION\n"); io.ntrename.in.old_name = fname2; io.ntrename.in.new_name = fname1; io.ntrename.in.attrib = 0; io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION; io.ntrename.in.cluster_size = 1; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); io.ntrename.in.flags = RENAME_FLAG_COPY; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); #if 0 { char buf[16384]; fnum = smbcli_open(cli->tree, fname1, O_RDWR, DENY_NONE); memset(buf, 1, sizeof(buf)); smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)); smbcli_close(cli->tree, fnum); fnum = smbcli_open(cli->tree, fname2, O_RDWR, DENY_NONE); memset(buf, 1, sizeof(buf)); smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)-1); smbcli_close(cli->tree, fnum); torture_all_info(cli->tree, fname1); torture_all_info(cli->tree, fname2); } io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION; status = smb_raw_rename(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); for (i=0; i<20000; i++) { io.ntrename.in.cluster_size = i; status = smb_raw_rename(cli->tree, &io); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { torture_warning(tctx, "i=%d status=%s\n", i, nt_errstr(status)); } } #endif torture_comment(tctx, "Checking other flags\n"); for (i=0; i<0xFFF; i++) { if (i == RENAME_FLAG_RENAME || i == RENAME_FLAG_HARD_LINK || i == RENAME_FLAG_COPY) { continue; } io.ntrename.in.old_name = fname2; io.ntrename.in.new_name = fname1; io.ntrename.in.flags = i; io.ntrename.in.attrib = 0; io.ntrename.in.cluster_size = 0; status = smb_raw_rename(cli->tree, &io); if (TARGET_IS_WIN7(tctx)) { if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { torture_warning(tctx, "flags=0x%x status=%s\n", i, nt_errstr(status)); } } else { if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { torture_warning(tctx, "flags=0x%x status=%s\n", i, nt_errstr(status)); } } } done: smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* basic testing of all RAW_SEARCH_* calls using a single file */ static bool test_one_file(struct torture_context *tctx, struct smbcli_state *cli) { bool ret = true; int fnum; const char *fname = "\\torture_search.txt"; const char *fname2 = "\\torture_search-NOTEXIST.txt"; NTSTATUS status; int i; union smb_fileinfo all_info, alt_info, name_info, internal_info; union smb_search_data *s; fnum = create_complex_file(cli, tctx, fname); if (fnum == -1) { printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); ret = false; goto done; } /* call all the levels */ for (i=0;i<ARRAY_SIZE(levels);i++) { NTSTATUS expected_status; uint32_t cap = cli->transport->negotiate.capabilities; torture_comment(tctx, "testing %s\n", levels[i].name); levels[i].status = torture_single_search(cli, tctx, fname, levels[i].level, levels[i].data_level, 0, &levels[i].data); /* see if this server claims to support this level */ if ((cap & levels[i].capability_mask) != levels[i].capability_mask) { printf("search level %s(%d) not supported by server\n", levels[i].name, (int)levels[i].level); continue; } if (!NT_STATUS_IS_OK(levels[i].status)) { printf("search level %s(%d) failed - %s\n", levels[i].name, (int)levels[i].level, nt_errstr(levels[i].status)); ret = false; continue; } status = torture_single_search(cli, tctx, fname2, levels[i].level, levels[i].data_level, 0, &levels[i].data); expected_status = NT_STATUS_NO_SUCH_FILE; if (levels[i].level == RAW_SEARCH_SEARCH || levels[i].level == RAW_SEARCH_FFIRST || levels[i].level == RAW_SEARCH_FUNIQUE) { expected_status = STATUS_NO_MORE_FILES; } if (!NT_STATUS_EQUAL(status, expected_status)) { printf("search level %s(%d) should fail with %s - %s\n", levels[i].name, (int)levels[i].level, nt_errstr(expected_status), nt_errstr(status)); ret = false; } } /* get the all_info file into to check against */ all_info.generic.level = RAW_FILEINFO_ALL_INFO; all_info.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, tctx, &all_info); torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_ALL_INFO failed"); alt_info.generic.level = RAW_FILEINFO_ALT_NAME_INFO; alt_info.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, tctx, &alt_info); torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_ALT_NAME_INFO failed"); internal_info.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION; internal_info.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, tctx, &internal_info); torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_INTERNAL_INFORMATION failed"); name_info.generic.level = RAW_FILEINFO_NAME_INFO; name_info.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, tctx, &name_info); torture_assert_ntstatus_ok(tctx, status, "RAW_FILEINFO_NAME_INFO failed"); #define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if ((s->sname1.field1) != (v.sname2.out.field2)) { \ printf("(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \ __location__, \ #sname1, #field1, (int)s->sname1.field1, \ #sname2, #field2, (int)v.sname2.out.field2); \ ret = false; \ } \ }} while (0) #define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (s->sname1.field1 != (~1 & nt_time_to_unix(v.sname2.out.field2))) { \ printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, timestring(tctx, s->sname1.field1), \ #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \ ret = false; \ } \ }} while (0) #define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (s->sname1.field1 != v.sname2.out.field2) { \ printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, nt_time_string(tctx, s->sname1.field1), \ #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \ ret = false; \ } \ }} while (0) #define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1 || strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \ printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, s->sname1.field1, \ #sname2, #field2, v.sname2.out.field2.s); \ ret = false; \ } \ }} while (0) #define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1.s || \ strcmp(s->sname1.field1.s, v.sname2.out.field2.s) || \ wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \ printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ __location__, \ #sname1, #field1, s->sname1.field1.s, \ #sname2, #field2, v.sname2.out.field2.s); \ ret = false; \ } \ }} while (0) #define CHECK_NAME(name, sname1, field1, fname, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1.s || \ strcmp(s->sname1.field1.s, fname) || \ wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \ printf("(%s) %s/%s [%s] != %s\n", \ __location__, \ #sname1, #field1, s->sname1.field1.s, \ fname); \ ret = false; \ } \ }} while (0) #define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \ s = find(name); \ if (s) { \ if (!s->sname1.field1 || \ strcmp(s->sname1.field1, fname)) { \ printf("(%s) %s/%s [%s] != %s\n", \ __location__, \ #sname1, #field1, s->sname1.field1, \ fname); \ ret = false; \ } \ }} while (0) /* check that all the results are as expected */ CHECK_VAL("SEARCH", search, attrib, all_info, all_info, attrib&0xFFF); CHECK_VAL("STANDARD", standard, attrib, all_info, all_info, attrib&0xFFF); CHECK_VAL("EA_SIZE", ea_size, attrib, all_info, all_info, attrib&0xFFF); CHECK_VAL("DIRECTORY_INFO", directory_info, attrib, all_info, all_info, attrib); CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, attrib, all_info, all_info, attrib); CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, attrib, all_info, all_info, attrib); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, attrib, all_info, all_info, attrib); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, attrib, all_info, all_info, attrib); CHECK_TIME("SEARCH", search, write_time, all_info, all_info, write_time); CHECK_TIME("STANDARD", standard, write_time, all_info, all_info, write_time); CHECK_TIME("EA_SIZE", ea_size, write_time, all_info, all_info, write_time); CHECK_TIME("STANDARD", standard, create_time, all_info, all_info, create_time); CHECK_TIME("EA_SIZE", ea_size, create_time, all_info, all_info, create_time); CHECK_TIME("STANDARD", standard, access_time, all_info, all_info, access_time); CHECK_TIME("EA_SIZE", ea_size, access_time, all_info, all_info, access_time); CHECK_NTTIME("DIRECTORY_INFO", directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, write_time, all_info, all_info, write_time); CHECK_NTTIME("DIRECTORY_INFO", directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, create_time, all_info, all_info, create_time); CHECK_NTTIME("DIRECTORY_INFO", directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, access_time, all_info, all_info, access_time); CHECK_NTTIME("DIRECTORY_INFO", directory_info, change_time, all_info, all_info, change_time); CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, change_time, all_info, all_info, change_time); CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, change_time, all_info, all_info, change_time); CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, change_time, all_info, all_info, change_time); CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, change_time, all_info, all_info, change_time); CHECK_VAL("SEARCH", search, size, all_info, all_info, size); CHECK_VAL("STANDARD", standard, size, all_info, all_info, size); CHECK_VAL("EA_SIZE", ea_size, size, all_info, all_info, size); CHECK_VAL("DIRECTORY_INFO", directory_info, size, all_info, all_info, size); CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, size, all_info, all_info, size); CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, size, all_info, all_info, size); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, size, all_info, all_info, size); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, size, all_info, all_info, size); CHECK_VAL("UNIX_INFO", unix_info, size, all_info, all_info, size); CHECK_VAL("STANDARD", standard, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("EA_SIZE", ea_size, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("DIRECTORY_INFO", directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("UNIX_INFO", unix_info, alloc_size, all_info, all_info, alloc_size); CHECK_VAL("EA_SIZE", ea_size, ea_size, all_info, all_info, ea_size); CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, ea_size, all_info, all_info, ea_size); CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, ea_size, all_info, all_info, ea_size); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, ea_size, all_info, all_info, ea_size); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, ea_size, all_info, all_info, ea_size); CHECK_STR("SEARCH", search, name, alt_info, alt_name_info, fname); CHECK_WSTR("BOTH_DIRECTORY_INFO", both_directory_info, short_name, alt_info, alt_name_info, fname, STR_UNICODE); CHECK_NAME("STANDARD", standard, name, fname+1, 0); CHECK_NAME("EA_SIZE", ea_size, name, fname+1, 0); CHECK_NAME("DIRECTORY_INFO", directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("NAME_INFO", name_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_NAME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_UNIX_NAME("UNIX_INFO", unix_info, name, fname+1, STR_TERMINATE_ASCII); CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, file_id, internal_info, internal_information, file_id); CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, file_id, internal_info, internal_information, file_id); done: smb_raw_exit(cli->session); smbcli_unlink(cli->tree, fname); 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; }
/* benchmark open calls */ bool torture_bench_open(struct torture_context *torture) { bool ret = true; TALLOC_CTX *mem_ctx = talloc_new(torture); int i; int timelimit = torture_setting_int(torture, "timelimit", 10); struct timeval tv; struct benchopen_state *state; int total = 0; int total_retries = 0; int minops = 0; bool progress=false; progress = torture_setting_bool(torture, "progress", true); nprocs = torture_setting_int(torture, "nprocs", 4); state = talloc_zero_array(mem_ctx, struct benchopen_state, nprocs); printf("Opening %d connections\n", nprocs); for (i=0;i<nprocs;i++) { state[i].tctx = torture; state[i].mem_ctx = talloc_new(state); state[i].client_num = i; state[i].ev = torture->ev; if (!torture_open_connection_ev(&state[i].cli, i, torture, torture->ev)) { return false; } talloc_steal(mem_ctx, state); state[i].tree = state[i].cli->tree; state[i].dest_host = talloc_strdup(state[i].mem_ctx, state[i].cli->tree->session->transport->socket->hostname); state[i].dest_ports = talloc_array(state[i].mem_ctx, const char *, 2); state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports, "%u", state[i].cli->tree->session->transport->socket->port); state[i].dest_ports[1] = NULL; state[i].called_name = talloc_strdup(state[i].mem_ctx, state[i].cli->tree->session->transport->called.name); state[i].service_type = talloc_strdup(state[i].mem_ctx, state[i].cli->tree->device); } num_connected = i; if (!torture_setup_dir(state[0].cli, BASEDIR)) { goto failed; } fnames = talloc_array(mem_ctx, char *, 3*nprocs); for (i=0;i<3*nprocs;i++) { fnames[i] = talloc_asprintf(fnames, "%s\\file%d.dat", BASEDIR, i); } for (i=0;i<nprocs;i++) { /* all connections start with the same file */ state[i].next_file_num = 0; state[i].open_fnum = -1; state[i].close_fnum = -1; next_open(&state[i]); } tv = timeval_current(); if (progress) { report_te = event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state); } printf("Running for %d seconds\n", timelimit); while (timeval_elapsed(&tv) < timelimit) { event_loop_once(torture->ev); if (open_failed) { DEBUG(0,("open failed\n")); goto failed; } if (close_failed) { DEBUG(0,("open failed\n")); goto failed; } } talloc_free(report_te); if (progress) { for (i=0;i<nprocs;i++) { printf(" "); } printf("\r"); } minops = state[0].count; for (i=0;i<nprocs;i++) { total += state[i].count; total_retries += state[i].open_retries; printf("[%d] %u ops (%u retries)\n", i, state[i].count, state[i].open_retries); if (state[i].count < minops) minops = state[i].count; } printf("%.2f ops/second (%d retries)\n", total/timeval_elapsed(&tv), total_retries); if (minops < 0.5*total/nprocs) { printf("Failed: unbalanced open\n"); goto failed; } for (i=0;i<nprocs;i++) { talloc_free(state[i].req_open); talloc_free(state[i].req_close); smb_raw_exit(state[i].tree->session); } smbcli_deltree(state[0].tree, BASEDIR); talloc_free(mem_ctx); return ret; failed: talloc_free(mem_ctx); return false; }
/* test seek ops */ static BOOL test_seek(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_seek io; union smb_fileinfo finfo; union smb_setfileinfo sfinfo; NTSTATUS status; BOOL ret = True; int fnum, fnum2; const char *fname = BASEDIR "\\test.txt"; uint8_t c[2]; if (!torture_setup_dir(cli, BASEDIR)) { return False; } fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE); if (fnum == -1) { printf("Failed to open test.txt - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; printf("Trying bad handle\n"); io.lseek.in.file.fnum = fnum+1; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("Trying simple seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = 17; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 17); status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("Trying relative seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = -3; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 14); printf("Trying end seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_END; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, finfo.all_info.out.size); printf("Trying max seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = -1; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 0xffffffff); printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("Trying max overflow\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = 1000; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 999); printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("trying write to update offset\n"); ZERO_STRUCT(c); if (smbcli_write(cli->tree, fnum, 0, c, 0, 2) != 2) { printf("Write failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 2); if (smbcli_read(cli->tree, fnum, c, 0, 1) != 1) { printf("Read failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 1); status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 1); printf("Testing position information\n"); fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE); if (fnum2 == -1) { printf("2nd open failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; sfinfo.position_information.in.file.fnum = fnum2; sfinfo.position_information.in.position = 25; status = smb_raw_setfileinfo(cli->tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum2; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 25); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 1); printf("position_information via paths\n"); sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; sfinfo.position_information.in.file.path = fname; sfinfo.position_information.in.position = 32; status = smb_raw_setpathinfo(cli->tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum2; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 25); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); done: smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
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; }
/** * 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; }
/* basic testing of all RAW_CLOSE_* calls */ BOOL torture_raw_close(struct torture_context *torture) { struct smbcli_state *cli; BOOL ret = True; TALLOC_CTX *mem_ctx; union smb_close io; union smb_flush io_flush; int fnum; const char *fname = "\\torture_close.txt"; time_t basetime = (time(NULL) + 3*86400) & ~1; union smb_fileinfo finfo, finfo2; NTSTATUS status; if (!torture_open_connection(&cli, 0)) { return False; } mem_ctx = talloc_init("torture_raw_close"); #define REOPEN do { \ fnum = create_complex_file(cli, mem_ctx, fname); \ if (fnum == -1) { \ printf("(%d) Failed to create %s\n", __LINE__, fname); \ ret = False; \ goto done; \ }} while (0) #define CHECK_STATUS(status, correct) do { \ if (!NT_STATUS_EQUAL(status, correct)) { \ printf("(%d) Incorrect status %s - should be %s\n", \ __LINE__, nt_errstr(status), nt_errstr(correct)); \ ret = False; \ goto done; \ }} while (0) REOPEN; io.close.level = RAW_CLOSE_CLOSE; io.close.in.file.fnum = fnum; io.close.in.write_time = basetime; status = smb_raw_close(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smb_raw_close(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("testing close.in.write_time\n"); /* the file should have the write time set */ finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); if (basetime != nt_time_to_unix(finfo.all_info.out.write_time)) { printf("Incorrect write time on file - %s - %s\n", timestring(mem_ctx, basetime), nt_time_string(mem_ctx, finfo.all_info.out.write_time)); dump_all_info(mem_ctx, &finfo); ret = False; } printf("testing other times\n"); /* none of the other times should be set to that time */ if (nt_time_equal(&finfo.all_info.out.write_time, &finfo.all_info.out.access_time) || nt_time_equal(&finfo.all_info.out.write_time, &finfo.all_info.out.create_time) || nt_time_equal(&finfo.all_info.out.write_time, &finfo.all_info.out.change_time)) { printf("Incorrect times after close - only write time should be set\n"); dump_all_info(mem_ctx, &finfo); ret = False; } smbcli_unlink(cli->tree, fname); REOPEN; finfo2.generic.level = RAW_FILEINFO_ALL_INFO; finfo2.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2); CHECK_STATUS(status, NT_STATUS_OK); io.close.level = RAW_CLOSE_CLOSE; io.close.in.file.fnum = fnum; io.close.in.write_time = 0; status = smb_raw_close(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); /* the file should have the write time set equal to access time */ finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.generic.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); if (!nt_time_equal(&finfo.all_info.out.write_time, &finfo2.all_info.out.write_time)) { printf("Incorrect write time on file - 0 time should be ignored\n"); dump_all_info(mem_ctx, &finfo); ret = False; } printf("testing splclose\n"); /* check splclose on a file */ REOPEN; io.splclose.level = RAW_CLOSE_SPLCLOSE; io.splclose.in.file.fnum = fnum; status = smb_raw_close(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror)); printf("testing flush\n"); smbcli_close(cli->tree, fnum); io_flush.flush.level = RAW_FLUSH_FLUSH; io_flush.flush.in.file.fnum = fnum; status = smb_raw_flush(cli->tree, &io_flush); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); io_flush.flush_all.level = RAW_FLUSH_ALL; status = smb_raw_flush(cli->tree, &io_flush); CHECK_STATUS(status, NT_STATUS_OK); REOPEN; io_flush.flush.level = RAW_FLUSH_FLUSH; io_flush.flush.in.file.fnum = fnum; status = smb_raw_flush(cli->tree, &io_flush); CHECK_STATUS(status, NT_STATUS_OK); printf("Testing SMBexit\n"); smb_raw_exit(cli->session); io_flush.flush.level = RAW_FLUSH_FLUSH; io_flush.flush.in.file.fnum = fnum; status = smb_raw_flush(cli->tree, &io_flush); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); done: smbcli_close(cli->tree, fnum); smbcli_unlink(cli->tree, fname); torture_close_connection(cli); talloc_free(mem_ctx); return ret; }