static int /* O - 0 = success, non-0 = failure */ smb_print(struct smbcli_state *cli, /* I - SMB connection */ char *title, /* I - Title/job name */ FILE *fp) /* I - File to print */ { int fnum; /* File number */ int nbytes, /* Number of bytes read */ tbytes; /* Total bytes read */ char buffer[8192], /* Buffer for copy */ *ptr; /* Pointer into tile */ /* * Sanitize the title... */ for (ptr = title; *ptr; ptr ++) if (!isalnum((int)*ptr) && !isspace((int)*ptr)) *ptr = '_'; /* * Open the printer device... */ if ((fnum = smbcli_open(cli, title, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE)) == -1) { fprintf(stderr, "ERROR: %s opening remote file %s\n", smbcli_errstr(cli), title); return (1); } /* * Copy the file to the printer... */ if (fp != stdin) rewind(fp); tbytes = 0; while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) { if (smbcli_write(cli, fnum, 0, buffer, tbytes, nbytes) != nbytes) { fprintf(stderr, "ERROR: Error writing file: %s\n", smbcli_errstr(cli)); break; } tbytes += nbytes; } if (!smbcli_close(cli, fnum)) { fprintf(stderr, "ERROR: %s closing remote file %s\n", smbcli_errstr(cli), title); return (1); } else return (0); }
bool torture_trans2_scan(struct torture_context *torture, struct smbcli_state *cli) { int op, level; const char *fname = "\\scanner.dat"; int fnum, dnum, qfnum; fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE); if (fnum == -1) { printf("file open failed - %s\n", smbcli_errstr(cli->tree)); } dnum = smbcli_nt_create_full(cli->tree, "\\", 0, SEC_RIGHTS_FILE_READ, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN, NTCREATEX_OPTIONS_DIRECTORY, 0); if (dnum == -1) { printf("directory open failed - %s\n", smbcli_errstr(cli->tree)); } qfnum = smbcli_nt_create_full(cli->tree, "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION", NTCREATEX_FLAGS_EXTENDED, SEC_FLAG_MAXIMUM_ALLOWED, 0, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN, 0, 0); if (qfnum == -1) { printf("quota open failed - %s\n", smbcli_errstr(cli->tree)); } for (op=OP_MIN; op<=OP_MAX; op++) { if (!trans2_op_exists(cli, op)) { continue; } for (level = 0; level <= 50; level++) { scan_trans2(cli, op, level, fnum, dnum, qfnum, fname); } for (level = 0x100; level <= 0x130; level++) { scan_trans2(cli, op, level, fnum, dnum, qfnum, fname); } for (level = 1000; level < 1050; level++) { scan_trans2(cli, op, level, fnum, dnum, qfnum, fname); } } return true; }
/* test a write that hits a byte range lock and send the close after the write */ static bool test_mux_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_write io; NTSTATUS status; int fnum; bool ret = true; struct smbcli_request *req; printf("Testing multiplexed lock/write/close\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; } cli->session->pid = 1; /* lock a range */ if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 0, 4, 0, WRITE_LOCK))) { printf("lock failed in mux_write - %s\n", smbcli_errstr(cli->tree)); ret = false; goto done; } cli->session->pid = 2; /* send an async write */ io.generic.level = RAW_WRITE_WRITEX; 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 = 4; io.writex.in.data = (const uint8_t *)&fnum; req = smb_raw_write_send(cli->tree, &io); /* unlock the range */ cli->session->pid = 1; smbcli_unlock(cli->tree, fnum, 0, 4); /* and recv the async write reply */ status = smb_raw_write_recv(req, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); smbcli_close(cli->tree, fnum); done: return ret; }
/* basic testing of all RAW_FILEINFO_* calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ BOOL torture_raw_qfileinfo(struct torture_context *torture) { struct smbcli_state *cli; BOOL ret = True; TALLOC_CTX *mem_ctx; int fnum; const char *fname = "\\torture_qfileinfo.txt"; if (!torture_open_connection(&cli, 0)) { return False; } mem_ctx = talloc_init("torture_qfileinfo"); fnum = create_complex_file(cli, mem_ctx, fname); if (fnum == -1) { printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); ret = False; goto done; } ret = torture_raw_qfileinfo_internals(torture, mem_ctx, cli->tree, fnum, fname, False /* is_ipc */); smbcli_close(cli->tree, fnum); smbcli_unlink(cli->tree, fname); done: torture_close_connection(cli); talloc_free(mem_ctx); return ret; }
static bool find_single_info2(void *mem_ctx, struct torture_context *torture, struct smbcli_state *cli, const char *fname, struct unix_info2 *info2) { union smb_search_first search; NTSTATUS status; /* Set up a new search for a single item, not using resume keys. */ ZERO_STRUCT(search); search.t2ffirst.level = RAW_SEARCH_TRANS2; search.t2ffirst.data_level = SMB_FIND_UNIX_INFO2; search.t2ffirst.in.max_count = 1; search.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE; search.t2ffirst.in.pattern = fname; status = smb_raw_search_first(cli->tree, mem_ctx, &search, info2, search_callback); torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK, smbcli_errstr(cli->tree)); torture_assert_int_equal(torture, search.t2ffirst.out.count, 1, "expected exactly one result"); torture_assert_int_equal(torture, search.t2ffirst.out.end_of_search, 1, "expected end_of_search to be true"); return check_unix_info2(torture, info2); }
/* see how many RPC pipes we can open at once */ bool run_pipe_number(struct torture_context *tctx, struct smbcli_state *cli1) { const char *pipe_name = "\\WKSSVC"; int fnum; int num_pipes = 0; while(1) { fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0); if (fnum == -1) { torture_comment(tctx, "Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree)); break; } num_pipes++; if (torture_setting_bool(tctx, "progress", true)) { torture_comment(tctx, "%d\r", num_pipes); fflush(stdout); } } torture_comment(tctx, "pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name ); return true; }
bool torture_samba3_caseinsensitive(struct torture_context *torture) { struct smbcli_state *cli; TALLOC_CTX *mem_ctx; NTSTATUS status; const char *dirname = "insensitive"; const char *ucase_dirname = "InSeNsItIvE"; const char *fname = "foo"; char *fpath; int fnum; int counter = 0; bool ret = true; if (!(mem_ctx = talloc_init("torture_samba3_caseinsensitive"))) { d_printf("talloc_init failed\n"); return false; } if (!torture_open_connection(&cli, torture, 0)) { goto done; } smbcli_deltree(cli->tree, dirname); status = smbcli_mkdir(cli->tree, dirname); if (!NT_STATUS_IS_OK(status)) { d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status)); goto done; } if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) { goto done; } fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { d_printf("Could not create file %s: %s\n", fpath, smbcli_errstr(cli->tree)); goto done; } smbcli_close(cli->tree, fnum); smbcli_list(cli->tree, talloc_asprintf( mem_ctx, "%s\\*", ucase_dirname), FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN |FILE_ATTRIBUTE_SYSTEM, count_fn, (void *)&counter); if (counter == 3) { ret = true; } else { d_fprintf(stderr, "expected 3 entries, got %d\n", counter); ret = false; } done: talloc_free(mem_ctx); return ret; }
/* open a file N times on the server and just hold them open used for testing performance when there are N file handles alopenn */ bool torture_holdopen(struct torture_context *tctx, struct smbcli_state *cli) { int i, fnum; const char *fname = "\\holdopen.dat"; NTSTATUS status; smbcli_unlink(cli->tree, fname); fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); if (fnum == -1) { torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); return false; } smbcli_close(cli->tree, fnum); for (i=0;i<torture_numops;i++) { union smb_open op; op.generic.level = RAW_OPEN_NTCREATEX; op.ntcreatex.in.root_fid.fnum = 0; op.ntcreatex.in.flags = 0; op.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; op.ntcreatex.in.create_options = 0; op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; op.ntcreatex.in.alloc_size = 0; op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; op.ntcreatex.in.security_flags = 0; op.ntcreatex.in.fname = fname; status = smb_raw_open(cli->tree, tctx, &op); if (!NT_STATUS_IS_OK(status)) { torture_warning(tctx, "open %d failed\n", i); continue; } if (torture_setting_bool(tctx, "progress", true)) { torture_comment(tctx, "opened %d file\r", i); fflush(stdout); } } torture_comment(tctx, "\nStarting pings\n"); while (1) { struct smb_echo ec; status = smb_raw_echo(cli->transport, &ec); torture_comment(tctx, "."); fflush(stdout); sleep(15); } return true; }
/* callback function for torture_deltree() */ static void delete_fn(struct clilist_file_info *finfo, const char *name, void *state) { struct delete_state *dstate = (struct delete_state *)state; char *s, *n; if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) { return; } n = strdup(name); n[strlen(n)-1] = 0; asprintf(&s, "%s%s", n, finfo->name); if (finfo->attrib & FILE_ATTRIBUTE_READONLY) { if (NT_STATUS_IS_ERR(smbcli_setatr(dstate->tree, s, 0, 0))) { DEBUG(2,("Failed to remove READONLY on %s - %s\n", s, smbcli_errstr(dstate->tree))); } } if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) { char *s2; asprintf(&s2, "%s\\*", s); smbcli_unlink(dstate->tree, s2); smbcli_list(dstate->tree, s2, FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, delete_fn, state); free(s2); if (NT_STATUS_IS_ERR(smbcli_rmdir(dstate->tree, s))) { DEBUG(2,("Failed to delete %s - %s\n", s, smbcli_errstr(dstate->tree))); dstate->failed = true; } dstate->total_deleted++; } else { if (NT_STATUS_IS_ERR(smbcli_unlink(dstate->tree, s))) { DEBUG(2,("Failed to delete %s - %s\n", s, smbcli_errstr(dstate->tree))); dstate->failed = true; } dstate->total_deleted++; } free(s); free(n); }
/** 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; }
/* recursively descend a tree deleting all files returns the number of files deleted, or -1 on error */ int smbcli_deltree(struct smbcli_tree *tree, const char *dname) { char *mask; struct delete_state dstate; NTSTATUS status; dstate.tree = tree; dstate.total_deleted = 0; dstate.failed = false; /* it might be a file */ status = smbcli_unlink(tree, dname); if (NT_STATUS_IS_OK(smbcli_unlink(tree, dname))) { return 1; } if (NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_NAME_NOT_FOUND) || NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_PATH_NOT_FOUND) || NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_NO_SUCH_FILE) || NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_DOS(ERRDOS, ERRbadfile))) { return 0; } if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) { /* it could be read-only */ status = smbcli_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL, 0); if (NT_STATUS_IS_OK(smbcli_unlink(tree, dname))) { return 1; } } asprintf(&mask, "%s\\*", dname); smbcli_unlink(dstate.tree, mask); smbcli_list(dstate.tree, mask, FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, delete_fn, &dstate); free(mask); status = smbcli_rmdir(dstate.tree, dname); if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) { /* it could be read-only */ status = smbcli_setatr(dstate.tree, dname, FILE_ATTRIBUTE_NORMAL, 0); status = smbcli_rmdir(dstate.tree, dname); } if (NT_STATUS_IS_ERR(status)) { DEBUG(2,("Failed to delete %s - %s\n", dname, smbcli_errstr(dstate.tree))); return -1; } dstate.total_deleted++; if (dstate.failed) { return -1; } return dstate.total_deleted; }
/* sees what IOCTLs are supported */ bool torture_ioctl_test(struct torture_context *tctx, struct smbcli_state *cli) { uint16_t device, function; int fnum; const char *fname = "\\ioctl.dat"; NTSTATUS status; union smb_ioctl parms; TALLOC_CTX *mem_ctx; mem_ctx = talloc_named_const(tctx, 0, "ioctl_test"); smbcli_unlink(cli->tree, fname); fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); if (fnum == -1) { torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); return false; } parms.ioctl.level = RAW_IOCTL_IOCTL; parms.ioctl.in.file.fnum = fnum; parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO; status = smb_raw_ioctl(cli->tree, mem_ctx, &parms); torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree)); for (device=0;device<0x100;device++) { torture_comment(tctx, "testing device=0x%x\n", device); for (function=0;function<0x100;function++) { parms.ioctl.in.request = (device << 16) | function; status = smb_raw_ioctl(cli->tree, mem_ctx, &parms); if (NT_STATUS_IS_OK(status)) { torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n", device, function, (int)parms.ioctl.out.blob.length); } } } return true; }
static bool test_DeleteDir(struct smbcli_state *cli, const char *dir) { printf("Deleting directory %s\n", dir); if (smbcli_deltree(cli->tree, dir) == -1) { printf("Unable to delete dir %s - %s\n", dir, smbcli_errstr(cli->tree)); return false; } return true; }
bool torture_samba3_caseinsensitive(struct torture_context *torture, struct smbcli_state *cli) { TALLOC_CTX *mem_ctx; const char *dirname = "insensitive"; const char *ucase_dirname = "InSeNsItIvE"; const char *fname = "foo"; char *fpath; int fnum; int counter = 0; bool ret = false; if (!(mem_ctx = talloc_init("torture_samba3_caseinsensitive"))) { torture_result(torture, TORTURE_FAIL, "talloc_init failed\n"); return false; } torture_assert(torture, torture_setup_dir(cli, dirname), "creating test directory"); if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) { goto done; } fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { torture_result(torture, TORTURE_FAIL, "Could not create file %s: %s", fpath, smbcli_errstr(cli->tree)); goto done; } smbcli_close(cli->tree, fnum); smbcli_list(cli->tree, talloc_asprintf( mem_ctx, "%s\\*", ucase_dirname), FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN |FILE_ATTRIBUTE_SYSTEM, count_fn, (void *)&counter); if (counter == 3) { ret = true; } else { torture_result(torture, TORTURE_FAIL, "expected 3 entries, got %d", counter); ret = false; } done: talloc_free(mem_ctx); return ret; }
static bool gpo_sync_files(struct sync_context *ctx) { DEBUG(3,("calling cli_list with mask: %s\n", ctx->mask)); if (smbcli_list(ctx->cli->tree, ctx->mask, ctx->attribute, gpo_sync_func, ctx) == -1) { DEBUG(1,("listing [%s] failed with error: %s\n", ctx->mask, smbcli_errstr(ctx->cli->tree))); return false; } return true; }
/* test disconnect with timed lock */ static bool test_disconnect_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_lock io; NTSTATUS status; int fnum; struct smbcli_request *req; struct smb_lock_entry lock[1]; printf("trying disconnect with async lock\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)); return false; } 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 = 3000; req = smb_raw_lock_send(cli->tree, &io); if (!req) { printf("test_disconnect_lock: smb_raw_lock_send() " "returned NULL\n"); return false; } status = smbcli_chkpath(cli->tree, "\\"); CHECK_STATUS(status, NT_STATUS_OK); talloc_free(cli); return true; }
static bool query_file_path_info2(void *mem_ctx, struct torture_context *torture, struct smbcli_state *cli, int fnum, const char *fname, struct unix_info2 *info2) { NTSTATUS result; union smb_fileinfo finfo; finfo.generic.level = RAW_FILEINFO_UNIX_INFO2; if (fname) { finfo.generic.in.file.path = fname; result = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); } else { finfo.generic.in.file.fnum = fnum; result = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); } torture_assert_ntstatus_equal(torture, result, NT_STATUS_OK, smbcli_errstr(cli->tree)); info2->end_of_file = finfo.unix_info2.out.end_of_file; info2->num_bytes = finfo.unix_info2.out.num_bytes; info2->status_change_time = finfo.unix_info2.out.status_change_time; info2->access_time = finfo.unix_info2.out.access_time; info2->change_time = finfo.unix_info2.out.change_time; info2->uid = finfo.unix_info2.out.uid; info2->gid = finfo.unix_info2.out.gid; info2->file_type = finfo.unix_info2.out.file_type; info2->dev_major = finfo.unix_info2.out.dev_major; info2->dev_minor = finfo.unix_info2.out.dev_minor; info2->unique_id = finfo.unix_info2.out.unique_id; info2->permissions = finfo.unix_info2.out.permissions; info2->nlink = finfo.unix_info2.out.nlink; info2->create_time = finfo.unix_info2.out.create_time; info2->file_flags = finfo.unix_info2.out.file_flags; info2->flags_mask = finfo.unix_info2.out.flags_mask; if (!check_unix_info2(torture, info2)) { return false; } return true; }
/* check that a stream has the right contents */ static BOOL check_stream(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname, const char *sname, const char *value) { int fnum; const char *full_name; uint8_t *buf; ssize_t ret; full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname); fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE); if (value == NULL) { if (fnum != -1) { printf("should have failed stream open of %s\n", full_name); return False; } return True; } if (fnum == -1) { printf("Failed to open stream '%s' - %s\n", full_name, smbcli_errstr(cli->tree)); return False; } buf = talloc_size(mem_ctx, strlen(value)+11); ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11); if (ret != strlen(value)) { printf("Failed to read %lu bytes from stream '%s' - got %d\n", (long)strlen(value), full_name, (int)ret); return False; } if (memcmp(buf, value, strlen(value)) != 0) { printf("Bad data in stream\n"); return False; } smbcli_close(cli->tree, fnum); return True; }
/* basic testing of all RAW_FILEINFO_* calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ bool torture_raw_qfileinfo(struct torture_context *torture, struct smbcli_state *cli) { int fnum; bool ret; const char *fname = "\\torture_qfileinfo.txt"; fnum = create_complex_file(cli, torture, fname); if (fnum == -1) { printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); return false; } ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, false /* is_ipc */); smbcli_close(cli->tree, fnum); smbcli_unlink(cli->tree, fname); return ret; }
bool torture_samba3_badpath(struct torture_context *torture) { struct smbcli_state *cli_nt = NULL; struct smbcli_state *cli_dos = NULL; const char *fname = "test.txt"; const char *fname1 = "test1.txt"; const char *dirname = "testdir"; char *fpath; char *fpath1; int fnum; NTSTATUS status; bool ret = true; TALLOC_CTX *mem_ctx; bool nt_status_support; torture_assert(torture, mem_ctx = talloc_init("torture_samba3_badpath"), "talloc_init failed"); nt_status_support = lpcfg_nt_status_support(torture->lp_ctx); torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes"), ret, fail, "Could not set 'nt status support = yes'\n"); torture_assert_goto(torture, torture_open_connection(&cli_nt, torture, 0), ret, fail, "Could not open NTSTATUS connection\n"); torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no"), ret, fail, "Could not set 'nt status support = no'\n"); torture_assert_goto(torture, torture_open_connection(&cli_dos, torture, 1), ret, fail, "Could not open DOS connection\n"); torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", nt_status_support ? "yes":"no"), ret, fail, "Could not set 'nt status support' back to where it was\n"); torture_assert(torture, torture_setup_dir(cli_nt, dirname), "creating test directory"); status = smbcli_chkpath(cli_nt->tree, dirname); CHECK_STATUS(torture, status, NT_STATUS_OK); status = smbcli_chkpath(cli_nt->tree, talloc_asprintf(mem_ctx, "%s\\bla", dirname)); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND); status = smbcli_chkpath(cli_dos->tree, talloc_asprintf(mem_ctx, "%s\\bla", dirname)); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, talloc_asprintf(mem_ctx, "%s\\bla\\blub", dirname)); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_PATH_NOT_FOUND); status = smbcli_chkpath(cli_dos->tree, talloc_asprintf(mem_ctx, "%s\\bla\\blub", dirname)); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); torture_assert_goto(torture, fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname), ret, fail, "Could not allocate fpath\n"); fnum = smbcli_open(cli_nt->tree, fpath, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { torture_result(torture, TORTURE_FAIL, "Could not create file %s: %s\n", fpath, smbcli_errstr(cli_nt->tree)); goto fail; } smbcli_close(cli_nt->tree, fnum); if (!(fpath1 = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname1))) { goto fail; } fnum = smbcli_open(cli_nt->tree, fpath1, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { torture_result(torture, TORTURE_FAIL, "Could not create file %s: %s\n", fpath1, smbcli_errstr(cli_nt->tree)); goto fail; } smbcli_close(cli_nt->tree, fnum); /* * Do a whole bunch of error code checks on chkpath */ status = smbcli_chkpath(cli_nt->tree, fpath); CHECK_STATUS(torture, status, NT_STATUS_NOT_A_DIRECTORY); status = smbcli_chkpath(cli_dos->tree, fpath); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, ".."); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); status = smbcli_chkpath(cli_dos->tree, ".."); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath)); status = smbcli_chkpath(cli_nt->tree, "."); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "."); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, "\t"); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "\t"); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, "\t\\bla"); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "\t\\bla"); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, "<"); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "<"); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, "<\\bla"); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "<\\bla"); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); /* * .... And the same gang against getatr. Note that the DOS error codes * differ.... */ status = smbcli_getatr(cli_nt->tree, fpath, NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_OK); status = smbcli_getatr(cli_dos->tree, fpath, NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_OK); status = smbcli_getatr(cli_nt->tree, "..", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); status = smbcli_getatr(cli_dos->tree, "..", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath)); status = smbcli_getatr(cli_nt->tree, ".", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, ".", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = smbcli_getatr(cli_nt->tree, "\t", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, "\t", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = smbcli_getatr(cli_nt->tree, "\t\\bla", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, "\t\\bla", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = smbcli_getatr(cli_nt->tree, "<", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, "<", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = smbcli_getatr(cli_nt->tree, "<\\bla", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, "<\\bla", NULL, NULL, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); /* Try the same set with openX. */ status = raw_smbcli_open(cli_nt->tree, "..", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); status = raw_smbcli_open(cli_dos->tree, "..", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath)); status = raw_smbcli_open(cli_nt->tree, ".", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, ".", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = raw_smbcli_open(cli_nt->tree, "\t", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, "\t", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = raw_smbcli_open(cli_nt->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = raw_smbcli_open(cli_nt->tree, "<", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, "<", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = raw_smbcli_open(cli_nt->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); /* Let's test EEXIST error code mapping. */ status = raw_smbcli_open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION); status = raw_smbcli_open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRfilexists)); status = raw_smbcli_t2open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED) || !torture_setting_bool(torture, "samba3", false)) { /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION); } status = raw_smbcli_t2open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS,ERReasnotsupported)) || !torture_setting_bool(torture, "samba3", false)) { /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRfilexists)); } status = raw_smbcli_ntcreate(cli_nt->tree, fpath, NULL); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION); status = raw_smbcli_ntcreate(cli_dos->tree, fpath, NULL); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRfilexists)); /* Try the rename test. */ { union smb_rename io; memset(&io, '\0', sizeof(io)); io.rename.in.pattern1 = fpath1; io.rename.in.pattern2 = fpath; /* Try with SMBmv rename. */ status = smb_raw_rename(cli_nt->tree, &io); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION); status = smb_raw_rename(cli_dos->tree, &io); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRrename)); /* Try with NT rename. */ io.generic.level = RAW_RENAME_NTRENAME; io.ntrename.in.old_name = fpath1; io.ntrename.in.new_name = fpath; io.ntrename.in.attrib = 0; io.ntrename.in.cluster_size = 0; io.ntrename.in.flags = RENAME_FLAG_RENAME; status = smb_raw_rename(cli_nt->tree, &io); CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION); status = smb_raw_rename(cli_dos->tree, &io); CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRrename)); } goto done; fail: ret = false; done: if (cli_nt != NULL) { smbcli_deltree(cli_nt->tree, dirname); torture_close_connection(cli_nt); } if (cli_dos != NULL) { torture_close_connection(cli_dos); } talloc_free(mem_ctx); return ret; }
bool torture_samba3_checkfsp(struct torture_context *torture, struct smbcli_state *cli) { const char *fname = "test.txt"; const char *dirname = "testdir"; int fnum; NTSTATUS status; bool ret = true; TALLOC_CTX *mem_ctx; ssize_t nread; char buf[16]; struct smbcli_tree *tree2; torture_assert(torture, mem_ctx = talloc_init("torture_samba3_checkfsp"), "talloc_init failed\n"); torture_assert_ntstatus_equal(torture, torture_second_tcon(torture, cli->session, torture_setting_string(torture, "share", NULL), &tree2), NT_STATUS_OK, "creating second tcon"); /* Try a read on an invalid FID */ nread = smbcli_read(cli->tree, 4711, buf, 0, sizeof(buf)); CHECK_STATUS(torture, smbcli_nt_error(cli->tree), NT_STATUS_INVALID_HANDLE); /* Try a read on a directory handle */ torture_assert(torture, torture_setup_dir(cli, dirname), "creating test directory"); /* Open the directory */ { union smb_open io; io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.root_fid.fnum = 0; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.fname = dirname; status = smb_raw_open(cli->tree, mem_ctx, &io); if (!NT_STATUS_IS_OK(status)) { torture_result(torture, TORTURE_FAIL, "smb_open on the directory failed: %s\n", nt_errstr(status)); ret = false; goto done; } fnum = io.ntcreatex.out.file.fnum; } /* Try a read on the directory */ nread = smbcli_read(cli->tree, fnum, buf, 0, sizeof(buf)); if (nread >= 0) { torture_result(torture, TORTURE_FAIL, "smbcli_read on a directory succeeded, expected " "failure\n"); ret = false; } CHECK_STATUS(torture, smbcli_nt_error(cli->tree), NT_STATUS_INVALID_DEVICE_REQUEST); /* Same test on the second tcon */ nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf)); if (nread >= 0) { torture_result(torture, TORTURE_FAIL, "smbcli_read on a directory succeeded, expected " "failure\n"); ret = false; } CHECK_STATUS(torture, smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE); smbcli_close(cli->tree, fnum); /* Try a normal file read on a second tcon */ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); if (fnum == -1) { torture_result(torture, TORTURE_FAIL, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); ret = false; goto done; } nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf)); CHECK_STATUS(torture, smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE); smbcli_close(cli->tree, fnum); done: smbcli_deltree(cli->tree, dirname); talloc_free(mem_ctx); return ret; }
/* Test rename on files open with share delete and no share delete. */ bool torture_test_rename(struct torture_context *tctx, struct smbcli_state *cli1) { const char *fname = "\\test.txt"; const char *fname1 = "\\test1.txt"; int fnum1; smbcli_unlink(cli1->tree, fname); smbcli_unlink(cli1->tree, fname1); fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_RIGHTS_FILE_READ, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_READ, NTCREATEX_DISP_OVERWRITE_IF, 0, 0); torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "First open failed - %s", smbcli_errstr(cli1->tree))); torture_assert(tctx, NT_STATUS_IS_ERR(smbcli_rename(cli1->tree, fname, fname1)), "First rename succeeded - this should have failed !"); torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1), talloc_asprintf(tctx, "close - 1 failed (%s)", smbcli_errstr(cli1->tree))); smbcli_unlink(cli1->tree, fname); smbcli_unlink(cli1->tree, fname1); fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_RIGHTS_FILE_READ, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_DELETE|NTCREATEX_SHARE_ACCESS_READ, NTCREATEX_DISP_OVERWRITE_IF, 0, 0); torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "Second open failed - %s", smbcli_errstr(cli1->tree))); torture_assert_ntstatus_ok(tctx, smbcli_rename(cli1->tree, fname, fname1), talloc_asprintf(tctx, "Second rename failed - this should have succeeded - %s", smbcli_errstr(cli1->tree))); torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1), talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree))); smbcli_unlink(cli1->tree, fname); smbcli_unlink(cli1->tree, fname1); fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_STD_READ_CONTROL, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0); torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "Third open failed - %s", smbcli_errstr(cli1->tree))); torture_assert_ntstatus_ok(tctx, smbcli_rename(cli1->tree, fname, fname1), talloc_asprintf(tctx, "Third rename failed - this should have succeeded - %s", smbcli_errstr(cli1->tree))); torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1), talloc_asprintf(tctx, "close - 3 failed (%s)", smbcli_errstr(cli1->tree))); smbcli_unlink(cli1->tree, fname); smbcli_unlink(cli1->tree, fname1); return true; }
bool unix_torture_unix_info2(struct torture_context *torture) { void *mem_ctx; struct smbcli_state *cli; int fnum; struct unix_info2 pinfo, finfo; mem_ctx = talloc_init("smb_query_unix_info2"); torture_assert(torture, mem_ctx != NULL, "out of memory"); if (!(cli = connect_to_server(torture))) { talloc_free(mem_ctx); return false; } smbcli_unlink(cli->tree, FILENAME); fnum = create_file(cli, FILENAME); torture_assert(torture, fnum != -1, smbcli_errstr(cli->tree)); printf("checking SMB_QFILEINFO_UNIX_INFO2 for QueryFileInfo\n"); if (!query_file_info2(mem_ctx, torture, cli, fnum, &finfo)) { goto fail; } printf("checking SMB_QFILEINFO_UNIX_INFO2 for QueryPathInfo\n"); if (!query_path_info2(mem_ctx, torture, cli, FILENAME, &pinfo)) { goto fail; } if (!match_info2(torture, &pinfo, &finfo)) { goto fail; } printf("checking SMB_FIND_UNIX_INFO2 for FindFirst\n"); if (!find_single_info2(mem_ctx, torture, cli, FILENAME, &pinfo)) { goto fail; } if (!match_info2(torture, &pinfo, &finfo)) { goto fail; } /* XXX: should repeat this test with SetFileInfo. */ printf("checking SMB_SFILEINFO_UNIX_INFO2 for SetPathInfo\n"); if (!verify_setinfo_flags(mem_ctx, torture, cli, FILENAME)) { goto fail; } smbcli_close(cli->tree, fnum); smbcli_unlink(cli->tree, FILENAME); torture_close_connection(cli); talloc_free(mem_ctx); return true; fail: smbcli_close(cli->tree, fnum); smbcli_unlink(cli->tree, FILENAME); torture_close_connection(cli); talloc_free(mem_ctx); return false; }
/* test how many open files this server supports on the one socket */ bool run_maxfidtest(struct torture_context *tctx, struct smbcli_state *cli, int dummy) { #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d" char *fname; int fnums[0x11000], i; int retries=4, maxfid; bool correct = true; if (retries <= 0) { torture_comment(tctx, "failed to connect\n"); return false; } if (smbcli_deltree(cli->tree, "\\maxfid") == -1) { torture_comment(tctx, "Failed to deltree \\maxfid - %s\n", smbcli_errstr(cli->tree)); return false; } if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) { torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n", smbcli_errstr(cli->tree)); return false; } torture_comment(tctx, "Testing maximum number of open files\n"); for (i=0; i<0x11000; i++) { if (i % 1000 == 0) { asprintf(&fname, "\\maxfid\\fid%d", i/1000); if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) { torture_comment(tctx, "Failed to mkdir %s, error=%s\n", fname, smbcli_errstr(cli->tree)); return false; } free(fname); } asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid()); if ((fnums[i] = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) { torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); torture_comment(tctx, "maximum fnum is %d\n", i); break; } free(fname); if (torture_setting_bool(tctx, "progress", true)) { torture_comment(tctx, "%6d\r", i); fflush(stdout); } } torture_comment(tctx, "%6d\n", i); i--; maxfid = i; torture_comment(tctx, "cleaning up\n"); for (i=0;i<maxfid/2;i++) { asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid()); if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) { torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree)); } if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) { torture_comment(tctx, "unlink of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); correct = false; } free(fname); asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid()); if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) { torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree)); } if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) { torture_comment(tctx, "unlink of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); correct = false; } free(fname); if (torture_setting_bool(tctx, "progress", true)) { torture_comment(tctx, "%6d %6d\r", i, maxfid-i); fflush(stdout); } } torture_comment(tctx, "%6d\n", 0); if (smbcli_deltree(cli->tree, "\\maxfid") == -1) { torture_comment(tctx, "Failed to deltree \\maxfid - %s\n", smbcli_errstr(cli->tree)); return false; } torture_comment(tctx, "maxfid test finished\n"); if (!torture_close_connection(cli)) { correct = false; } return correct; #undef MAXFID_TEMPLATE }
static bool rw_torture(struct torture_context *tctx, struct smbcli_state *c) { const char *lockfname = "\\torture.lck"; char *fname; int fnum; int fnum2; pid_t pid2, pid = getpid(); int i, j; uint8_t buf[1024]; bool correct = true; fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL, DENY_NONE); if (fnum2 == -1) fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE); if (fnum2 == -1) { torture_comment(tctx, "open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree)); return false; } generate_random_buffer(buf, sizeof(buf)); for (i=0;i<torture_numops;i++) { uint_t n = (uint_t)random()%10; if (i % 10 == 0) { if (torture_setting_bool(tctx, "progress", true)) { torture_comment(tctx, "%d\r", i); fflush(stdout); } } asprintf(&fname, "\\torture.%u", n); if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) { return false; } fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL); if (fnum == -1) { torture_comment(tctx, "open failed (%s)\n", smbcli_errstr(c->tree)); correct = false; break; } if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) { torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree)); correct = false; } for (j=0;j<50;j++) { if (smbcli_write(c->tree, fnum, 0, buf, sizeof(pid)+(j*sizeof(buf)), sizeof(buf)) != sizeof(buf)) { torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree)); correct = false; } } pid2 = 0; if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) { torture_comment(tctx, "read failed (%s)\n", smbcli_errstr(c->tree)); correct = false; } if (pid2 != pid) { torture_comment(tctx, "data corruption!\n"); correct = false; } if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) { torture_comment(tctx, "close failed (%s)\n", smbcli_errstr(c->tree)); correct = false; } if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) { torture_comment(tctx, "unlink failed (%s)\n", smbcli_errstr(c->tree)); correct = false; } if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) { torture_comment(tctx, "unlock failed (%s)\n", smbcli_errstr(c->tree)); correct = false; } free(fname); } smbcli_close(c->tree, fnum2); smbcli_unlink(c->tree, lockfname); torture_comment(tctx, "%d\n", i); return correct; }
bool torture_samba3_posixtimedlock(struct torture_context *tctx, struct smbcli_state *cli) { NTSTATUS status; bool ret = true; const char *dirname = "posixlock"; const char *fname = "locked"; const char *fpath; const char *localdir; const char *localname; int fnum = -1; int fd = -1; struct flock posix_lock; union smb_lock io; struct smb_lock_entry lock_entry; struct smbcli_request *req; struct lock_result_state lock_result; struct tevent_timer *te; torture_assert(tctx, torture_setup_dir(cli, dirname), "creating test directory"); if (!(fpath = talloc_asprintf(tctx, "%s\\%s", dirname, fname))) { torture_warning(tctx, "talloc failed\n"); ret = false; goto done; } fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { torture_warning(tctx, "Could not create file %s: %s\n", fpath, smbcli_errstr(cli->tree)); ret = false; goto done; } if (!(localdir = torture_setting_string(tctx, "localdir", NULL))) { torture_warning(tctx, "Need 'localdir' setting\n"); ret = false; goto done; } if (!(localname = talloc_asprintf(tctx, "%s/%s/%s", localdir, dirname, fname))) { torture_warning(tctx, "talloc failed\n"); ret = false; goto done; } /* * Lock a byte range from posix */ fd = open(localname, O_RDWR); if (fd == -1) { torture_warning(tctx, "open(%s) failed: %s\n", localname, strerror(errno)); goto done; } posix_lock.l_type = F_WRLCK; posix_lock.l_whence = SEEK_SET; posix_lock.l_start = 0; posix_lock.l_len = 1; if (fcntl(fd, F_SETLK, &posix_lock) == -1) { torture_warning(tctx, "fcntl failed: %s\n", strerror(errno)); ret = false; goto done; } /* * Try a cifs brlock without timeout to see if posix locking = yes */ io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; lock_entry.count = 1; lock_entry.offset = 0; lock_entry.pid = cli->tree->session->pid; io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; io.lockx.in.timeout = 0; io.lockx.in.locks = &lock_entry; io.lockx.in.file.fnum = fnum; status = smb_raw_lock(cli->tree, &io); ret = true; CHECK_STATUS(tctx, status, NT_STATUS_FILE_LOCK_CONFLICT); if (!ret) { goto done; } /* * Now fire off a timed brlock, unlock the posix lock and see if the * timed lock gets through. */ io.lockx.in.timeout = 5000; req = smb_raw_lock_send(cli->tree, &io); if (req == NULL) { torture_warning(tctx, "smb_raw_lock_send failed\n"); ret = false; goto done; } lock_result.done = false; req->async.fn = receive_lock_result; req->async.private_data = &lock_result; te = tevent_add_timer(tctx->ev, tctx, timeval_current_ofs(1, 0), close_locked_file, &fd); if (te == NULL) { torture_warning(tctx, "tevent_add_timer failed\n"); ret = false; goto done; } while ((fd != -1) || (!lock_result.done)) { if (tevent_loop_once(tctx->ev) == -1) { torture_warning(tctx, "tevent_loop_once failed: %s\n", strerror(errno)); ret = false; goto done; } } CHECK_STATUS(tctx, lock_result.status, NT_STATUS_OK); done: if (fnum != -1) { smbcli_close(cli->tree, fnum); } if (fd != -1) { close(fd); } smbcli_deltree(cli->tree, dirname); return ret; }
/* test seek ops */ static BOOL test_seek(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_seek io; union smb_fileinfo finfo; union smb_setfileinfo sfinfo; NTSTATUS status; BOOL ret = True; int fnum, fnum2; const char *fname = BASEDIR "\\test.txt"; uint8_t c[2]; if (!torture_setup_dir(cli, BASEDIR)) { return False; } fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE); if (fnum == -1) { printf("Failed to open test.txt - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; printf("Trying bad handle\n"); io.lseek.in.file.fnum = fnum+1; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE); printf("Trying simple seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = 17; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 17); status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("Trying relative seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = -3; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 14); printf("Trying end seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_END; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_ALL_INFO; finfo.all_info.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, finfo.all_info.out.size); printf("Trying max seek\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_START; io.lseek.in.offset = -1; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 0xffffffff); printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("Trying max overflow\n"); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = 1000; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 999); printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); printf("trying write to update offset\n"); ZERO_STRUCT(c); if (smbcli_write(cli->tree, fnum, 0, c, 0, 2) != 2) { printf("Write failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); io.lseek.in.file.fnum = fnum; io.lseek.in.mode = SEEK_MODE_CURRENT; io.lseek.in.offset = 0; status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 2); if (smbcli_read(cli->tree, fnum, c, 0, 1) != 1) { printf("Read failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } printf("Testing position information change\n"); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 1); status = smb_raw_seek(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(io.lseek.out.offset, 1); printf("Testing position information\n"); fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE); if (fnum2 == -1) { printf("2nd open failed - %s\n", smbcli_errstr(cli->tree)); ret = False; goto done; } sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; sfinfo.position_information.in.file.fnum = fnum2; sfinfo.position_information.in.position = 25; status = smb_raw_setfileinfo(cli->tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum2; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 25); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 1); printf("position_information via paths\n"); sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; sfinfo.position_information.in.file.path = fname; sfinfo.position_information.in.position = 32; status = smb_raw_setpathinfo(cli->tree, &sfinfo); CHECK_STATUS(status, NT_STATUS_OK); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.fnum = fnum2; status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 25); finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION; finfo.position_information.in.file.path = fname; status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VALUE(finfo.position_information.out.position, 0); done: smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); return ret; }
/* basic testing of all RAW_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 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; }
/* basic testing of all RAW_FILEINFO_* calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ static bool torture_raw_qfileinfo_internals(struct torture_context *torture, TALLOC_CTX *mem_ctx, struct smbcli_tree *tree, int fnum, const char *fname, bool is_ipc) { int i; bool ret = true; int count; union smb_fileinfo *s1, *s2; NTTIME correct_time; uint64_t correct_size; uint32_t correct_attrib; const char *correct_name; bool skip_streams = false; /* scan all the fileinfo and pathinfo levels */ for (i=0; levels[i].name; i++) { if (!levels[i].only_paths) { levels[i].fnum_finfo.generic.level = levels[i].level; levels[i].fnum_finfo.generic.in.file.fnum = fnum; levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx, &levels[i].fnum_finfo); } if (!levels[i].only_handles) { levels[i].fname_finfo.generic.level = levels[i].level; levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname); levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx, &levels[i].fname_finfo); } } /* check for completely broken levels */ for (count=i=0; levels[i].name; i++) { uint32_t cap = tree->session->transport->negotiate.capabilities; /* see if this server claims to support this level */ if ((cap & levels[i].capability_mask) != levels[i].capability_mask) { continue; } if (is_ipc) { if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) { } else if (!levels[i].only_handles && NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_SUPPORTED)) { torture_warning(torture, "fname level %s %s", levels[i].name, nt_errstr(levels[i].fname_status)); continue; } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) { printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n", levels[i].name, nt_errstr(levels[i].fname_status)); count++; } if (!levels[i].only_paths && (NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fnum level %s %s", levels[i].name, nt_errstr(levels[i].fnum_status)); continue; } if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) { printf("ERROR: fnum level %s failed, expected %s - %s\n", levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status), nt_errstr(levels[i].fnum_status)); count++; } } else { if (!levels[i].only_paths && (NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fnum_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fnum level %s %s", levels[i].name, nt_errstr(levels[i].fnum_status)); continue; } if (!levels[i].only_handles && (NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_SUPPORTED) || NT_STATUS_EQUAL(levels[i].fname_status, NT_STATUS_NOT_IMPLEMENTED))) { torture_warning(torture, "fname level %s %s", levels[i].name, nt_errstr(levels[i].fname_status)); continue; } if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) { printf("ERROR: fnum level %s failed - %s\n", levels[i].name, nt_errstr(levels[i].fnum_status)); count++; } if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) { printf("ERROR: fname level %s failed - %s\n", levels[i].name, nt_errstr(levels[i].fname_status)); count++; } } } if (count != 0) { ret = false; printf("%d levels failed\n", count); if (count > 35) { torture_fail(torture, "too many level failures - giving up"); } } /* see if we can do streams */ s1 = fnum_find("STREAM_INFO"); if (!s1 || s1->stream_info.out.num_streams == 0) { if (!is_ipc) { printf("STREAM_INFO broken (%d) - skipping streams checks\n", s1 ? s1->stream_info.out.num_streams : -1); } skip_streams = true; } /* this code is incredibly repititive but doesn't lend itself to loops, so we use lots of macros to make it less painful */ /* first off we check the levels that are supposed to be aliases. It will be quite rare for this code to fail, but we need to check it for completeness */ #define ALIAS_CHECK(sname1, sname2) \ do { \ s1 = fnum_find(sname1); s2 = fnum_find(sname2); \ if (s1 && s2) { INFO_CHECK } \ s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2) { INFO_CHECK } \ s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2) { INFO_CHECK } \ } while (0) #define INFO_CHECK \ STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \ STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \ STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \ STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \ VAL_EQUAL (basic_info, attrib, basic_info, attrib); ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \ VAL_EQUAL(standard_info, size, standard_info, size); \ VAL_EQUAL(standard_info, nlink, standard_info, nlink); \ VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \ VAL_EQUAL(standard_info, directory, standard_info, directory); ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(ea_info, ea_size, ea_info, ea_size); ALIAS_CHECK("EA_INFO", "EA_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STR_EQUAL(name_info, fname, name_info, fname); ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STRUCT_EQUAL(all_info, create_time, all_info, create_time); \ STRUCT_EQUAL(all_info, access_time, all_info, access_time); \ STRUCT_EQUAL(all_info, write_time, all_info, write_time); \ STRUCT_EQUAL(all_info, change_time, all_info, change_time); \ VAL_EQUAL(all_info, attrib, all_info, attrib); \ VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \ VAL_EQUAL(all_info, size, all_info, size); \ VAL_EQUAL(all_info, nlink, all_info, nlink); \ VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \ VAL_EQUAL(all_info, directory, all_info, directory); \ VAL_EQUAL(all_info, ea_size, all_info, ea_size); \ STR_EQUAL(all_info, fname, all_info, fname); ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \ VAL_EQUAL(compression_info, format, compression_info, format); \ VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \ VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \ VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift); ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION"); #undef INFO_CHECK #define INFO_CHECK \ STR_EQUAL(alt_name_info, fname, alt_name_info, fname); ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION"); #define TIME_CHECK_NT(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ nt_time_string(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ nt_time_string(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #define TIME_CHECK_DOS(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #if 0 /* unused */ #define TIME_CHECK_UNX(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \ timestring(mem_ctx, s1->stype.out.tfield), \ nt_time_string(mem_ctx, correct_time)); \ ret = false; \ }} while (0) #endif /* now check that all the times that are supposed to be equal are correct */ s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.create_time; torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time); TIME_CHECK_DOS("GETATTRE", getattre, create_time); TIME_CHECK_DOS("STANDARD", standard, create_time); TIME_CHECK_DOS("EA_SIZE", ea_size, create_time); TIME_CHECK_NT ("ALL_INFO", all_info, create_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.access_time; torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time); TIME_CHECK_DOS("GETATTRE", getattre, access_time); TIME_CHECK_DOS("STANDARD", standard, access_time); TIME_CHECK_DOS("EA_SIZE", ea_size, access_time); TIME_CHECK_NT ("ALL_INFO", all_info, access_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.write_time; torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time); TIME_CHECK_DOS("GETATTR", getattr, write_time); TIME_CHECK_DOS("GETATTRE", getattre, write_time); TIME_CHECK_DOS("STANDARD", standard, write_time); TIME_CHECK_DOS("EA_SIZE", ea_size, write_time); TIME_CHECK_NT ("ALL_INFO", all_info, write_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time); s1 = fnum_find("BASIC_INFO"); correct_time = s1->basic_info.out.change_time; torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time)); TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time); TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time); TIME_CHECK_NT ("ALL_INFO", all_info, change_time); TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time); #define SIZE_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != correct_size) { \ printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_size); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != correct_size) { \ printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_size); \ ret = false; \ }} while (0) s1 = fnum_find("STANDARD_INFO"); correct_size = s1->standard_info.out.size; torture_comment(torture, "size: %u\n", (unsigned int)correct_size); SIZE_CHECK("GETATTR", getattr, size); SIZE_CHECK("GETATTRE", getattre, size); SIZE_CHECK("STANDARD", standard, size); SIZE_CHECK("EA_SIZE", ea_size, size); SIZE_CHECK("STANDARD_INFO", standard_info, size); SIZE_CHECK("STANDARD_INFORMATION", standard_info, size); SIZE_CHECK("ALL_INFO", all_info, size); SIZE_CHECK("ALL_INFORMATION", all_info, size); SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size); SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size); SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size); if (!skip_streams) { SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size); SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size); } s1 = fnum_find("STANDARD_INFO"); correct_size = s1->standard_info.out.alloc_size; torture_comment(torture, "alloc_size: %u\n", (unsigned int)correct_size); SIZE_CHECK("GETATTRE", getattre, alloc_size); SIZE_CHECK("STANDARD", standard, alloc_size); SIZE_CHECK("EA_SIZE", ea_size, alloc_size); SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size); SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size); SIZE_CHECK("ALL_INFO", all_info, alloc_size); SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size); SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size); if (!skip_streams) { SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size); SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size); } #define ATTRIB_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != correct_attrib) { \ printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_attrib); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != correct_attrib) { \ printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \ (unsigned int)s1->stype.out.tfield, \ (unsigned int)correct_attrib); \ ret = false; \ }} while (0) s1 = fnum_find("BASIC_INFO"); correct_attrib = s1->basic_info.out.attrib; torture_comment(torture, "attrib: 0x%x\n", (unsigned int)correct_attrib); ATTRIB_CHECK("GETATTR", getattr, attrib); if (!is_ipc) { ATTRIB_CHECK("GETATTRE", getattre, attrib); ATTRIB_CHECK("STANDARD", standard, attrib); ATTRIB_CHECK("EA_SIZE", ea_size, attrib); } ATTRIB_CHECK("BASIC_INFO", basic_info, attrib); ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib); ATTRIB_CHECK("ALL_INFO", all_info, attrib); ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib); ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib); ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib); correct_name = fname; torture_comment(torture, "name: %s\n", correct_name); #define NAME_CHECK(sname, stype, tfield, flags) do { \ s1 = fnum_find(sname); \ if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \ wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \ printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \ s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \ wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \ printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \ s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \ ret = false; \ }} while (0) NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE); NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE); /* the ALL_INFO file name is the full path on the filesystem */ s1 = fnum_find("ALL_INFO"); if (s1 && !s1->all_info.out.fname.s) { torture_fail(torture, "ALL_INFO didn't give a filename"); } if (s1 && s1->all_info.out.fname.s) { char *p = strrchr(s1->all_info.out.fname.s, '\\'); if (!p) { printf("Not a full path in all_info/fname? - '%s'\n", s1->all_info.out.fname.s); ret = false; } else { if (strcmp_safe(correct_name, p) != 0) { printf("incorrect basename in all_info/fname - '%s'\n", s1->all_info.out.fname.s); ret = false; } } if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) { printf("Should not null terminate all_info/fname\n"); ret = false; } } s1 = fnum_find("ALT_NAME_INFO"); if (s1) { correct_name = s1->alt_name_info.out.fname.s; } if (!correct_name) { torture_comment(torture, "no alternate name information\n"); } else { torture_comment(torture, "alt_name: %s\n", correct_name); NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE); NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE); /* and make sure we can open by alternate name */ smbcli_close(tree, fnum); fnum = smbcli_nt_create_full(tree, correct_name, 0, SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_DELETE| NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0); if (fnum == -1) { printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree)); ret = false; } if (!skip_streams) { correct_name = "::$DATA"; torture_comment(torture, "stream_name: %s\n", correct_name); NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE); NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE); } } /* make sure the EAs look right */ s1 = fnum_find("ALL_EAS"); s2 = fnum_find("ALL_INFO"); if (s1) { for (i=0;i<s1->all_eas.out.num_eas;i++) { printf(" flags=%d %s=%*.*s\n", s1->all_eas.out.eas[i].flags, s1->all_eas.out.eas[i].name.s, (int)s1->all_eas.out.eas[i].value.length, (int)s1->all_eas.out.eas[i].value.length, s1->all_eas.out.eas[i].value.data); } } if (s1 && s2) { if (s1->all_eas.out.num_eas == 0) { if (s2->all_info.out.ea_size != 0) { printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n", s2->all_info.out.ea_size); } } else { if (s2->all_info.out.ea_size != ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) { printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n", (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas), (int)s2->all_info.out.ea_size); } } } s2 = fname_find(is_ipc, "ALL_EAS"); if (s2) { VAL_EQUAL(all_eas, num_eas, all_eas, num_eas); for (i=0;i<s1->all_eas.out.num_eas;i++) { VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags); STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name); VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length); } } #define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \ s1 = fnum_find(sname1); s2 = fnum_find(sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ } \ s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \ printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \ #stype1, #tfield1, #stype2, #tfield2, \ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \ ret = false; \ }} while (0) VAL_CHECK("STANDARD_INFO", standard_info, delete_pending, "ALL_INFO", all_info, delete_pending); VAL_CHECK("STANDARD_INFO", standard_info, directory, "ALL_INFO", all_info, directory); VAL_CHECK("STANDARD_INFO", standard_info, nlink, "ALL_INFO", all_info, nlink); s1 = fnum_find("BASIC_INFO"); if (s1 && is_ipc) { if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) { printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, (int)FILE_ATTRIBUTE_NORMAL); ret = false; } } s1 = fnum_find("STANDARD_INFO"); if (s1 && is_ipc) { if (s1->standard_info.out.nlink != 1) { printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink); ret = false; } if (s1->standard_info.out.delete_pending != 1) { printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending); ret = false; } } VAL_CHECK("EA_INFO", ea_info, ea_size, "ALL_INFO", all_info, ea_size); if (!is_ipc) { VAL_CHECK("EA_SIZE", ea_size, ea_size, "ALL_INFO", all_info, ea_size); } #define NAME_PATH_CHECK(sname, stype, field) do { \ s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \ if (s1 && s2) { \ VAL_EQUAL(stype, field, stype, field); \ } \ } while (0) s1 = fnum_find("INTERNAL_INFORMATION"); if (s1) { torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id); } NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id); NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position); if (s1 && s2) { printf("fnum pos = %.0f, fname pos = %.0f\n", (double)s2->position_information.out.position, (double)s1->position_information.out.position ); } NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode); NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement); NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib); NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag); #if 0 /* these are expected to differ */ NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags); #endif #if 0 /* unused */ #define UNKNOWN_CHECK(sname, stype, tfield) do { \ s1 = fnum_find(sname); \ if (s1 && s1->stype.out.tfield != 0) { \ printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \ #stype, #tfield, \ (unsigned int)s1->stype.out.tfield); \ } \ s1 = fname_find(is_ipc, sname); \ if (s1 && s1->stype.out.tfield != 0) { \ printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \ #stype, #tfield, \ (unsigned int)s1->stype.out.tfield); \ }} while (0) #endif /* now get a bit fancier .... */ /* when we set the delete disposition then the link count should drop to 0 and delete_pending should be 1 */ return ret; }