wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
+401
View File
@@ -0,0 +1,401 @@
/*
Unix SMB/CIFS implementation.
SMB trans2 alias scanner
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "lib/util/dlinklist.h"
#include "libcli/raw/libcliraw.h"
#include "torture/torture.h"
#include "libcli/libcli.h"
#include "torture/util.h"
int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname);
struct trans2_blobs {
struct trans2_blobs *next, *prev;
uint16_t level;
DATA_BLOB params, data;
};
/* look for aliases for a query */
static bool gen_aliases(struct torture_context *tctx,
struct smbcli_state *cli, struct smb_trans2 *t2,
int level_offset)
{
uint16_t level;
struct trans2_blobs *alias_blobs = NULL;
struct trans2_blobs *t2b, *t2b2;
int count=0, alias_count=0;
for (level=0;level<2000;level++) {
NTSTATUS status;
SSVAL(t2->in.params.data, level_offset, level);
status = smb_raw_trans2(cli->tree, tctx, t2);
if (!NT_STATUS_IS_OK(status)) continue;
t2b = talloc(tctx, struct trans2_blobs);
t2b->level = level;
t2b->params = t2->out.params;
t2b->data = t2->out.data;
DLIST_ADD(alias_blobs, t2b);
torture_comment(tctx,
"\tFound level %4u (0x%03x) of size %3d (0x%02x)\n",
level, level,
(int)t2b->data.length, (int)t2b->data.length);
count++;
}
torture_comment(tctx, "Found %d levels with success status\n", count);
for (t2b=alias_blobs; t2b; t2b=t2b->next) {
for (t2b2=alias_blobs; t2b2; t2b2=t2b2->next) {
if (t2b->level >= t2b2->level) continue;
if (data_blob_equal(&t2b->params, &t2b2->params) &&
data_blob_equal(&t2b->data, &t2b2->data)) {
torture_comment(tctx,
"\tLevel %u (0x%x) and level %u (0x%x) are possible aliases\n",
t2b->level, t2b->level, t2b2->level, t2b2->level);
alias_count++;
}
}
}
torture_comment(tctx, "Found %d aliased levels\n", alias_count);
return true;
}
/* look for qfsinfo aliases */
static bool qfsinfo_aliases(struct torture_context *tctx,
struct smbcli_state *cli)
{
struct smb_trans2 t2;
uint16_t setup = TRANSACT2_QFSINFO;
t2.in.max_param = 0;
t2.in.max_data = smb_raw_max_trans_data(cli->tree, 0);
t2.in.max_setup = 0;
t2.in.flags = 0;
t2.in.timeout = 0;
t2.in.setup_count = 1;
t2.in.setup = &setup;
t2.in.params = data_blob(NULL, 2);
t2.in.data = data_blob(NULL, 0);
return gen_aliases(tctx, cli, &t2, 0);
}
/* look for qfileinfo aliases */
static bool qfileinfo_aliases(struct torture_context *tctx,
struct smbcli_state *cli)
{
struct smb_trans2 t2;
uint16_t setup = TRANSACT2_QFILEINFO;
const char *fname = "\\qfileinfo_aliases.txt";
int fnum;
t2.in.max_param = 2;
t2.in.max_data = smb_raw_max_trans_data(cli->tree, 2);
t2.in.max_setup = 0;
t2.in.flags = 0;
t2.in.timeout = 0;
t2.in.setup_count = 1;
t2.in.setup = &setup;
t2.in.params = data_blob(NULL, 4);
t2.in.data = data_blob(NULL, 0);
smbcli_unlink(cli->tree, fname);
fnum = create_complex_file(cli, cli, fname);
torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
"open of %s failed (%s)", fname,
smbcli_errstr(cli->tree)));
smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
SSVAL(t2.in.params.data, 0, fnum);
if (!gen_aliases(tctx, cli, &t2, 2))
return false;
smbcli_close(cli->tree, fnum);
smbcli_unlink(cli->tree, fname);
return true;
}
/* look for qpathinfo aliases */
static bool qpathinfo_aliases(struct torture_context *tctx,
struct smbcli_state *cli)
{
struct smb_trans2 t2;
uint16_t setup = TRANSACT2_QPATHINFO;
const char *fname = "\\qpathinfo_aliases.txt";
int fnum;
t2.in.max_param = 2;
t2.in.max_data = smb_raw_max_trans_data(cli->tree, 2);
t2.in.max_setup = 0;
t2.in.flags = 0;
t2.in.timeout = 0;
t2.in.setup_count = 1;
t2.in.setup = &setup;
t2.in.params = data_blob_talloc(tctx, NULL, 6);
t2.in.data = data_blob(NULL, 0);
smbcli_unlink(cli->tree, fname);
fnum = create_complex_file(cli, cli, fname);
torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
"open of %s failed (%s)", fname,
smbcli_errstr(cli->tree)));
smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
smbcli_close(cli->tree, fnum);
SIVAL(t2.in.params.data, 2, 0);
smbcli_blob_append_string(cli->session, tctx, &t2.in.params,
fname, STR_TERMINATE);
if (!gen_aliases(tctx, cli, &t2, 0))
return false;
smbcli_unlink(cli->tree, fname);
return true;
}
/* look for trans2 findfirst aliases */
static bool findfirst_aliases(struct torture_context *tctx,
struct smbcli_state *cli)
{
struct smb_trans2 t2;
uint16_t setup = TRANSACT2_FINDFIRST;
const char *fname = "\\findfirst_aliases.txt";
int fnum;
t2.in.max_param = 16;
t2.in.max_data = smb_raw_max_trans_data(cli->tree, 16);
t2.in.max_setup = 0;
t2.in.flags = 0;
t2.in.timeout = 0;
t2.in.setup_count = 1;
t2.in.setup = &setup;
t2.in.params = data_blob_talloc(tctx, NULL, 12);
t2.in.data = data_blob(NULL, 0);
smbcli_unlink(cli->tree, fname);
fnum = create_complex_file(cli, cli, fname);
torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
"open of %s failed (%s)", fname,
smbcli_errstr(cli->tree)));
smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
smbcli_close(cli->tree, fnum);
SSVAL(t2.in.params.data, 0, 0);
SSVAL(t2.in.params.data, 2, 1);
SSVAL(t2.in.params.data, 4, FLAG_TRANS2_FIND_CLOSE);
SSVAL(t2.in.params.data, 6, 0);
SIVAL(t2.in.params.data, 8, 0);
smbcli_blob_append_string(cli->session, tctx, &t2.in.params,
fname, STR_TERMINATE);
if (!gen_aliases(tctx, cli, &t2, 6))
return false;
smbcli_unlink(cli->tree, fname);
return true;
}
/* look for aliases for a set function */
static bool gen_set_aliases(struct torture_context *tctx,
struct smbcli_state *cli,
struct smb_trans2 *t2, int level_offset)
{
uint16_t level;
struct trans2_blobs *alias_blobs = NULL;
struct trans2_blobs *t2b;
int count=0, dsize;
for (level=1;level<1100;level++) {
NTSTATUS status, status1;
SSVAL(t2->in.params.data, level_offset, level);
status1 = NT_STATUS_OK;
for (dsize=2; dsize<1024; dsize += 2) {
data_blob_free(&t2->in.data);
t2->in.data = data_blob(NULL, dsize);
data_blob_clear(&t2->in.data);
status = smb_raw_trans2(cli->tree, tctx, t2);
/* some error codes mean that this whole level doesn't exist */
if (NT_STATUS_EQUAL(NT_STATUS_INVALID_LEVEL, status) ||
NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, status) ||
NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED, status)) {
break;
}
if (NT_STATUS_IS_OK(status)) break;
/* invalid parameter means that the level exists at this
size, but the contents are wrong (not surprising with
all zeros!) */
if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) break;
/* this is the usual code for 'wrong size' */
if (NT_STATUS_EQUAL(status, NT_STATUS_INFO_LENGTH_MISMATCH)) {
continue;
}
if (!NT_STATUS_EQUAL(status, status1)) {
torture_comment(tctx, "level=%d size=%d %s\n", level, dsize, nt_errstr(status));
}
status1 = status;
}
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) continue;
t2b = talloc(tctx, struct trans2_blobs);
t2b->level = level;
t2b->params = t2->out.params;
t2b->data = t2->out.data;
DLIST_ADD(alias_blobs, t2b);
torture_comment(tctx,
"\tFound level %4u (0x%03x) of size %3d (0x%02x)\n",
level, level,
(int)t2->in.data.length, (int)t2->in.data.length);
count++;
}
torture_comment(tctx, "Found %d valid levels\n", count);
return true;
}
/* look for setfileinfo aliases */
static bool setfileinfo_aliases(struct torture_context *tctx,
struct smbcli_state *cli)
{
struct smb_trans2 t2;
uint16_t setup = TRANSACT2_SETFILEINFO;
const char *fname = "\\setfileinfo_aliases.txt";
int fnum;
t2.in.max_param = 2;
t2.in.max_data = 0;
t2.in.max_setup = 0;
t2.in.flags = 0;
t2.in.timeout = 0;
t2.in.setup_count = 1;
t2.in.setup = &setup;
t2.in.params = data_blob(NULL, 6);
t2.in.data = data_blob(NULL, 0);
smbcli_unlink(cli->tree, fname);
fnum = create_complex_file(cli, cli, fname);
torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
"open of %s failed (%s)", fname,
smbcli_errstr(cli->tree)));
smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
SSVAL(t2.in.params.data, 0, fnum);
SSVAL(t2.in.params.data, 4, 0);
gen_set_aliases(tctx, cli, &t2, 2);
smbcli_close(cli->tree, fnum);
smbcli_unlink(cli->tree, fname);
return true;
}
/* look for setpathinfo aliases */
static bool setpathinfo_aliases(struct torture_context *tctx,
struct smbcli_state *cli)
{
struct smb_trans2 t2;
uint16_t setup = TRANSACT2_SETPATHINFO;
const char *fname = "\\setpathinfo_aliases.txt";
int fnum;
t2.in.max_param = 32;
t2.in.max_data = smb_raw_max_trans_data(cli->tree, 32);
t2.in.max_setup = 0;
t2.in.flags = 0;
t2.in.timeout = 0;
t2.in.setup_count = 1;
t2.in.setup = &setup;
t2.in.params = data_blob_talloc(tctx, NULL, 4);
t2.in.data = data_blob(NULL, 0);
smbcli_unlink(cli->tree, fname);
fnum = create_complex_file(cli, cli, fname);
torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
"open of %s failed (%s)", fname,
smbcli_errstr(cli->tree)));
smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
smbcli_close(cli->tree, fnum);
SSVAL(t2.in.params.data, 2, 0);
smbcli_blob_append_string(cli->session, tctx, &t2.in.params,
fname, STR_TERMINATE);
if (!gen_set_aliases(tctx, cli, &t2, 0))
return false;
torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli->tree, fname),
talloc_asprintf(tctx, "unlink: %s", smbcli_errstr(cli->tree)));
return true;
}
/* look for aliased info levels in trans2 calls */
struct torture_suite *torture_trans2_aliases(void)
{
struct torture_suite *suite = torture_suite_create(
talloc_autofree_context(),
"ALIASES");
torture_suite_add_1smb_test(suite, "QFILEINFO aliases",
qfsinfo_aliases);
torture_suite_add_1smb_test(suite, "QFSINFO aliases", qfileinfo_aliases);
torture_suite_add_1smb_test(suite, "QPATHINFO aliases", qpathinfo_aliases);
torture_suite_add_1smb_test(suite, "FINDFIRST aliases", findfirst_aliases);
torture_suite_add_1smb_test(suite, "setfileinfo_aliases",
setfileinfo_aliases);
torture_suite_add_1smb_test(suite, "setpathinfo_aliases",
setpathinfo_aliases);
return suite;
}
+184
View File
@@ -0,0 +1,184 @@
/*
Unix SMB/CIFS implementation.
openattr tester
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/libcli.h"
#include "torture/util.h"
extern int torture_failures;
#define CHECK_MAX_FAILURES(label) do { if (++failures >= torture_failures) goto label; } while (0)
static const uint32_t open_attrs_table[] = {
FILE_ATTRIBUTE_NORMAL,
FILE_ATTRIBUTE_ARCHIVE,
FILE_ATTRIBUTE_READONLY,
FILE_ATTRIBUTE_HIDDEN,
FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY,
FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN,
FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN,
FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN,
FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_SYSTEM,
};
struct trunc_open_results {
uint_t num;
uint32_t init_attr;
uint32_t trunc_attr;
uint32_t result_attr;
};
static const struct trunc_open_results attr_results[] = {
{ 0, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE },
{ 1, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE },
{ 2, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY },
{ 16, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE },
{ 17, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE },
{ 18, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY },
{ 51, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
{ 54, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
{ 56, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
{ 68, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
{ 71, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
{ 73, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM },
{ 99, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
{ 102, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
{ 104, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
{ 116, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
{ 119, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
{ 121, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM },
{ 170, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN },
{ 173, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM },
{ 227, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
{ 230, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
{ 232, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
{ 244, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
{ 247, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
{ 249, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM }
};
BOOL torture_openattrtest(struct torture_context *tctx,
struct smbcli_state *cli1)
{
const char *fname = "\\openattr.file";
int fnum1;
uint16_t attr;
uint_t i, j, k, l;
int failures = 0;
for (k = 0, i = 0; i < sizeof(open_attrs_table)/sizeof(uint32_t); i++) {
smbcli_setatr(cli1->tree, fname, 0, 0);
smbcli_unlink(cli1->tree, fname);
fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
SEC_FILE_WRITE_DATA,
open_attrs_table[i],
NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open %d (1) of %s failed (%s)", i,
fname, smbcli_errstr(cli1->tree)));
torture_assert_ntstatus_ok(tctx,
smbcli_close(cli1->tree, fnum1),
talloc_asprintf(tctx, "close %d (1) of %s failed (%s)", i, fname,
smbcli_errstr(cli1->tree)));
for (j = 0; j < ARRAY_SIZE(open_attrs_table); j++) {
fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
SEC_FILE_READ_DATA|
SEC_FILE_WRITE_DATA,
open_attrs_table[j],
NTCREATEX_SHARE_ACCESS_NONE,
NTCREATEX_DISP_OVERWRITE, 0, 0);
if (fnum1 == -1) {
for (l = 0; l < ARRAY_SIZE(attr_results); l++) {
if (attr_results[l].num == k) {
torture_comment(tctx, "[%d] trunc open 0x%x -> 0x%x of %s failed - should have succeeded !(%s)\n",
k, open_attrs_table[i],
open_attrs_table[j],
fname, smbcli_errstr(cli1->tree));
CHECK_MAX_FAILURES(error_exit);
}
}
torture_assert_ntstatus_equal(tctx,
smbcli_nt_error(cli1->tree), NT_STATUS_ACCESS_DENIED,
talloc_asprintf(tctx, "[%d] trunc open 0x%x -> 0x%x failed with wrong error code %s",
k, open_attrs_table[i], open_attrs_table[j],
smbcli_errstr(cli1->tree)));
CHECK_MAX_FAILURES(error_exit);
#if 0
torture_comment(tctx, "[%d] trunc open 0x%x -> 0x%x failed\n", k, open_attrs_table[i], open_attrs_table[j]);
#endif
k++;
continue;
}
torture_assert_ntstatus_ok(tctx,
smbcli_close(cli1->tree, fnum1),
talloc_asprintf(tctx, "close %d (2) of %s failed (%s)", j,
fname, smbcli_errstr(cli1->tree)));
torture_assert_ntstatus_ok(tctx,
smbcli_getatr(cli1->tree, fname, &attr, NULL, NULL),
talloc_asprintf(tctx, "getatr(2) failed (%s)", smbcli_errstr(cli1->tree)));
#if 0
torture_comment(tctx, "[%d] getatr check [0x%x] trunc [0x%x] got attr 0x%x\n",
k, open_attrs_table[i], open_attrs_table[j], attr );
#endif
for (l = 0; l < ARRAY_SIZE(attr_results); l++) {
if (attr_results[l].num == k) {
if (attr != attr_results[l].result_attr ||
open_attrs_table[i] != attr_results[l].init_attr ||
open_attrs_table[j] != attr_results[l].trunc_attr) {
torture_comment(tctx, "[%d] getatr check failed. [0x%x] trunc [0x%x] got attr 0x%x, should be 0x%x\n",
k, open_attrs_table[i],
open_attrs_table[j],
(uint_t)attr,
attr_results[l].result_attr);
CHECK_MAX_FAILURES(error_exit);
}
break;
}
}
k++;
}
}
error_exit:
smbcli_setatr(cli1->tree, fname, 0, 0);
smbcli_unlink(cli1->tree, fname);
return true;
}
File diff suppressed because it is too large Load Diff
+265
View File
@@ -0,0 +1,265 @@
/*
Unix SMB/CIFS implementation.
SMB torture tester - charset test routines
Copyright (C) Andrew Tridgell 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\chartest\\"
/*
open a file using a set of unicode code points for the name
the prefix BASEDIR is added before the name
*/
static NTSTATUS unicode_open(struct torture_context *tctx,
struct smbcli_tree *tree,
TALLOC_CTX *mem_ctx,
uint32_t open_disposition,
const uint32_t *u_name,
size_t u_name_len)
{
union smb_open io;
char *fname, *fname2=NULL, *ucs_name;
int i;
NTSTATUS status;
ucs_name = talloc_size(mem_ctx, (1+u_name_len)*2);
if (!ucs_name) {
printf("Failed to create UCS2 Name - talloc() failure\n");
return NT_STATUS_NO_MEMORY;
}
for (i=0;i<u_name_len;i++) {
SSVAL(ucs_name, i*2, u_name[i]);
}
SSVAL(ucs_name, i*2, 0);
i = convert_string_talloc(ucs_name, CH_UTF16, CH_UNIX, ucs_name, (1+u_name_len)*2, (void **)&fname);
if (i == -1) {
torture_comment(tctx, "Failed to convert UCS2 Name into unix - convert_string_talloc() failure\n");
talloc_free(ucs_name);
return NT_STATUS_NO_MEMORY;
}
fname2 = talloc_asprintf(ucs_name, "%s%s", BASEDIR, fname);
if (!fname2) {
talloc_free(ucs_name);
return NT_STATUS_NO_MEMORY;
}
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname2;
io.ntcreatex.in.open_disposition = open_disposition;
status = smb_raw_open(tree, mem_ctx, &io);
talloc_free(ucs_name);
return status;
}
/*
see if the server recognises composed characters
*/
static BOOL test_composed(struct torture_context *tctx,
struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
const uint32_t name1[] = {0x61, 0x308};
const uint32_t name2[] = {0xe4};
NTSTATUS status1, status2;
printf("Testing composite character (a umlaut)\n");
status1 = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name1, 2);
if (!NT_STATUS_IS_OK(status1)) {
printf("Failed to create composed name - %s\n",
nt_errstr(status1));
return False;
}
status2 = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name2, 1);
if (!NT_STATUS_IS_OK(status2)) {
printf("Failed to create accented character - %s\n",
nt_errstr(status2));
return False;
}
return True;
}
/*
see if the server recognises a naked diacritical
*/
static BOOL test_diacritical(struct torture_context *tctx,
struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
const uint32_t name1[] = {0x308};
const uint32_t name2[] = {0x308, 0x308};
NTSTATUS status1, status2;
printf("Testing naked diacritical (umlaut)\n");
status1 = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name1, 1);
if (!NT_STATUS_IS_OK(status1)) {
printf("Failed to create naked diacritical - %s\n",
nt_errstr(status1));
return False;
}
/* try a double diacritical */
status2 = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name2, 2);
if (!NT_STATUS_IS_OK(status2)) {
printf("Failed to create double naked diacritical - %s\n",
nt_errstr(status2));
return False;
}
return True;
}
/*
see if the server recognises a partial surrogate pair
*/
static BOOL test_surrogate(struct torture_context *tctx,
struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
const uint32_t name1[] = {0xd800};
const uint32_t name2[] = {0xdc00};
const uint32_t name3[] = {0xd800, 0xdc00};
NTSTATUS status;
printf("Testing partial surrogate\n");
status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name1, 1);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to create partial surrogate 1 - %s\n",
nt_errstr(status));
return False;
}
status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name2, 1);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to create partial surrogate 2 - %s\n",
nt_errstr(status));
return False;
}
status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name3, 2);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to create full surrogate - %s\n",
nt_errstr(status));
return False;
}
return True;
}
/*
see if the server recognises wide-a characters
*/
static BOOL test_widea(struct torture_context *tctx,
struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
const uint32_t name1[] = {'a'};
const uint32_t name2[] = {0xff41};
const uint32_t name3[] = {0xff21};
NTSTATUS status;
printf("Testing wide-a\n");
status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name1, 1);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to create 'a' - %s\n",
nt_errstr(status));
return False;
}
status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name2, 1);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to create wide-a - %s\n",
nt_errstr(status));
return False;
}
status = unicode_open(tctx, cli->tree, mem_ctx, NTCREATEX_DISP_CREATE, name3, 1);
if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
printf("Expected %s creating wide-A - %s\n",
nt_errstr(NT_STATUS_OBJECT_NAME_COLLISION),
nt_errstr(status));
return False;
}
return True;
}
BOOL torture_charset(struct torture_context *tctx, struct smbcli_state *cli)
{
BOOL ret = True;
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_init("torture_charset");
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
if (!test_composed(tctx, cli, mem_ctx)) {
ret = False;
}
if (!test_diacritical(tctx, cli, mem_ctx)) {
ret = False;
}
if (!test_surrogate(tctx, cli, mem_ctx)) {
ret = False;
}
if (!test_widea(tctx, cli, mem_ctx)) {
ret = False;
}
return ret;
}
+617
View File
@@ -0,0 +1,617 @@
/*
Unix SMB/CIFS implementation.
test suite for delayed write update
Copyright (C) Volker Lendecke 2004
Copyright (C) Andrew Tridgell 2004
Copyright (C) Jeremy Allison 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "system/time.h"
#include "system/filesys.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\delaywrite"
static BOOL test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
{
union smb_fileinfo finfo1, finfo2;
const char *fname = BASEDIR "\\torture_file.txt";
NTSTATUS status;
int fnum1 = -1;
BOOL ret = True;
ssize_t written;
time_t t;
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum1 == -1) {
torture_comment(tctx, "Failed to open %s\n", fname);
return False;
}
finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo1.basic_info.in.file.fnum = fnum1;
finfo2 = finfo1;
status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
return False;
}
torture_comment(tctx, "Initial write time %s\n",
nt_time_string(tctx, finfo1.basic_info.out.write_time));
/* 3 second delay to ensure we get past any 2 second time
granularity (older systems may have that) */
sleep(3);
written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
if (written != 1) {
torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
(int)written, __location__);
return False;
}
t = time(NULL);
while (time(NULL) < t+120) {
status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
ret = False;
break;
}
torture_comment(tctx, "write time %s\n",
nt_time_string(tctx, finfo2.basic_info.out.write_time));
if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server updated write_time after %d seconds\n",
(int)(time(NULL) - t));
break;
}
sleep(1);
fflush(stdout);
}
if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server did not update write time?!\n");
ret = False;
}
if (fnum1 != -1)
smbcli_close(cli->tree, fnum1);
smbcli_unlink(cli->tree, fname);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
* Do as above, but using 2 connections.
*/
static BOOL test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
struct smbcli_state *cli2)
{
union smb_fileinfo finfo1, finfo2;
const char *fname = BASEDIR "\\torture_file.txt";
NTSTATUS status;
int fnum1 = -1;
int fnum2 = -1;
BOOL ret = True;
ssize_t written;
time_t t;
union smb_flush flsh;
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum1 == -1) {
torture_comment(tctx, "Failed to open %s\n", fname);
return False;
}
finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo1.basic_info.in.file.fnum = fnum1;
finfo2 = finfo1;
status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
return False;
}
torture_comment(tctx, "Initial write time %s\n",
nt_time_string(tctx, finfo1.basic_info.out.write_time));
/* 3 second delay to ensure we get past any 2 second time
granularity (older systems may have that) */
sleep(3);
{
/* Try using setfileinfo instead of write to update write time. */
union smb_setfileinfo sfinfo;
time_t t_set = time(NULL);
sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
sfinfo.basic_info.in.file.fnum = fnum1;
sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
/* I tried this with both + and - ve to see if it makes a different.
It doesn't - once the filetime is set via setfileinfo it stays that way. */
#if 1
unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
#else
unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
#endif
sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
status = smb_raw_setfileinfo(cli->tree, &sfinfo);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("sfileinfo failed: %s\n", nt_errstr(status)));
return False;
}
}
t = time(NULL);
while (time(NULL) < t+120) {
finfo2.basic_info.in.file.path = fname;
status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
ret = False;
break;
}
torture_comment(tctx, "write time %s\n",
nt_time_string(tctx, finfo2.basic_info.out.write_time));
if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server updated write_time after %d seconds\n",
(int)(time(NULL) - t));
break;
}
sleep(1);
fflush(stdout);
}
if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server did not update write time?!\n");
ret = False;
}
/* Now try a write to see if the write time gets reset. */
finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo1.basic_info.in.file.fnum = fnum1;
finfo2 = finfo1;
status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
return False;
}
torture_comment(tctx, "Modified write time %s\n",
nt_time_string(tctx, finfo1.basic_info.out.write_time));
torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
if (written != 10) {
torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
(int)written, __location__);
return False;
}
/* Just to prove to tridge that the an smbflush has no effect on
the write time :-). The setfileinfo IS STICKY. JRA. */
torture_comment(tctx, "Doing flush after write\n");
flsh.flush.level = RAW_FLUSH_FLUSH;
flsh.flush.in.file.fnum = fnum1;
status = smb_raw_flush(cli->tree, &flsh);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
return False;
}
t = time(NULL);
/* Once the time was set using setfileinfo then it stays set - writes
don't have any effect. But make sure. */
while (time(NULL) < t+15) {
status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
ret = False;
break;
}
torture_comment(tctx, "write time %s\n",
nt_time_string(tctx, finfo2.basic_info.out.write_time));
if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server updated write_time after %d seconds\n",
(int)(time(NULL) - t));
break;
}
sleep(1);
fflush(stdout);
}
if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server did not update write time\n");
}
fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
if (fnum2 == -1) {
torture_comment(tctx, "Failed to open %s\n", fname);
return False;
}
torture_comment(tctx, "Doing a 10 byte write to extend the file via second fd and see if this changes the last write time.\n");
written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
if (written != 10) {
torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
(int)written, __location__);
return False;
}
status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
return False;
}
torture_comment(tctx, "write time %s\n",
nt_time_string(tctx, finfo2.basic_info.out.write_time));
if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server updated write_time\n");
}
torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
smbcli_close(cli->tree, fnum1);
fnum1 = -1;
torture_comment(tctx, "Doing a 10 byte write to extend the file via second fd and see if this changes the last write time.\n");
written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
if (written != 10) {
torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
(int)written, __location__);
return False;
}
finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo1.basic_info.in.file.fnum = fnum2;
finfo2 = finfo1;
status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
return False;
}
torture_comment(tctx, "write time %s\n",
nt_time_string(tctx, finfo2.basic_info.out.write_time));
if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server updated write_time\n");
}
t = time(NULL);
/* Once the time was set using setfileinfo then it stays set - writes
don't have any effect. But make sure. */
while (time(NULL) < t+15) {
status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
ret = False;
break;
}
torture_comment(tctx, "write time %s\n",
nt_time_string(tctx, finfo2.basic_info.out.write_time));
if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server updated write_time after %d seconds\n",
(int)(time(NULL) - t));
break;
}
sleep(1);
fflush(stdout);
}
if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server did not update write time\n");
}
torture_comment(tctx, "Closing both fd's to see if write time updated.\n");
smbcli_close(cli->tree, fnum2);
fnum2 = -1;
fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
if (fnum1 == -1) {
torture_comment(tctx, "Failed to open %s\n", fname);
return False;
}
finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo1.basic_info.in.file.fnum = fnum1;
finfo2 = finfo1;
status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
return False;
}
torture_comment(tctx, "Second open initial write time %s\n",
nt_time_string(tctx, finfo1.basic_info.out.write_time));
sleep(10);
torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
if (written != 10) {
torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
(int)written, __location__);
return False;
}
finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo1.basic_info.in.file.fnum = fnum1;
finfo2 = finfo1;
status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
return False;
}
torture_comment(tctx, "write time %s\n",
nt_time_string(tctx, finfo2.basic_info.out.write_time));
if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server updated write_time\n");
}
t = time(NULL);
/* Once the time was set using setfileinfo then it stays set - writes
don't have any effect. But make sure. */
while (time(NULL) < t+15) {
status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
ret = False;
break;
}
torture_comment(tctx, "write time %s\n",
nt_time_string(tctx, finfo2.basic_info.out.write_time));
if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server updated write_time after %d seconds\n",
(int)(time(NULL) - t));
break;
}
sleep(1);
fflush(stdout);
}
if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
torture_comment(tctx, "Server did not update write time\n");
}
/* One more test to do. We should read the filetime via findfirst on the
second connection to ensure it's the same. This is very easy for a Windows
server but a bastard to get right on a POSIX server. JRA. */
if (fnum1 != -1)
smbcli_close(cli->tree, fnum1);
smbcli_unlink(cli->tree, fname);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/* Windows does obviously not update the stat info during a write call. I
* *think* this is the problem causing a spurious Excel 2003 on XP error
* message when saving a file. Excel does a setfileinfo, writes, and then does
* a getpath(!)info. Or so... For Samba sometimes it displays an error message
* that the file might have been changed in between. What i've been able to
* trace down is that this happens if the getpathinfo after the write shows a
* different last write time than the setfileinfo showed. This is really
* nasty....
*/
static BOOL test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
struct smbcli_state *cli2)
{
union smb_fileinfo finfo1, finfo2;
const char *fname = BASEDIR "\\torture_file.txt";
NTSTATUS status;
int fnum1 = -1;
int fnum2;
BOOL ret = True;
ssize_t written;
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum1 == -1) {
ret = False;
goto done;
}
finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo1.basic_info.in.file.fnum = fnum1;
status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
ret = False;
goto done;
}
msleep(1000);
written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
if (written != 1) {
torture_comment(tctx, "(%s) written gave %d - should have been 1\n",
__location__, (int)written);
ret = False;
goto done;
}
fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
if (fnum2 == -1) {
torture_comment(tctx, "(%s) failed to open 2nd time - %s\n",
__location__, smbcli_errstr(cli2->tree));
ret = False;
goto done;
}
written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
if (written != 1) {
torture_comment(tctx, "(%s) written gave %d - should have been 1\n",
__location__, (int)written);
ret = False;
goto done;
}
finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo2.basic_info.in.file.path = fname;
status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("(%s) fileinfo failed: %s\n",
__location__, nt_errstr(status)));
ret = False;
goto done;
}
if (finfo1.basic_info.out.create_time !=
finfo2.basic_info.out.create_time) {
torture_comment(tctx, "(%s) create_time changed\n", __location__);
ret = False;
goto done;
}
if (finfo1.basic_info.out.access_time !=
finfo2.basic_info.out.access_time) {
torture_comment(tctx, "(%s) access_time changed\n", __location__);
ret = False;
goto done;
}
if (finfo1.basic_info.out.write_time !=
finfo2.basic_info.out.write_time) {
torture_comment(tctx, "(%s) write_time changed\n", __location__);
torture_comment(tctx, "write time conn 1 = %s, conn 2 = %s\n",
nt_time_string(tctx, finfo1.basic_info.out.write_time),
nt_time_string(tctx, finfo2.basic_info.out.write_time));
ret = False;
goto done;
}
if (finfo1.basic_info.out.change_time !=
finfo2.basic_info.out.change_time) {
torture_comment(tctx, "(%s) change_time changed\n", __location__);
ret = False;
goto done;
}
/* One of the two following calls updates the qpathinfo. */
/* If you had skipped the smbcli_write on fnum2, it would
* *not* have updated the stat on disk */
smbcli_close(cli2->tree, fnum2);
cli2 = NULL;
/* This call is only for the people looking at ethereal :-) */
finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
finfo2.basic_info.in.file.path = fname;
status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
ret = False;
goto done;
}
done:
if (fnum1 != -1)
smbcli_close(cli->tree, fnum1);
smbcli_unlink(cli->tree, fname);
smbcli_deltree(cli->tree, BASEDIR);
return ret;
}
/*
testing of delayed update of write_time
*/
struct torture_suite *torture_delay_write(void)
{
struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "DELAYWRITE");
torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
return suite;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+166
View File
@@ -0,0 +1,166 @@
/*
Unix SMB/CIFS implementation.
directory scanning tests
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "libcli/libcli.h"
#include "torture/torture.h"
#include "torture/util.h"
#include "system/filesys.h"
static void list_fn(struct clilist_file_info *finfo, const char *name, void *state)
{
}
/*
test directory listing speed
*/
BOOL torture_dirtest1(struct torture_context *tctx,
struct smbcli_state *cli)
{
int i;
int fnum;
BOOL correct = True;
extern int torture_numops;
struct timeval tv;
torture_comment(tctx, "Creating %d random filenames\n", torture_numops);
srandom(0);
tv = timeval_current();
for (i=0;i<torture_numops;i++) {
char *fname;
asprintf(&fname, "\\%x", (int)random());
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
if (fnum == -1) {
fprintf(stderr,"(%s) Failed to open %s\n",
__location__, fname);
return False;
}
smbcli_close(cli->tree, fnum);
free(fname);
}
torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "a*.*", 0, list_fn, NULL));
torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "b*.*", 0, list_fn, NULL));
torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "xyzabc", 0, list_fn, NULL));
torture_comment(tctx, "dirtest core %g seconds\n", timeval_elapsed(&tv));
srandom(0);
for (i=0;i<torture_numops;i++) {
char *fname;
asprintf(&fname, "\\%x", (int)random());
smbcli_unlink(cli->tree, fname);
free(fname);
}
return correct;
}
BOOL torture_dirtest2(struct torture_context *tctx,
struct smbcli_state *cli)
{
int i;
int fnum, num_seen;
BOOL correct = True;
extern int torture_entries;
if (!torture_setup_dir(cli, "\\LISTDIR")) {
return False;
}
torture_comment(tctx, "Creating %d files\n", torture_entries);
/* Create torture_entries files and torture_entries directories. */
for (i=0;i<torture_entries;i++) {
char *fname;
asprintf(&fname, "\\LISTDIR\\f%d", i);
fnum = smbcli_nt_create_full(cli->tree, fname, 0,
SEC_RIGHTS_FILE_ALL,
FILE_ATTRIBUTE_ARCHIVE,
NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
if (fnum == -1) {
fprintf(stderr,"(%s) Failed to open %s, error=%s\n",
__location__, fname, smbcli_errstr(cli->tree));
return False;
}
free(fname);
smbcli_close(cli->tree, fnum);
}
for (i=0;i<torture_entries;i++) {
char *fname;
asprintf(&fname, "\\LISTDIR\\d%d", i);
if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
fprintf(stderr,"(%s) Failed to open %s, error=%s\n",
__location__, fname, smbcli_errstr(cli->tree));
return False;
}
free(fname);
}
/* Now ensure that doing an old list sees both files and directories. */
num_seen = smbcli_list_old(cli->tree, "\\LISTDIR\\*", FILE_ATTRIBUTE_DIRECTORY, list_fn, NULL);
torture_comment(tctx, "num_seen = %d\n", num_seen );
/* We should see (torture_entries) each of files & directories + . and .. */
if (num_seen != (2*torture_entries)+2) {
correct = False;
fprintf(stderr,"(%s) entry count mismatch, should be %d, was %d\n",
__location__, (2*torture_entries)+2, num_seen);
}
/* Ensure if we have the "must have" bits we only see the
* relevant entries.
*/
num_seen = smbcli_list_old(cli->tree, "\\LISTDIR\\*", (FILE_ATTRIBUTE_DIRECTORY<<8)|FILE_ATTRIBUTE_DIRECTORY, list_fn, NULL);
torture_comment(tctx, "num_seen = %d\n", num_seen );
if (num_seen != torture_entries+2) {
correct = False;
fprintf(stderr,"(%s) entry count mismatch, should be %d, was %d\n",
__location__, torture_entries+2, num_seen);
}
num_seen = smbcli_list_old(cli->tree, "\\LISTDIR\\*", (FILE_ATTRIBUTE_ARCHIVE<<8)|FILE_ATTRIBUTE_DIRECTORY, list_fn, NULL);
torture_comment(tctx, "num_seen = %d\n", num_seen );
if (num_seen != torture_entries) {
correct = False;
fprintf(stderr,"(%s) entry count mismatch, should be %d, was %d\n",
__location__, torture_entries, num_seen);
}
/* Delete everything. */
if (smbcli_deltree(cli->tree, "\\LISTDIR") == -1) {
fprintf(stderr,"(%s) Failed to deltree %s, error=%s\n", "\\LISTDIR",
__location__, smbcli_errstr(cli->tree));
return False;
}
#if 0
torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "a*.*", 0, list_fn, NULL));
torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "b*.*", 0, list_fn, NULL));
torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "xyzabc", 0, list_fn, NULL));
#endif
return correct;
}
+174
View File
@@ -0,0 +1,174 @@
/*
Unix SMB/CIFS implementation.
test server handling of unexpected client disconnects
Copyright (C) Andrew Tridgell 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/filesys.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\test_disconnect"
#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)); \
talloc_free(cli); \
return False; \
}} while (0)
/*
test disconnect after async open
*/
static BOOL test_disconnect_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
union smb_open io;
NTSTATUS status;
struct smbcli_request *req1, *req2;
printf("trying open/disconnect\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = BASEDIR "\\open.dat";
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
io.ntcreatex.in.share_access = 0;
req1 = smb_raw_open_send(cli->tree, &io);
req2 = smb_raw_open_send(cli->tree, &io);
status = smbcli_chkpath(cli->tree, "\\");
CHECK_STATUS(status, NT_STATUS_OK);
talloc_free(cli);
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);
status = smbcli_chkpath(cli->tree, "\\");
CHECK_STATUS(status, NT_STATUS_OK);
talloc_free(cli);
return True;
}
/*
basic testing of disconnects
*/
BOOL torture_disconnect(struct torture_context *torture)
{
BOOL ret = True;
TALLOC_CTX *mem_ctx;
int i;
extern int torture_numops;
struct smbcli_state *cli;
mem_ctx = talloc_init("torture_raw_mux");
if (!torture_open_connection(&cli, 0)) {
return False;
}
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
for (i=0;i<torture_numops;i++) {
ret &= test_disconnect_lock(cli, mem_ctx);
if (!torture_open_connection(&cli, 0)) {
return False;
}
ret &= test_disconnect_open(cli, mem_ctx);
if (!torture_open_connection(&cli, 0)) {
return False;
}
if (torture_setting_bool(torture, "samba3", False)) {
/*
* In Samba3 it might happen that the old smbd from
* test_disconnect_lock is not scheduled before the
* new process comes in. Try to get rid of the random
* failures in the build farm.
*/
msleep(200);
}
}
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
talloc_free(mem_ctx);
return ret;
}
+812
View File
@@ -0,0 +1,812 @@
/*
Unix SMB/CIFS implementation.
basic locking tests
Copyright (C) Andrew Tridgell 2000-2004
Copyright (C) Jeremy Allison 2000-2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/ui.h"
#include "torture/util.h"
#include "torture/torture.h"
#include "system/time.h"
#include "system/filesys.h"
#define BASEDIR "\\locktest"
/*
This test checks for two things:
1) correct support for retaining locks over a close (ie. the server
must not use posix semantics)
2) support for lock timeouts
*/
bool torture_locktest1(struct torture_context *tctx,
struct smbcli_state *cli1,
struct smbcli_state *cli2)
{
const char *fname = BASEDIR "\\lockt1.lck";
int fnum1, fnum2, fnum3;
time_t t1, t2;
uint_t lock_timeout;
if (!torture_setup_dir(cli1, BASEDIR)) {
return False;
}
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
torture_assert(tctx, fnum1 != -1,
talloc_asprintf(tctx,
"open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
"open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx,
"open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
torture_assert_ntstatus_ok(tctx,
smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
"lock2 succeeded! This is a locking bug\n");
if (!check_error(__location__, cli2, ERRDOS, ERRlock,
NT_STATUS_LOCK_NOT_GRANTED)) return False;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
"lock2 succeeded! This is a locking bug\n");
if (!check_error(__location__, cli2, ERRDOS, ERRlock,
NT_STATUS_FILE_LOCK_CONFLICT)) return False;
torture_assert_ntstatus_ok(tctx,
smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
talloc_asprintf(tctx,
"lock1 failed (%s)", smbcli_errstr(cli1->tree)));
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
"lock2 succeeded! This is a locking bug");
if (!check_error(__location__, cli2, ERRDOS, ERRlock,
NT_STATUS_LOCK_NOT_GRANTED)) return False;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
"lock2 succeeded! This is a locking bug");
if (!check_error(__location__, cli2, ERRDOS, ERRlock,
NT_STATUS_LOCK_NOT_GRANTED)) return False;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
"lock2 succeeded! This is a locking bug");
if (!check_error(__location__, cli2, ERRDOS, ERRlock,
NT_STATUS_FILE_LOCK_CONFLICT)) return False;
lock_timeout = (6 + (random() % 20));
torture_comment(tctx, "Testing lock timeout with timeout=%u\n",
lock_timeout);
t1 = time(NULL);
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
"lock3 succeeded! This is a locking bug\n");
if (!check_error(__location__, cli2, ERRDOS, ERRlock,
NT_STATUS_FILE_LOCK_CONFLICT)) return False;
t2 = time(NULL);
if (t2 - t1 < 5) {
torture_fail(tctx,
"error: This server appears not to support timed lock requests");
}
torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
(uint_t)(t2-t1), lock_timeout);
torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
"lock4 succeeded! This is a locking bug");
if (!check_error(__location__, cli2, ERRDOS, ERRlock,
NT_STATUS_FILE_LOCK_CONFLICT)) return False;
torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
return true;
}
/*
This test checks that
1) the server supports multiple locking contexts on the one SMB
connection, distinguished by PID.
2) the server correctly fails overlapping locks made by the same PID (this
goes against POSIX behaviour, which is why it is tricky to implement)
3) the server denies unlock requests by an incorrect client PID
*/
bool torture_locktest2(struct torture_context *tctx,
struct smbcli_state *cli)
{
const char *fname = BASEDIR "\\lockt2.lck";
int fnum1, fnum2, fnum3;
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
torture_comment(tctx, "Testing pid context\n");
cli->session->pid = 1;
fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
torture_assert(tctx, fnum1 != -1,
talloc_asprintf(tctx,
"open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
torture_assert(tctx, fnum2 != -1,
talloc_asprintf(tctx, "open2 of %s failed (%s)",
fname, smbcli_errstr(cli->tree)));
cli->session->pid = 2;
fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
torture_assert(tctx, fnum3 != -1,
talloc_asprintf(tctx,
"open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
cli->session->pid = 1;
torture_assert_ntstatus_ok(tctx,
smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
talloc_asprintf(tctx,
"lock1 failed (%s)", smbcli_errstr(cli->tree)));
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
"WRITE lock1 succeeded! This is a locking bug");
if (!check_error(__location__, cli, ERRDOS, ERRlock,
NT_STATUS_LOCK_NOT_GRANTED)) return False;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
"WRITE lock2 succeeded! This is a locking bug");
if (!check_error(__location__, cli, ERRDOS, ERRlock,
NT_STATUS_LOCK_NOT_GRANTED)) return False;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
"READ lock2 succeeded! This is a locking bug");
if (!check_error(__location__, cli, ERRDOS, ERRlock,
NT_STATUS_FILE_LOCK_CONFLICT)) return False;
torture_assert_ntstatus_ok(tctx,
smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
talloc_asprintf(tctx,
"lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
cli->session->pid = 2;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
"unlock at 100 succeeded! This is a locking bug");
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
"unlock1 succeeded! This is a locking bug");
if (!check_error(__location__, cli,
ERRDOS, ERRnotlocked,
NT_STATUS_RANGE_NOT_LOCKED)) return False;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
"unlock2 succeeded! This is a locking bug");
if (!check_error(__location__, cli,
ERRDOS, ERRnotlocked,
NT_STATUS_RANGE_NOT_LOCKED)) return False;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
"lock3 succeeded! This is a locking bug");
if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
cli->session->pid = 1;
torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
return true;
}
/*
This test checks that
1) the server supports the full offset range in lock requests
*/
bool torture_locktest3(struct torture_context *tctx,
struct smbcli_state *cli1,
struct smbcli_state *cli2)
{
const char *fname = BASEDIR "\\lockt3.lck";
int fnum1, fnum2, i;
uint32_t offset;
extern int torture_numops;
#define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
torture_comment(tctx, "Testing 32 bit offset ranges");
if (!torture_setup_dir(cli1, BASEDIR)) {
return False;
}
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
torture_assert(tctx, fnum1 != -1,
talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
torture_assert(tctx, fnum2 != -1,
talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
torture_comment(tctx, "Establishing %d locks\n", torture_numops);
for (offset=i=0;i<torture_numops;i++) {
NEXT_OFFSET;
torture_assert_ntstatus_ok(tctx,
smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
torture_assert_ntstatus_ok(tctx,
smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
talloc_asprintf(tctx, "lock2 %d failed (%s)",
i, smbcli_errstr(cli1->tree)));
}
torture_comment(tctx, "Testing %d locks\n", torture_numops);
for (offset=i=0;i<torture_numops;i++) {
NEXT_OFFSET;
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
torture_assert(tctx,
!NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
}
torture_comment(tctx, "Removing %d locks\n", torture_numops);
for (offset=i=0;i<torture_numops;i++) {
NEXT_OFFSET;
torture_assert_ntstatus_ok(tctx,
smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
talloc_asprintf(tctx, "unlock1 %d failed (%s)",
i,
smbcli_errstr(cli1->tree)));
torture_assert_ntstatus_ok(tctx,
smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
talloc_asprintf(tctx, "unlock2 %d failed (%s)",
i,
smbcli_errstr(cli1->tree)));
}
torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
return true;
}
#define EXPECTED(ret, v) if ((ret) != (v)) { \
torture_comment(tctx, "** "); correct = False; \
}
/*
looks at overlapping locks
*/
BOOL torture_locktest4(struct torture_context *tctx,
struct smbcli_state *cli1,
struct smbcli_state *cli2)
{
const char *fname = BASEDIR "\\lockt4.lck";
int fnum1, fnum2, f;
BOOL ret;
uint8_t buf[1000];
BOOL correct = True;
if (!torture_setup_dir(cli1, BASEDIR)) {
return False;
}
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
memset(buf, 0, sizeof(buf));
if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
torture_comment(tctx, "Failed to create file\n");
correct = False;
goto fail;
}
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
EXPECTED(ret, False);
torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
EXPECTED(ret, False);
torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
EXPECTED(ret, False);
torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
EXPECTED(ret, True);
torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
EXPECTED(ret, False);
torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
EXPECTED(ret, False);
torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
EXPECTED(ret, False);
torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
EXPECTED(ret, False);
torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
(smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
EXPECTED(ret, False);
torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
(smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
EXPECTED(ret, False);
torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
EXPECTED(ret, True);
torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
(smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
!(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
EXPECTED(ret, True);
torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
(smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&
(smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
(smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&
(smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
!(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&
(smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
smbcli_close(cli1->tree, fnum1);
smbcli_close(cli2->tree, fnum2);
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
smbcli_close(cli1->tree, f);
smbcli_close(cli1->tree, fnum1);
EXPECTED(ret, True);
torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
fail:
smbcli_close(cli1->tree, fnum1);
smbcli_close(cli2->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
return correct;
}
/*
looks at lock upgrade/downgrade.
*/
BOOL torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
struct smbcli_state *cli2)
{
const char *fname = BASEDIR "\\lockt5.lck";
int fnum1, fnum2, fnum3;
BOOL ret;
uint8_t buf[1000];
BOOL correct = True;
if (!torture_setup_dir(cli1, BASEDIR)) {
return False;
}
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
memset(buf, 0, sizeof(buf));
torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
"Failed to create file");
/* Check for NT bug... */
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
smbcli_close(cli1->tree, fnum1);
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
smbcli_close(cli1->tree, fnum1);
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
smbcli_unlock(cli1->tree, fnum3, 0, 1);
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
EXPECTED(ret, False);
torture_comment(tctx, "a different processs %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
/* Unlock the process 2 lock. */
smbcli_unlock(cli2->tree, fnum2, 0, 4);
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
EXPECTED(ret, False);
torture_comment(tctx, "the same processs on a different fnum %s get a read lock\n", ret?"can":"cannot");
/* Unlock the process 1 fnum3 lock. */
smbcli_unlock(cli1->tree, fnum3, 0, 4);
/* Stack 2 more locks here. */
ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
/* Unlock the first process lock, then check this was the WRITE lock that was
removed. */
ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
/* Unlock the process 2 lock. */
smbcli_unlock(cli2->tree, fnum2, 0, 4);
/* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
EXPECTED(ret, True);
torture_comment(tctx, "the same process %s unlock the stack of 4 locks\n", ret?"can":"cannot");
/* Ensure the next unlock fails. */
ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
EXPECTED(ret, False);
torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot");
/* Ensure connection 2 can get a write lock. */
ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
EXPECTED(ret, True);
torture_comment(tctx, "a different processs %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
smbcli_close(cli1->tree, fnum1);
smbcli_close(cli2->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
return correct;
}
/*
tries the unusual lockingX locktype bits
*/
BOOL torture_locktest6(struct torture_context *tctx,
struct smbcli_state *cli)
{
const char *fname[1] = { "\\lock6.txt" };
int i;
int fnum;
NTSTATUS status;
if (!torture_setup_dir(cli, BASEDIR)) {
return False;
}
for (i=0;i<1;i++) {
torture_comment(tctx, "Testing %s\n", fname[i]);
smbcli_unlink(cli->tree, fname[i]);
fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
smbcli_close(cli->tree, fnum);
torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
smbcli_close(cli->tree, fnum);
torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
smbcli_unlink(cli->tree, fname[i]);
}
return True;
}
BOOL torture_locktest7(struct torture_context *tctx,
struct smbcli_state *cli1)
{
const char *fname = BASEDIR "\\lockt7.lck";
int fnum1;
int fnum2 = -1;
size_t size;
uint8_t buf[200];
BOOL correct = False;
torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
memset(buf, 0, sizeof(buf));
torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
"Failed to create file");
cli1->session->pid = 1;
torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
smbcli_errstr(cli1->tree)));
torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
smbcli_errstr(cli1->tree)));
torture_comment(tctx, "pid1 successfully read the range 130:4\n");
if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
"Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
} else {
torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
}
cli1->session->pid = 2;
if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
} else {
torture_comment(tctx, "pid2 successfully read the range 130:4\n");
}
if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
"Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
} else {
torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
}
cli1->session->pid = 1;
smbcli_unlock(cli1->tree, fnum1, 130, 4);
torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
smbcli_errstr(cli1->tree)));
torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
smbcli_errstr(cli1->tree)));
torture_comment(tctx, "pid1 successfully read the range 130:4\n");
torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
smbcli_errstr(cli1->tree)));
torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
cli1->session->pid = 2;
if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
smbcli_errstr(cli1->tree));
torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
"Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
} else {
torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
}
if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
smbcli_errstr(cli1->tree));
if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
__location__);
goto fail;
}
} else {
torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
__location__);
goto fail;
}
torture_comment(tctx, "Testing truncate of locked file.\n");
fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
torture_comment(tctx, "Truncated locked file.\n");
torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
cli1->session->pid = 1;
smbcli_unlock(cli1->tree, fnum1, 130, 4);
correct = True;
fail:
smbcli_close(cli1->tree, fnum1);
smbcli_close(cli1->tree, fnum2);
smbcli_unlink(cli1->tree, fname);
return correct;
}
struct torture_suite *torture_base_locktest(void)
{
struct torture_suite *suite = torture_suite_create(talloc_autofree_context(),
"LOCK");
torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);
return suite;
}
+202
View File
@@ -0,0 +1,202 @@
/*
Unix SMB/CIFS implementation.
SMB torture tester - mangling test
Copyright (C) Andrew Tridgell 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/filesys.h"
#include "system/dir.h"
#include "lib/tdb/include/tdb.h"
#include "lib/util/util_tdb.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#include "pstring.h"
static TDB_CONTEXT *tdb;
#define NAME_LENGTH 20
static uint_t total, collisions, failures;
static BOOL test_one(struct smbcli_state *cli, const char *name)
{
int fnum;
const char *shortname;
fstring name2;
NTSTATUS status;
TDB_DATA data;
total++;
fnum = smbcli_open(cli->tree, name, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
if (fnum == -1) {
printf("open of %s failed (%s)\n", name, smbcli_errstr(cli->tree));
return False;
}
if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
printf("close of %s failed (%s)\n", name, smbcli_errstr(cli->tree));
return False;
}
/* get the short name */
status = smbcli_qpathinfo_alt_name(cli->tree, name, &shortname);
if (!NT_STATUS_IS_OK(status)) {
printf("query altname of %s failed (%s)\n", name, smbcli_errstr(cli->tree));
return False;
}
snprintf(name2, sizeof(name2), "\\mangle_test\\%s", shortname);
if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, name2))) {
printf("unlink of %s (%s) failed (%s)\n",
name2, name, smbcli_errstr(cli->tree));
return False;
}
/* recreate by short name */
fnum = smbcli_open(cli->tree, name2, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
if (fnum == -1) {
printf("open2 of %s failed (%s)\n", name2, smbcli_errstr(cli->tree));
return False;
}
if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
printf("close of %s failed (%s)\n", name, smbcli_errstr(cli->tree));
return False;
}
/* and unlink by long name */
if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, name))) {
printf("unlink2 of %s (%s) failed (%s)\n",
name, name2, smbcli_errstr(cli->tree));
failures++;
smbcli_unlink(cli->tree, name2);
return True;
}
/* see if the short name is already in the tdb */
data = tdb_fetch_bystring(tdb, shortname);
if (data.dptr) {
/* maybe its a duplicate long name? */
if (strcasecmp(name, (const char *)data.dptr) != 0) {
/* we have a collision */
collisions++;
printf("Collision between %s and %s -> %s "
" (coll/tot: %u/%u)\n",
name, data.dptr, shortname, collisions, total);
}
free(data.dptr);
} else {
TDB_DATA namedata;
/* store it for later */
namedata.dptr = discard_const_p(uint8_t, name);
namedata.dsize = strlen(name)+1;
tdb_store_bystring(tdb, shortname, namedata, TDB_REPLACE);
}
return True;
}
static void gen_name(char *name)
{
const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~...";
uint_t max_idx = strlen(chars);
uint_t len;
int i;
char *p;
fstrcpy(name, "\\mangle_test\\");
p = name + strlen(name);
len = 1 + random() % NAME_LENGTH;
for (i=0;i<len;i++) {
p[i] = chars[random() % max_idx];
}
p[i] = 0;
if (ISDOT(p) || ISDOTDOT(p)) {
p[0] = '_';
}
/* have a high probability of a common lead char */
if (random() % 2 == 0) {
p[0] = 'A';
}
/* and a medium probability of a common lead string */
if (random() % 10 == 0) {
strncpy(p, "ABCDE", 5);
}
/* and a high probability of a good extension length */
if (random() % 2 == 0) {
char *s = strrchr(p, '.');
if (s) {
s[4] = 0;
}
}
}
BOOL torture_mangle(struct torture_context *torture,
struct smbcli_state *cli)
{
extern int torture_numops;
int i;
/* we will use an internal tdb to store the names we have used */
tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0);
if (!tdb) {
printf("ERROR: Failed to open tdb\n");
return False;
}
if (!torture_setup_dir(cli, "\\mangle_test")) {
return False;
}
for (i=0;i<torture_numops;i++) {
fstring name;
ZERO_STRUCT(name);
gen_name(name);
if (!test_one(cli, name)) {
break;
}
if (total && total % 100 == 0) {
printf("collisions %u/%u - %.2f%% (%u failures)\r",
collisions, total, (100.0*collisions) / total, failures);
}
}
smbcli_unlink(cli->tree, "\\mangle_test\\*");
if (NT_STATUS_IS_ERR(smbcli_rmdir(cli->tree, "\\mangle_test"))) {
printf("ERROR: Failed to remove directory\n");
return False;
}
printf("\nTotal collisions %u/%u - %.2f%% (%u failures)\n",
collisions, total, (100.0*collisions) / total, failures);
return (failures == 0);
}
+857
View File
@@ -0,0 +1,857 @@
/*
Unix SMB/CIFS implementation.
SMB torture tester
Copyright (C) Andrew Tridgell 1997-2003
Copyright (C) Jelmer Vernooij 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "libcli/raw/libcliraw.h"
#include "system/time.h"
#include "system/wait.h"
#include "system/filesys.h"
#include "libcli/raw/ioctl.h"
#include "libcli/libcli.h"
#include "lib/events/events.h"
#include "libcli/resolve/resolve.h"
#include "auth/credentials/credentials.h"
#include "librpc/gen_ndr/ndr_nbt.h"
#include "torture/torture.h"
#include "torture/util.h"
#include "libcli/smb_composite/smb_composite.h"
#include "libcli/composite/composite.h"
extern struct cli_credentials *cmdline_credentials;
static void benchrw_callback(struct smbcli_request *req);
enum benchrw_stage {
START,
OPEN_CONNECTION,
CLEANUP_TESTDIR,
MK_TESTDIR,
OPEN_FILE,
INITIAL_WRITE,
READ_WRITE_DATA,
MAX_OPS_REACHED,
ERROR,
CLOSE_FILE,
CLEANUP,
FINISHED
};
struct benchrw_state{
struct torture_context *tctx;
char *dname;
char *fname;
uint16_t fnum;
int nr;
struct smbcli_tree *cli;
uint8_t *buffer;
int writecnt;
int readcnt;
int completed;
TALLOC_CTX *mem_ctx;
void *req_params;
enum benchrw_stage mode;
struct params{
struct unclist{
const char *host;
const char *share;
} **unc;
const char *workgroup;
int retry;
unsigned int writeblocks;
unsigned int blocksize;
unsigned int writeratio;
} *lp_params;
};
static BOOL wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
{
while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return False;
}
return True;
}
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;
}
for (i=0;i<torture_numops;i++) {
uint_t n = (uint_t)random()%10;
if (i % 10 == 0) {
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 run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
{
return rw_torture(tctx, cli);
}
/*
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++;
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;
}
/*
open N connections to the server and just hold them open
used for testing performance when there are N idle users
already connected
*/
BOOL torture_holdcon(struct torture_context *tctx)
{
int i;
struct smbcli_state **cli;
int num_dead = 0;
torture_comment(tctx, "Opening %d connections\n", torture_numops);
cli = malloc_array_p(struct smbcli_state *, torture_numops);
for (i=0;i<torture_numops;i++) {
if (!torture_open_connection(&cli[i], i)) {
return False;
}
torture_comment(tctx, "opened %d connections\r", i);
fflush(stdout);
}
torture_comment(tctx, "\nStarting pings\n");
while (1) {
for (i=0;i<torture_numops;i++) {
NTSTATUS status;
if (cli[i]) {
status = smbcli_chkpath(cli[i]->tree, "\\");
if (!NT_STATUS_IS_OK(status)) {
torture_comment(tctx, "Connection %d is dead\n", i);
cli[i] = NULL;
num_dead++;
}
usleep(100);
}
}
if (num_dead == torture_numops) {
torture_comment(tctx, "All connections dead - finishing\n");
break;
}
torture_comment(tctx, ".");
fflush(stdout);
}
return True;
}
/*
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);
torture_comment(tctx, "%6d\r", i);
}
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);
torture_comment(tctx, "%6d %6d\r", i, maxfid-i);
}
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
}
/*
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;
}
/*
init params using lp_parm_xxx
return number of unclist entries
*/
static int init_benchrw_params(struct torture_context *tctx, struct params *lpar)
{
char **unc_list = NULL;
int num_unc_names = 0, conn_index=0, empty_lines=0;
const char *p;
lpar->retry = torture_setting_int(tctx, "retry",3);
lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
lpar->workgroup = lp_workgroup();
p = torture_setting_string(tctx, "unclist", NULL);
if (p) {
char *h, *s;
unc_list = file_lines_load(p, &num_unc_names, NULL);
if (!unc_list || num_unc_names <= 0) {
torture_comment(tctx, "Failed to load unc names list from '%s'\n", p);
exit(1);
}
lpar->unc = talloc_array(tctx, struct unclist *, (num_unc_names-empty_lines));
for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
/* ignore empty lines */
if(strlen(unc_list[conn_index % num_unc_names])==0){
empty_lines++;
continue;
}
if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
NULL, &h, &s)) {
torture_comment(tctx, "Failed to parse UNC name %s\n",
unc_list[conn_index % num_unc_names]);
exit(1);
}
lpar->unc[conn_index-empty_lines] = talloc(tctx,struct unclist);
lpar->unc[conn_index-empty_lines]->host = h;
lpar->unc[conn_index-empty_lines]->share = s;
}
return num_unc_names-empty_lines;
}else{
lpar->unc = talloc_array(tctx, struct unclist *, 1);
lpar->unc[0] = talloc(tctx,struct unclist);
lpar->unc[0]->host = torture_setting_string(tctx, "host", NULL);
lpar->unc[0]->share = torture_setting_string(tctx, "share", NULL);
return 1;
}
}
/*
Called when the reads & writes are finished. closes the file.
*/
static NTSTATUS benchrw_close(struct torture_context *tctx,struct smbcli_request *req,
struct benchrw_state *state)
{
union smb_close close_parms;
NT_STATUS_NOT_OK_RETURN(req->status);
torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
close_parms.close.level = RAW_CLOSE_CLOSE;
close_parms.close.in.file.fnum = state->fnum ;
close_parms.close.in.write_time = 0;
state->mode=CLOSE_FILE;
req = smb_raw_close_send(state->cli, &close_parms);
NT_STATUS_HAVE_NO_MEMORY(req);
/*register the callback function!*/
req->async.fn = benchrw_callback;
req->async.private = state;
return NT_STATUS_OK;
}
/*
Called when the initial write is completed is done. write or read a file.
*/
static NTSTATUS benchrw_readwrite(struct torture_context *tctx,struct smbcli_request *req,
struct benchrw_state *state)
{
union smb_read rd;
union smb_write wr;
NT_STATUS_NOT_OK_RETURN(req->status);
state->completed++;
/*rotate between writes and reads*/
if( state->completed % state->lp_params->writeratio == 0){
torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
state->nr,state->completed,torture_numops);
wr.generic.level = RAW_WRITE_WRITEX ;
wr.writex.in.file.fnum = state->fnum ;
wr.writex.in.offset = 0;
wr.writex.in.wmode = 0 ;
wr.writex.in.remaining = 0;
wr.writex.in.count = state->lp_params->blocksize;
wr.writex.in.data = state->buffer;
state->readcnt=0;
req = smb_raw_write_send(state->cli,&wr);
}else{
torture_comment(tctx, "Callback READ file:%d (%d/%d) Offset:%d\n",
state->nr,state->completed,torture_numops,
(state->readcnt*state->lp_params->blocksize));
rd.generic.level = RAW_READ_READ ;
rd.read.in.file.fnum = state->fnum ;
rd.read.in.offset = state->readcnt *
state->lp_params->blocksize;
rd.read.in.count = state->lp_params->blocksize;
rd.read.in.remaining = 0 ;
rd.read.out.data = state->buffer;
if(state->readcnt < state->lp_params->writeblocks){
state->readcnt++;
}else{
/*start reading from beginn of file*/
state->readcnt=0;
}
req = smb_raw_read_send(state->cli,&rd);
}
NT_STATUS_HAVE_NO_MEMORY(req);
/*register the callback function!*/
req->async.fn = benchrw_callback;
req->async.private = state;
return NT_STATUS_OK;
}
/*
Called when the open is done. writes to the file.
*/
static NTSTATUS benchrw_open(struct torture_context *tctx,struct smbcli_request *req,
struct benchrw_state *state)
{
union smb_write wr;
if(state->mode == OPEN_FILE){
NTSTATUS status;
status = smb_raw_open_recv(req,state->mem_ctx,(
union smb_open*)state->req_params);
NT_STATUS_NOT_OK_RETURN(status);
state->fnum = ((union smb_open*)state->req_params)
->openx.out.file.fnum;
torture_comment(tctx, "File opened (%d)\n",state->fnum);
state->mode=INITIAL_WRITE;
}
torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
(state->writecnt+1)*state->lp_params->blocksize,
(state->lp_params->writeblocks*state->lp_params->blocksize));
wr.generic.level = RAW_WRITE_WRITEX ;
wr.writex.in.file.fnum = state->fnum ;
wr.writex.in.offset = state->writecnt *
state->lp_params->blocksize;
wr.writex.in.wmode = 0 ;
wr.writex.in.remaining = (state->lp_params->writeblocks *
state->lp_params->blocksize)-
((state->writecnt+1)*state->
lp_params->blocksize);
wr.writex.in.count = state->lp_params->blocksize;
wr.writex.in.data = state->buffer;
state->writecnt++;
if(state->writecnt == state->lp_params->writeblocks){
state->mode=READ_WRITE_DATA;
}
req = smb_raw_write_send(state->cli,&wr);
NT_STATUS_HAVE_NO_MEMORY(req);
/*register the callback function!*/
req->async.fn = benchrw_callback;
req->async.private = state;
return NT_STATUS_OK;
}
/*
Called when the mkdir is done. Opens a file.
*/
static NTSTATUS benchrw_mkdir(struct torture_context *tctx,struct smbcli_request *req,
struct benchrw_state *state)
{
union smb_open *open_parms;
uint8_t *writedata;
NT_STATUS_NOT_OK_RETURN(req->status);
/* open/create the files */
torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
lp_parm_int(-1, "torture", "nprocs", 4));
open_parms=talloc_zero(state->mem_ctx, union smb_open);
NT_STATUS_HAVE_NO_MEMORY(open_parms);
open_parms->openx.level = RAW_OPEN_OPENX;
open_parms->openx.in.flags = 0;
open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
open_parms->openx.in.search_attrs =
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
open_parms->openx.in.file_attrs = 0;
open_parms->openx.in.write_time = 0;
open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
open_parms->openx.in.size = 0;
open_parms->openx.in.timeout = 0;
open_parms->openx.in.fname = state->fname;
writedata = talloc_size(state->mem_ctx,state->lp_params->blocksize);
NT_STATUS_HAVE_NO_MEMORY(writedata);
generate_random_buffer(writedata,state->lp_params->blocksize);
state->buffer=writedata;
state->writecnt=1;
state->readcnt=0;
state->req_params=open_parms;
state->mode=OPEN_FILE;
req = smb_raw_open_send(state->cli,open_parms);
NT_STATUS_HAVE_NO_MEMORY(req);
/*register the callback function!*/
req->async.fn = benchrw_callback;
req->async.private = state;
return NT_STATUS_OK;
}
/*
handler for completion of a sub-request of the bench-rw test
*/
static void benchrw_callback(struct smbcli_request *req)
{
struct benchrw_state *state = req->async.private;
struct torture_context *tctx = state->tctx;
/*dont send new requests when torture_numops is reached*/
if(state->completed >= torture_numops){
state->completed=0;
state->mode=MAX_OPS_REACHED;
}
switch (state->mode) {
case MK_TESTDIR:
if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
torture_comment(tctx, "Failed to create the test directory - %s\n",
nt_errstr(req->status));
state->mode=ERROR;
return;
}
break;
case OPEN_FILE:
case INITIAL_WRITE:
if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
torture_comment(tctx, "Failed to open/write the file - %s\n",
nt_errstr(req->status));
state->mode=ERROR;
return;
}
break;
case READ_WRITE_DATA:
if (!NT_STATUS_IS_OK(benchrw_readwrite(tctx,req,state))){
torture_comment(tctx, "Failed to read/write the file - %s\n",
nt_errstr(req->status));
state->mode=ERROR;
return;
}
break;
case MAX_OPS_REACHED:
if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
torture_comment(tctx, "Failed to read/write/close the file - %s\n",
nt_errstr(req->status));
state->mode=ERROR;
return;
}
break;
case CLOSE_FILE:
torture_comment(tctx, "File %d closed\n",state->nr);
if (!NT_STATUS_IS_OK(req->status)) {
torture_comment(tctx, "Failed to close the file - %s\n",
nt_errstr(req->status));
state->mode=ERROR;
return;
}
state->mode=CLEANUP;
return;
default:
break;
}
}
/* open connection async callback function*/
static void async_open_callback(struct composite_context *con)
{
struct benchrw_state *state = con->async.private_data;
struct torture_context *tctx = state->tctx;
int retry = state->lp_params->retry;
if (NT_STATUS_IS_OK(con->status)) {
state->cli=((struct smb_composite_connect*)
state->req_params)->out.tree;
state->mode=CLEANUP_TESTDIR;
}else{
if(state->writecnt < retry){
torture_comment(tctx, "Failed to open connection:%d, Retry (%d/%d)\n",
state->nr,state->writecnt,retry);
state->writecnt++;
state->mode=START;
usleep(1000);
}else{
torture_comment(tctx, "Failed to open connection (%d) - %s\n",
state->nr, nt_errstr(con->status));
state->mode=ERROR;
}
return;
}
}
/*
establishs a smbcli_tree from scratch (async)
*/
static struct composite_context *torture_connect_async(
struct torture_context *tctx,
struct smb_composite_connect *smb,
TALLOC_CTX *mem_ctx,
struct event_context *ev,
const char *host,
const char *share,
const char *workgroup)
{
torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
smb->in.dest_host=talloc_strdup(mem_ctx,host);
smb->in.service=talloc_strdup(mem_ctx,share);
smb->in.port=0;
smb->in.called_name = strupper_talloc(mem_ctx, host);
smb->in.service_type=NULL;
smb->in.credentials=cmdline_credentials;
smb->in.fallback_to_anonymous=False;
smb->in.workgroup=workgroup;
return smb_composite_connect_send(smb,mem_ctx,ev);
}
BOOL run_benchrw(struct torture_context *tctx)
{
struct smb_composite_connect *smb_con;
const char *fname = "\\rwtest.dat";
struct smbcli_request *req;
struct benchrw_state **state;
int i , num_unc_names;
struct event_context *ev ;
struct composite_context *req1;
struct params lpparams;
union smb_mkdir parms;
int finished = 0;
BOOL success=True;
int torture_nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d num_nprocs=%d\n",
torture_numops, torture_nprocs);
/*init talloc context*/
ev = event_context_init(tctx);
state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
/* init params using lp_parm_xxx */
num_unc_names = init_benchrw_params(tctx,&lpparams);
/* init private data structs*/
for(i = 0; i<torture_nprocs;i++){
state[i]=talloc(tctx,struct benchrw_state);
state[i]->tctx = tctx;
state[i]->completed=0;
state[i]->lp_params=&lpparams;
state[i]->nr=i;
state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
state[i]->fname=talloc_asprintf(tctx,"%s%s",
state[i]->dname,fname);
state[i]->mode=START;
state[i]->writecnt=0;
}
torture_comment(tctx, "Starting async requests\n");
while(finished != torture_nprocs){
finished=0;
for(i = 0; i<torture_nprocs;i++){
switch (state[i]->mode){
/*open multiple connections with the same userid */
case START:
smb_con = talloc(tctx,struct smb_composite_connect) ;
state[i]->req_params=smb_con;
state[i]->mode=OPEN_CONNECTION;
req1 = torture_connect_async(tctx, smb_con,
tctx,ev,
lpparams.unc[i % num_unc_names]->host,
lpparams.unc[i % num_unc_names]->share,
lpparams.workgroup);
/* register callback fn + private data */
req1->async.fn = async_open_callback;
req1->async.private_data=state[i];
break;
/*setup test dirs (sync)*/
case CLEANUP_TESTDIR:
torture_comment(tctx, "Setup test dir %d\n",i);
smb_raw_exit(state[i]->cli->session);
if (smbcli_deltree(state[i]->cli,
state[i]->dname) == -1) {
torture_comment(tctx, "Unable to delete %s - %s\n",
state[i]->dname,
smbcli_errstr(state[i]->cli));
state[i]->mode=ERROR;
break;
}
state[i]->mode=MK_TESTDIR;
parms.mkdir.level = RAW_MKDIR_MKDIR;
parms.mkdir.in.path = state[i]->dname;
req = smb_raw_mkdir_send(state[i]->cli,&parms);
/* register callback fn + private data */
req->async.fn = benchrw_callback;
req->async.private=state[i];
break;
/* error occured , finish */
case ERROR:
finished++;
success=False;
break;
/* cleanup , close connection */
case CLEANUP:
torture_comment(tctx, "Deleting test dir %s %d/%d\n",state[i]->dname,
i+1,torture_nprocs);
smbcli_deltree(state[i]->cli,state[i]->dname);
if (NT_STATUS_IS_ERR(smb_tree_disconnect(
state[i]->cli))) {
torture_comment(tctx, "ERROR: Tree disconnect failed");
state[i]->mode=ERROR;
break;
}
state[i]->mode=FINISHED;
case FINISHED:
finished++;
break;
default:
event_loop_once(ev);
}
}
}
return success;
}
+120
View File
@@ -0,0 +1,120 @@
/*
Unix SMB/CIFS implementation.
show server properties
Copyright (C) Andrew Tridgell 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
struct bitmapping {
const char *name;
uint32_t value;
};
#define BIT_NAME(x) { #x, x }
const static struct bitmapping fs_attr_bits[] = {
BIT_NAME(FS_ATTR_CASE_SENSITIVE_SEARCH),
BIT_NAME(FS_ATTR_CASE_PRESERVED_NAMES),
BIT_NAME(FS_ATTR_UNICODE_ON_DISK),
BIT_NAME(FS_ATTR_PERSISTANT_ACLS),
BIT_NAME(FS_ATTR_COMPRESSION),
BIT_NAME(FS_ATTR_QUOTAS),
BIT_NAME(FS_ATTR_SPARSE_FILES),
BIT_NAME(FS_ATTR_REPARSE_POINTS),
BIT_NAME(FS_ATTR_REMOTE_STORAGE),
BIT_NAME(FS_ATTR_LFN_SUPPORT),
BIT_NAME(FS_ATTR_IS_COMPRESSED),
BIT_NAME(FS_ATTR_OBJECT_IDS),
BIT_NAME(FS_ATTR_ENCRYPTION),
BIT_NAME(FS_ATTR_NAMED_STREAMS),
{ NULL, 0 }
};
const static struct bitmapping capability_bits[] = {
BIT_NAME(CAP_RAW_MODE),
BIT_NAME(CAP_MPX_MODE),
BIT_NAME(CAP_UNICODE),
BIT_NAME(CAP_LARGE_FILES),
BIT_NAME(CAP_NT_SMBS),
BIT_NAME(CAP_RPC_REMOTE_APIS),
BIT_NAME(CAP_STATUS32),
BIT_NAME(CAP_LEVEL_II_OPLOCKS),
BIT_NAME(CAP_LOCK_AND_READ),
BIT_NAME(CAP_NT_FIND),
BIT_NAME(CAP_DFS),
BIT_NAME(CAP_W2K_SMBS),
BIT_NAME(CAP_LARGE_READX),
BIT_NAME(CAP_LARGE_WRITEX),
BIT_NAME(CAP_UNIX),
BIT_NAME(CAP_EXTENDED_SECURITY),
{ NULL, 0 }
};
static void show_bits(const struct bitmapping *bm, uint32_t value)
{
int i;
for (i=0;bm[i].name;i++) {
if (value & bm[i].value) {
d_printf("\t%s\n", bm[i].name);
value &= ~bm[i].value;
}
}
if (value != 0) {
d_printf("\tunknown bits: 0x%08x\n", value);
}
}
/*
print out server properties
*/
BOOL torture_test_properties(struct torture_context *torture,
struct smbcli_state *cli)
{
BOOL correct = True;
union smb_fsinfo fs;
NTSTATUS status;
d_printf("Capabilities: 0x%08x\n", cli->transport->negotiate.capabilities);
show_bits(capability_bits, cli->transport->negotiate.capabilities);
d_printf("\n");
fs.attribute_info.level = RAW_QFS_ATTRIBUTE_INFO;
status = smb_raw_fsinfo(cli->tree, cli, &fs);
if (!NT_STATUS_IS_OK(status)) {
d_printf("qfsinfo failed - %s\n", nt_errstr(status));
correct = False;
} else {
d_printf("Filesystem attributes: 0x%08x\n",
fs.attribute_info.out.fs_attr);
show_bits(fs_attr_bits, fs.attribute_info.out.fs_attr);
d_printf("max_file_component_length: %d\n",
fs.attribute_info.out.max_file_component_length);
d_printf("fstype: %s\n", fs.attribute_info.out.fs_type.s);
}
return correct;
}
+99
View File
@@ -0,0 +1,99 @@
/*
Unix SMB/CIFS implementation.
rename testing
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "libcli/libcli.h"
#include "torture/torture.h"
#include "torture/util.h"
/*
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;
}
+558
View File
@@ -0,0 +1,558 @@
/*
Unix SMB/CIFS implementation.
SMB torture tester - scanning functions
Copyright (C) Andrew Tridgell 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#include "libcli/raw/libcliraw.h"
#include "system/filesys.h"
#include "pstring.h"
#define VERBOSE 0
#define OP_MIN 0
#define OP_MAX 100
/****************************************************************************
look for a partial hit
****************************************************************************/
static void trans2_check_hit(const char *format, int op, int level, NTSTATUS status)
{
if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) ||
NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) ||
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
return;
}
#if VERBOSE
printf("possible %s hit op=%3d level=%5d status=%s\n",
format, op, level, nt_errstr(status));
#endif
}
/****************************************************************************
check for existance of a trans2 call
****************************************************************************/
static NTSTATUS try_trans2(struct smbcli_state *cli,
int op,
uint8_t *param, uint8_t *data,
int param_len, int data_len,
int *rparam_len, int *rdata_len)
{
NTSTATUS status;
struct smb_trans2 t2;
uint16_t setup = op;
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_init("try_trans2");
t2.in.max_param = 64;
t2.in.max_data = smb_raw_max_trans_data(cli->tree, 64);
t2.in.max_setup = 10;
t2.in.flags = 0;
t2.in.timeout = 0;
t2.in.setup_count = 1;
t2.in.setup = &setup;
t2.in.params.data = param;
t2.in.params.length = param_len;
t2.in.data.data = data;
t2.in.data.length = data_len;
status = smb_raw_trans2(cli->tree, mem_ctx, &t2);
*rparam_len = t2.out.params.length;
*rdata_len = t2.out.data.length;
talloc_free(mem_ctx);
return status;
}
static NTSTATUS try_trans2_len(struct smbcli_state *cli,
const char *format,
int op, int level,
uint8_t *param, uint8_t *data,
int param_len, int *data_len,
int *rparam_len, int *rdata_len)
{
NTSTATUS ret=NT_STATUS_OK;
ret = try_trans2(cli, op, param, data, param_len,
sizeof(pstring), rparam_len, rdata_len);
#if VERBOSE
printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
#endif
if (!NT_STATUS_IS_OK(ret)) return ret;
*data_len = 0;
while (*data_len < sizeof(pstring)) {
ret = try_trans2(cli, op, param, data, param_len,
*data_len, rparam_len, rdata_len);
if (NT_STATUS_IS_OK(ret)) break;
*data_len += 2;
}
if (NT_STATUS_IS_OK(ret)) {
printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
format, level, *data_len, *rparam_len, *rdata_len);
} else {
trans2_check_hit(format, op, level, ret);
}
return ret;
}
/****************************************************************************
check whether a trans2 opnum exists at all
****************************************************************************/
static BOOL trans2_op_exists(struct smbcli_state *cli, int op)
{
int data_len = 0;
int param_len = 0;
int rparam_len, rdata_len;
uint8_t param[1024], data[1024];
NTSTATUS status1, status2;
memset(data, 0, sizeof(data));
data_len = 4;
/* try with a info level only */
param_len = sizeof(param);
data_len = sizeof(data);
memset(param, 0xFF, sizeof(param));
memset(data, 0xFF, sizeof(data));
status1 = try_trans2(cli, 0xFFFF, param, data, param_len, data_len,
&rparam_len, &rdata_len);
status2 = try_trans2(cli, op, param, data, param_len, data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_EQUAL(status1, status2)) return False;
printf("Found op %d (status=%s)\n", op, nt_errstr(status2));
return True;
}
/****************************************************************************
check for existance of a trans2 call
****************************************************************************/
static BOOL scan_trans2(struct smbcli_state *cli, int op, int level,
int fnum, int dnum, int qfnum, const char *fname)
{
int data_len = 0;
int param_len = 0;
int rparam_len, rdata_len;
uint8_t param[1024], data[1024];
NTSTATUS status;
memset(data, 0, sizeof(data));
data_len = 4;
/* try with a info level only */
param_len = 2;
SSVAL(param, 0, level);
status = try_trans2_len(cli, "void", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a file descriptor */
param_len = 6;
SSVAL(param, 0, fnum);
SSVAL(param, 2, level);
SSVAL(param, 4, 0);
status = try_trans2_len(cli, "fnum", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a quota file descriptor */
param_len = 6;
SSVAL(param, 0, qfnum);
SSVAL(param, 2, level);
SSVAL(param, 4, 0);
status = try_trans2_len(cli, "qfnum", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a notify style */
param_len = 6;
SSVAL(param, 0, dnum);
SSVAL(param, 2, dnum);
SSVAL(param, 4, level);
status = try_trans2_len(cli, "notify", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a file name */
param_len = 6;
SSVAL(param, 0, level);
SSVAL(param, 2, 0);
SSVAL(param, 4, 0);
param_len += push_string(&param[6], fname, sizeof(pstring)-7, STR_TERMINATE|STR_UNICODE);
status = try_trans2_len(cli, "fname", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a new file name */
param_len = 6;
SSVAL(param, 0, level);
SSVAL(param, 2, 0);
SSVAL(param, 4, 0);
param_len += push_string(&param[6], "\\newfile.dat", sizeof(pstring)-7, STR_TERMINATE|STR_UNICODE);
status = try_trans2_len(cli, "newfile", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
smbcli_unlink(cli->tree, "\\newfile.dat");
smbcli_rmdir(cli->tree, "\\newfile.dat");
if (NT_STATUS_IS_OK(status)) return True;
/* try dfs style */
smbcli_mkdir(cli->tree, "\\testdir");
param_len = 2;
SSVAL(param, 0, level);
param_len += push_string(&param[2], "\\testdir", sizeof(pstring)-3, STR_TERMINATE|STR_UNICODE);
status = try_trans2_len(cli, "dfs", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
smbcli_rmdir(cli->tree, "\\testdir");
if (NT_STATUS_IS_OK(status)) return True;
return False;
}
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;
}
/****************************************************************************
look for a partial hit
****************************************************************************/
static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status)
{
if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) ||
NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) ||
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
return;
}
#if VERBOSE
printf("possible %s hit op=%3d level=%5d status=%s\n",
format, op, level, nt_errstr(status));
#endif
}
/****************************************************************************
check for existence of a nttrans call
****************************************************************************/
static NTSTATUS try_nttrans(struct smbcli_state *cli,
int op,
uint8_t *param, uint8_t *data,
int param_len, int data_len,
int *rparam_len, int *rdata_len)
{
struct smb_nttrans parms;
DATA_BLOB ntparam_blob, ntdata_blob;
TALLOC_CTX *mem_ctx;
NTSTATUS status;
mem_ctx = talloc_init("try_nttrans");
ntparam_blob.length = param_len;
ntparam_blob.data = param;
ntdata_blob.length = data_len;
ntdata_blob.data = data;
parms.in.max_param = 64;
parms.in.max_data = smb_raw_max_trans_data(cli->tree, 64);
parms.in.max_setup = 0;
parms.in.setup_count = 0;
parms.in.function = op;
parms.in.params = ntparam_blob;
parms.in.data = ntdata_blob;
status = smb_raw_nttrans(cli->tree, mem_ctx, &parms);
if (NT_STATUS_IS_ERR(status)) {
DEBUG(1,("Failed to send NT_TRANS\n"));
talloc_free(mem_ctx);
return status;
}
*rparam_len = parms.out.params.length;
*rdata_len = parms.out.data.length;
talloc_free(mem_ctx);
return status;
}
static NTSTATUS try_nttrans_len(struct smbcli_state *cli,
const char *format,
int op, int level,
uint8_t *param, uint8_t *data,
int param_len, int *data_len,
int *rparam_len, int *rdata_len)
{
NTSTATUS ret=NT_STATUS_OK;
ret = try_nttrans(cli, op, param, data, param_len,
sizeof(pstring), rparam_len, rdata_len);
#if VERBOSE
printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
#endif
if (!NT_STATUS_IS_OK(ret)) return ret;
*data_len = 0;
while (*data_len < sizeof(pstring)) {
ret = try_nttrans(cli, op, param, data, param_len,
*data_len, rparam_len, rdata_len);
if (NT_STATUS_IS_OK(ret)) break;
*data_len += 2;
}
if (NT_STATUS_IS_OK(ret)) {
printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
format, level, *data_len, *rparam_len, *rdata_len);
} else {
nttrans_check_hit(format, op, level, ret);
}
return ret;
}
/****************************************************************************
check for existance of a nttrans call
****************************************************************************/
static BOOL scan_nttrans(struct smbcli_state *cli, int op, int level,
int fnum, int dnum, const char *fname)
{
int data_len = 0;
int param_len = 0;
int rparam_len, rdata_len;
uint8_t param[1024], data[1024];
NTSTATUS status;
memset(data, 0, sizeof(data));
data_len = 4;
/* try with a info level only */
param_len = 2;
SSVAL(param, 0, level);
status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a file descriptor */
param_len = 6;
SSVAL(param, 0, fnum);
SSVAL(param, 2, level);
SSVAL(param, 4, 0);
status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a notify style */
param_len = 6;
SSVAL(param, 0, dnum);
SSVAL(param, 2, dnum);
SSVAL(param, 4, level);
status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a file name */
param_len = 6;
SSVAL(param, 0, level);
SSVAL(param, 2, 0);
SSVAL(param, 4, 0);
param_len += push_string(&param[6], fname, sizeof(pstring), STR_TERMINATE | STR_UNICODE);
status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
if (NT_STATUS_IS_OK(status)) return True;
/* try with a new file name */
param_len = 6;
SSVAL(param, 0, level);
SSVAL(param, 2, 0);
SSVAL(param, 4, 0);
param_len += push_string(&param[6], "\\newfile.dat", sizeof(pstring), STR_TERMINATE | STR_UNICODE);
status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
smbcli_unlink(cli->tree, "\\newfile.dat");
smbcli_rmdir(cli->tree, "\\newfile.dat");
if (NT_STATUS_IS_OK(status)) return True;
/* try dfs style */
smbcli_mkdir(cli->tree, "\\testdir");
param_len = 2;
SSVAL(param, 0, level);
param_len += push_string(&param[2], "\\testdir", sizeof(pstring), STR_TERMINATE | STR_UNICODE);
status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len,
&rparam_len, &rdata_len);
smbcli_rmdir(cli->tree, "\\testdir");
if (NT_STATUS_IS_OK(status)) return True;
return False;
}
BOOL torture_nttrans_scan(struct torture_context *torture,
struct smbcli_state *cli)
{
int op, level;
const char *fname = "\\scanner.dat";
int fnum, dnum;
fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC,
DENY_NONE);
dnum = smbcli_open(cli->tree, "\\", O_RDONLY, DENY_NONE);
for (op=OP_MIN; op<=OP_MAX; op++) {
printf("Scanning op=%d\n", op);
for (level = 0; level <= 50; level++) {
scan_nttrans(cli, op, level, fnum, dnum, fname);
}
for (level = 0x100; level <= 0x130; level++) {
scan_nttrans(cli, op, level, fnum, dnum, fname);
}
for (level = 1000; level < 1050; level++) {
scan_nttrans(cli, op, level, fnum, dnum, fname);
}
}
torture_close_connection(cli);
printf("nttrans scan finished\n");
return True;
}
/* scan for valid base SMB requests */
BOOL torture_smb_scan(struct torture_context *torture)
{
static struct smbcli_state *cli;
int op;
struct smbcli_request *req;
NTSTATUS status;
for (op=0x0;op<=0xFF;op++) {
if (op == SMBreadbraw) continue;
if (!torture_open_connection(&cli, 0)) {
return False;
}
req = smbcli_request_setup(cli->tree, op, 0, 0);
if (!smbcli_request_send(req)) {
smbcli_request_destroy(req);
break;
}
usleep(10000);
smbcli_transport_process(cli->transport);
if (req->state > SMBCLI_REQUEST_RECV) {
status = smbcli_request_simple_recv(req);
printf("op=0x%x status=%s\n", op, nt_errstr(status));
torture_close_connection(cli);
continue;
}
sleep(1);
smbcli_transport_process(cli->transport);
if (req->state > SMBCLI_REQUEST_RECV) {
status = smbcli_request_simple_recv(req);
printf("op=0x%x status=%s\n", op, nt_errstr(status));
} else {
printf("op=0x%x no reply\n", op);
smbcli_request_destroy(req);
continue; /* don't attempt close! */
}
torture_close_connection(cli);
}
printf("smb scan finished\n");
return True;
}
+72
View File
@@ -0,0 +1,72 @@
/*
Unix SMB/CIFS implementation.
find security related memory leaks
Copyright (C) Andrew Tridgell 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#include "system/time.h"
#include "libcli/smb_composite/smb_composite.h"
#include "auth/credentials/credentials.h"
static BOOL try_failed_login(struct smbcli_state *cli)
{
NTSTATUS status;
struct smb_composite_sesssetup setup;
struct smbcli_session *session;
session = smbcli_session_init(cli->transport, cli, False);
setup.in.sesskey = cli->transport->negotiate.sesskey;
setup.in.capabilities = cli->transport->negotiate.capabilities;
setup.in.workgroup = lp_workgroup();
setup.in.credentials = cli_credentials_init(session);
cli_credentials_set_conf(setup.in.credentials);
cli_credentials_set_domain(setup.in.credentials, "INVALID-DOMAIN", CRED_SPECIFIED);
cli_credentials_set_username(setup.in.credentials, "INVALID-USERNAME", CRED_SPECIFIED);
cli_credentials_set_password(setup.in.credentials, "INVALID-PASSWORD", CRED_SPECIFIED);
status = smb_composite_sesssetup(session, &setup);
talloc_free(session);
if (NT_STATUS_IS_OK(status)) {
printf("Allowed session setup with invalid credentials?!\n");
return False;
}
return True;
}
BOOL torture_sec_leak(struct torture_context *tctx, struct smbcli_state *cli)
{
time_t t1 = time(NULL);
int timelimit = torture_setting_int(tctx, "timelimit", 20);
while (time(NULL) < t1+timelimit) {
if (!try_failed_login(cli)) {
return False;
}
talloc_report(NULL, stdout);
}
return True;
}
+93
View File
@@ -0,0 +1,93 @@
/*
Unix SMB/CIFS implementation.
unlink tester
Copyright (C) Andrew Tridgell 2003
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/filesys.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#define BASEDIR "\\unlinktest"
/*
This test checks that
1) the server does not allow an unlink on a file that is open
*/
BOOL torture_unlinktest(struct torture_context *tctx, struct smbcli_state *cli)
{
const char *fname = BASEDIR "\\unlink.tst";
int fnum;
BOOL correct = True;
union smb_open io;
NTSTATUS status;
torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
talloc_asprintf(tctx, "Failed setting up %s", BASEDIR));
cli->session->pid = 1;
torture_comment(tctx, "Opening a file\n");
fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
torture_comment(tctx, "Unlinking a open file\n");
torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlink(cli->tree, fname)),
"server allowed unlink on an open file");
correct = check_error(__location__, cli, ERRDOS, ERRbadshare,
NT_STATUS_SHARING_VIOLATION);
smbcli_close(cli->tree, fnum);
smbcli_unlink(cli->tree, fname);
torture_comment(tctx, "testing unlink after ntcreatex with DELETE access\n");
io.ntcreatex.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
io.ntcreatex.in.file_attr = 0;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
io.ntcreatex.in.security_flags = 0;
io.ntcreatex.in.fname = fname;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
status = smb_raw_open(cli->tree, cli, &io);
torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "failed to open %s", fname));
torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlink(cli->tree, fname)),
"server allowed unlink on an open file");
correct = check_error(__location__, cli, ERRDOS, ERRbadshare,
NT_STATUS_SHARING_VIOLATION);
return correct;
}
+188
View File
@@ -0,0 +1,188 @@
/*
Unix SMB/CIFS implementation.
SMB torture tester - unicode table dumper
Copyright (C) Andrew Tridgell 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "torture/torture.h"
#include "system/filesys.h"
#include "system/locale.h"
#include "libcli/libcli.h"
#include "torture/util.h"
#include "pstring.h"
bool torture_utable(struct torture_context *tctx,
struct smbcli_state *cli)
{
fstring fname;
const char *alt_name;
int fnum;
uint8_t c2[4];
int c, len, fd;
int chars_allowed=0, alt_allowed=0;
uint8_t valid[0x10000];
torture_comment(tctx, "Generating valid character table\n");
memset(valid, 0, sizeof(valid));
torture_assert(tctx, torture_setup_dir(cli, "\\utable"),
"Setting up dir \\utable failed");
for (c=1; c < 0x10000; c++) {
char *p;
SSVAL(c2, 0, c);
fstrcpy(fname, "\\utable\\x");
p = fname+strlen(fname);
len = convert_string(CH_UTF16, CH_UNIX,
c2, 2,
p, sizeof(fname)-strlen(fname));
p[len] = 0;
fstrcat(fname,"_a_long_extension");
fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC,
DENY_NONE);
if (fnum == -1) continue;
chars_allowed++;
smbcli_qpathinfo_alt_name(cli->tree, fname, &alt_name);
if (strncmp(alt_name, "X_A_L", 5) != 0) {
alt_allowed++;
valid[c] = 1;
torture_comment(tctx, "fname=[%s] alt_name=[%s]\n", fname, alt_name);
}
smbcli_close(cli->tree, fnum);
smbcli_unlink(cli->tree, fname);
if (c % 100 == 0) {
torture_comment(tctx, "%d (%d/%d)\r", c, chars_allowed, alt_allowed);
}
}
torture_comment(tctx, "%d (%d/%d)\n", c, chars_allowed, alt_allowed);
smbcli_rmdir(cli->tree, "\\utable");
torture_comment(tctx, "%d chars allowed %d alt chars allowed\n", chars_allowed, alt_allowed);
fd = open("valid.dat", O_WRONLY|O_CREAT|O_TRUNC, 0644);
torture_assert(tctx, fd != -1,
talloc_asprintf(tctx,
"Failed to create valid.dat - %s", strerror(errno)));
write(fd, valid, 0x10000);
close(fd);
torture_comment(tctx, "wrote valid.dat\n");
return true;
}
static char *form_name(int c)
{
static fstring fname;
uint8_t c2[4];
char *p;
int len;
fstrcpy(fname, "\\utable\\");
p = fname+strlen(fname);
SSVAL(c2, 0, c);
len = convert_string(CH_UTF16, CH_UNIX,
c2, 2,
p, sizeof(fname)-strlen(fname));
p[len] = 0;
return fname;
}
bool torture_casetable(struct torture_context *tctx,
struct smbcli_state *cli)
{
char *fname;
int fnum;
int c, i;
#define MAX_EQUIVALENCE 8
codepoint_t equiv[0x10000][MAX_EQUIVALENCE];
torture_comment(tctx, "Determining upper/lower case table\n");
memset(equiv, 0, sizeof(equiv));
torture_assert(tctx, torture_setup_dir(cli, "\\utable"),
"Error setting up dir \\utable");
for (c=1; c < 0x10000; c++) {
size_t size;
if (c == '.' || c == '\\') continue;
torture_comment(tctx, "%04x (%c)\n", c, isprint(c)?c:'.');
fname = form_name(c);
fnum = smbcli_nt_create_full(cli->tree, fname, 0,
#if 0
SEC_RIGHT_MAXIMUM_ALLOWED,
#else
SEC_RIGHTS_FILE_ALL,
#endif
FILE_ATTRIBUTE_NORMAL,
NTCREATEX_SHARE_ACCESS_NONE,
NTCREATEX_DISP_OPEN_IF, 0, 0);
torture_assert(tctx, fnum != -1,
talloc_asprintf(tctx,
"Failed to create file with char %04x\n", c));
size = 0;
if (NT_STATUS_IS_ERR(smbcli_qfileinfo(cli->tree, fnum, NULL, &size,
NULL, NULL, NULL, NULL, NULL))) continue;
if (size > 0) {
/* found a character equivalence! */
int c2[MAX_EQUIVALENCE];
if (size/sizeof(int) >= MAX_EQUIVALENCE) {
torture_comment(tctx, "too many chars match?? size=%d c=0x%04x\n",
(int)size, c);
smbcli_close(cli->tree, fnum);
return False;
}
smbcli_read(cli->tree, fnum, c2, 0, size);
torture_comment(tctx, "%04x: ", c);
equiv[c][0] = c;
for (i=0; i<size/sizeof(int); i++) {
torture_comment(tctx, "%04x ", c2[i]);
equiv[c][i+1] = c2[i];
}
torture_comment(tctx, "\n");
}
smbcli_write(cli->tree, fnum, 0, &c, size, sizeof(c));
smbcli_close(cli->tree, fnum);
}
smbcli_unlink(cli->tree, "\\utable\\*");
smbcli_rmdir(cli->tree, "\\utable");
return true;
}