From fa0bc441e35bf0451f3ea471c4c144206a80febd Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 20:06:04 +1000 Subject: don't allow a file to be changed to a directory with setfileinfo (This used to be commit ad7acbf8bf83c7250dfcbd57f0f4e19e57534a92) --- source4/ntvfs/posix/pvfs_setfileinfo.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index 0beca75ead..1dd2c075d9 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -457,7 +457,12 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, /* possibly change the attribute */ if (newstats.dos.attrib != h->name->dos.attrib) { - mode_t mode = pvfs_fileperms(pvfs, newstats.dos.attrib); + mode_t mode; + if ((newstats.dos.attrib & FILE_ATTRIBUTE_DIRECTORY) && + !(h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) { + return NT_STATUS_INVALID_PARAMETER; + } + mode = pvfs_fileperms(pvfs, newstats.dos.attrib); if (!(h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) { if (fchmod(h->fd, mode) == -1) { return pvfs_map_errno(pvfs, errno); -- cgit From e814586bddd081d85a216533bf47a1ac9d8b025f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 20:06:22 +1000 Subject: generate security descriptors in gentest_smb2 (This used to be commit 5ca7e9590e792dc409c6677321cd14362255964e) --- source4/torture/gentest_smb2.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c index a3a794d3ea..84178ed9a5 100644 --- a/source4/torture/gentest_smb2.c +++ b/source4/torture/gentest_smb2.c @@ -30,11 +30,13 @@ #include "libcli/smb2/smb2.h" #include "libcli/smb2/smb2_calls.h" #include "librpc/gen_ndr/security.h" +#include "librpc/gen_ndr/ndr_security.h" #include "auth/credentials/credentials.h" #include "libcli/resolve/resolve.h" #include "auth/gensec/gensec.h" #include "param/param.h" #include "dynconfig/dynconfig.h" +#include "libcli/security/security.h" #define NSERVERS 2 #define NINSTANCES 2 @@ -725,6 +727,26 @@ static struct smb_ea_list gen_ea_list(void) return eas; } +/* generate a security descriptor */ +static struct security_descriptor *gen_sec_desc(void) +{ + struct security_descriptor *sd; + if (gen_chance(90)) return NULL; + + sd = security_descriptor_dacl_create(current_op.mem_ctx, + 0, NULL, NULL, + NULL, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC, + SEC_ACE_FLAG_OBJECT_INHERIT, + SID_WORLD, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_FILE_ALL | SEC_STD_ALL, + 0, + NULL); + return sd; +} + static void oplock_handler_close_recv(struct smb2_request *req) { NTSTATUS status; @@ -1066,6 +1088,13 @@ again: } \ } while(0) +#define CHECK_SECDESC(field) do { \ + if (!security_acl_equal(parm[0].field->dacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \ + printf("Mismatch in %s\n", #field); \ + return false; \ + } \ +} while(0) + #define CHECK_ATTRIB(field) do { \ if (!options.mask_indexing) { \ CHECK_EQUAL(field); \ @@ -1134,6 +1163,7 @@ static bool handler_create(int instance) parm[0].in.query_maximal_access = gen_bool(); parm[0].in.timewarp = gen_timewarp(); parm[0].in.query_on_disk_id = gen_bool(); + parm[0].in.sec_desc = gen_sec_desc(); if (!options.use_oplocks) { /* mask out oplocks */ @@ -1340,7 +1370,7 @@ static void gen_fileinfo(int instance, union smb_fileinfo *info) LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION), LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION), LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION), - LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), + LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC), }; do { i = gen_int_range(0, ARRAY_SIZE(levels)-1); @@ -1490,9 +1520,11 @@ static bool cmp_fileinfo(int instance, } break; - /* Unhandled levels */ - case RAW_FILEINFO_SEC_DESC: + CHECK_SECDESC(query_secdesc.out.sd); + break; + + /* Unhandled levels */ case RAW_FILEINFO_EA_LIST: case RAW_FILEINFO_UNIX_BASIC: case RAW_FILEINFO_UNIX_LINK: -- cgit From f7bf79043e664b83e62dae6ea187b5c019968d28 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 20:06:38 +1000 Subject: added testing of some strange read semantics on windows (This used to be commit 46a0b65742bc0e4277da53df9df823abd4a0d150) --- source4/torture/smb2/read.c | 61 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/torture/smb2/read.c b/source4/torture/smb2/read.c index b3c13ad667..1f306028f6 100644 --- a/source4/torture/smb2/read.c +++ b/source4/torture/smb2/read.c @@ -44,6 +44,9 @@ goto done; \ }} while (0) +#define FNAME "smb2_readtest.dat" +#define DNAME "smb2_readtest.dir" + static bool test_read_eof(struct torture_context *torture, struct smb2_tree *tree) { bool ret = true; @@ -55,7 +58,7 @@ static bool test_read_eof(struct torture_context *torture, struct smb2_tree *tre ZERO_STRUCT(buf); - status = torture_smb2_testfile(tree, "lock1.txt", &h); + status = torture_smb2_testfile(tree, FNAME, &h); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf)); @@ -139,7 +142,7 @@ static bool test_read_position(struct torture_context *torture, struct smb2_tree ZERO_STRUCT(buf); - status = torture_smb2_testfile(tree, "lock1.txt", &h); + status = torture_smb2_testfile(tree, FNAME, &h); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf)); @@ -172,6 +175,59 @@ done: return ret; } +static bool test_read_dir(struct torture_context *torture, struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_handle h; + uint8_t buf[100]; + struct smb2_read rd; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + + status = torture_smb2_testdir(tree, DNAME, &h); + if (!NT_STATUS_IS_OK(status)) { + printf(__location__ " Unable to create test directory '%s' - %s\n", DNAME, nt_errstr(status)); + return false; + } + + ZERO_STRUCT(rd); + rd.in.file.handle = h; + rd.in.length = 10; + rd.in.offset = 0; + rd.in.min_count = 1; + + status = smb2_read(tree, tmp_ctx, &rd); + CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST); + + rd.in.min_count = 11; + status = smb2_read(tree, tmp_ctx, &rd); + CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST); + + rd.in.length = 0; + rd.in.min_count = 2592; + status = smb2_read(tree, tmp_ctx, &rd); + if (torture_setting_bool(torture, "windows", false)) { + CHECK_STATUS(status, NT_STATUS_END_OF_FILE); + } else { + CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST); + } + + rd.in.length = 0; + rd.in.min_count = 0; + rd.in.channel = 0; + status = smb2_read(tree, tmp_ctx, &rd); + if (torture_setting_bool(torture, "windows", false)) { + CHECK_STATUS(status, NT_STATUS_OK); + } else { + CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST); + } + +done: + talloc_free(tmp_ctx); + return ret; +} + + /* basic testing of SMB2 read */ @@ -181,6 +237,7 @@ struct torture_suite *torture_smb2_read_init(void) torture_suite_add_1smb2_test(suite, "EOF", test_read_eof); torture_suite_add_1smb2_test(suite, "POSITION", test_read_position); + torture_suite_add_1smb2_test(suite, "DIR", test_read_dir); suite->description = talloc_strdup(suite, "SMB2-READ tests"); -- cgit From 1eabf8155486d007a69667175ae7f6bebc440122 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 20:06:48 +1000 Subject: check that we can't change a file to a directory (This used to be commit e013ada415ebb25e925f715791757330ba003b43) --- source4/torture/smb2/setinfo.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source4') diff --git a/source4/torture/smb2/setinfo.c b/source4/torture/smb2/setinfo.c index 685bb5a47b..7a912b4989 100644 --- a/source4/torture/smb2/setinfo.c +++ b/source4/torture/smb2/setinfo.c @@ -175,6 +175,10 @@ bool torture_smb2_setinfo(struct torture_context *torture) CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN); + printf("can't change a file to a directory\n"); + sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY; + CHECK_CALL(BASIC_INFORMATION, NT_STATUS_INVALID_PARAMETER); + printf("restore attribute\n"); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); -- cgit From f4077a05cbdb0a7bb0cc9baf120d26e026f86b9b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 21:48:26 +1000 Subject: updated comment based on MS-SMB2 docs (This used to be commit 5754cc13514a0f5fe4c47ce53521c256c9d96487) --- source4/libcli/smb2/create.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/libcli/smb2/create.c b/source4/libcli/smb2/create.c index bff0a1587d..342a519376 100644 --- a/source4/libcli/smb2/create.c +++ b/source4/libcli/smb2/create.c @@ -387,7 +387,8 @@ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct /* pull out the parsed blobs */ for (i=0;iout.blobs.num_blobs;i++) { if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) { - /* why 8 bytes not 4?? */ + /* TODO: this also contains a status field in + first 4 bytes */ if (io->out.blobs.blobs[i].data.length != 8) { smb2_request_destroy(req); return NT_STATUS_INVALID_NETWORK_RESPONSE; -- cgit From 86d69fd4b642860c3092a79ebbfb02544043b82d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 21:48:40 +1000 Subject: SMB2 doesn't have NAME_INFORMATION level (This used to be commit a431d51b113c2e214ccfe7a678ba0a565b020263) --- source4/ntvfs/posix/pvfs_qfileinfo.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source4') diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index c663466985..b9f763c2e0 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -216,6 +216,10 @@ static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs, case RAW_FILEINFO_NAME_INFO: case RAW_FILEINFO_NAME_INFORMATION: + if (req->ctx->protocol == PROTOCOL_SMB2) { + /* strange that SMB2 doesn't have this */ + return NT_STATUS_NOT_SUPPORTED; + } info->name_info.out.fname.s = name->original_name; return NT_STATUS_OK; -- cgit From dfdfe06dc126822de8705d9308237864965c7d40 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 21:49:04 +1000 Subject: added --noacls options and checking for same mismatch in backtracking (This used to be commit c7d2e1bf65a28b6a2efd60585ae8ead2fb486e53) --- source4/torture/gentest_smb2.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c index 84178ed9a5..e50c4969d5 100644 --- a/source4/torture/gentest_smb2.c +++ b/source4/torture/gentest_smb2.c @@ -57,6 +57,7 @@ static struct gentest_options { int fast_reconnect; int mask_indexing; int no_eas; + int no_acls; int skip_cleanup; int valid; } options; @@ -109,6 +110,7 @@ static struct { NTSTATUS status; uint_t opnum; TALLOC_CTX *mem_ctx; + const char *mismatch; } current_op; static struct smb2_handle bad_smb2_handle; @@ -731,7 +733,7 @@ static struct smb_ea_list gen_ea_list(void) static struct security_descriptor *gen_sec_desc(void) { struct security_descriptor *sd; - if (gen_chance(90)) return NULL; + if (options.no_acls || gen_chance(90)) return NULL; sd = security_descriptor_dacl_create(current_op.mem_ctx, 0, NULL, NULL, @@ -883,6 +885,7 @@ static bool compare_status(NTSTATUS status1, NTSTATUS status2) ignore_pattern(nt_errstr(status2))) { return true; } + current_op.mismatch = nt_errstr(status1); return false; } @@ -983,6 +986,7 @@ again: printf("Notify status mismatch - %s - %s\n", nt_errstr(notifies[0][j].status), nt_errstr(notifies[i][j].status)); + current_op.mismatch = "Notify status"; return false; } @@ -1082,6 +1086,7 @@ again: #define CHECK_EQUAL(field) do { \ if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%llx 0x%llx\n", #field, \ (unsigned long long)parm[0].field, (unsigned long long)parm[1].field); \ return false; \ @@ -1090,6 +1095,7 @@ again: #define CHECK_SECDESC(field) do { \ if (!security_acl_equal(parm[0].field->dacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s\n", #field); \ return false; \ } \ @@ -1099,6 +1105,7 @@ again: if (!options.mask_indexing) { \ CHECK_EQUAL(field); \ } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ (int)parm[0].field, (int)parm[1].field); \ return false; \ @@ -1111,6 +1118,7 @@ again: return false; \ } \ if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - %s %s\n", #field, \ parm[0].field.s, parm[1].field.s); \ return false; \ @@ -1120,6 +1128,7 @@ again: #define CHECK_BLOB_EQUAL(field) do { \ if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s\n", #field); \ return false; \ } \ @@ -1130,6 +1139,7 @@ again: if (labs(nt_time_to_unix(parm[0].field) - \ nt_time_to_unix(parm[1].field)) > time_skew() && \ !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ (int)nt_time_to_unix(parm[0].field), \ (int)nt_time_to_unix(parm[1].field)); \ @@ -1815,6 +1825,7 @@ static void backtrack_analyze(struct event_context *ev, struct loadparm_context *lp_ctx) { int chunk, ret; + const char *mismatch = current_op.mismatch; chunk = options.numops / 2; @@ -1841,6 +1852,9 @@ static void backtrack_analyze(struct event_context *ev, if (ret == options.numops) { /* this chunk is needed */ base += chunk; + } else if (strcmp(mismatch, current_op.mismatch)) { + base += chunk; + printf("Different error in backtracking\n"); } else if (ret < base) { printf("damn - inconsistent errors! found early error\n"); options.numops = ret+1; @@ -1989,6 +2003,7 @@ static bool split_unc_name(const char *unc, char **server, char **share) { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" }, {"maskindexing", 0, POPT_ARG_NONE, &options.mask_indexing, 0, "mask out the indexed file attrib", NULL}, {"noeas", 0, POPT_ARG_NONE, &options.no_eas, 0, "don't use extended attributes", NULL}, + {"noacls", 0, POPT_ARG_NONE, &options.no_acls, 0, "don't use ACLs", NULL}, {"skip-cleanup", 0, POPT_ARG_NONE, &options.skip_cleanup, 0, "don't delete files at start", NULL}, {"valid", 0, POPT_ARG_NONE, &options.valid, 0, "generate only valid fields", NULL}, POPT_COMMON_SAMBA -- cgit From 67226f054b57961ac00b419761014d4a92e8c18d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 22:44:20 +1000 Subject: fixed create_action for truncated files (This used to be commit 884c32fcef48244bd260026a61790332bd706eb4) --- source4/ntvfs/posix/pvfs_open.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 0f08136a79..a1c5571258 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -1122,6 +1122,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, uint32_t create_options; uint32_t share_access; uint32_t access_mask; + uint32_t create_action = NTCREATEX_ACTION_EXISTED; bool del_on_close; bool stream_existed, stream_truncate=false; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; @@ -1169,6 +1170,13 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_PARAMETER; } + /* we ignore some file_attr bits */ + io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED | + FILE_ATTRIBUTE_COMPRESSED | + FILE_ATTRIBUTE_REPARSE_POINT | + FILE_ATTRIBUTE_SPARSE | + FILE_ATTRIBUTE_NORMAL); + /* resolve the cifs name to a posix name */ status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, PVFS_RESOLVE_STREAMS, &name); @@ -1210,6 +1218,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, } else { stream_truncate = true; } + create_action = NTCREATEX_ACTION_TRUNCATED; break; case NTCREATEX_DISP_OPEN: @@ -1228,6 +1237,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, } else { stream_truncate = true; } + create_action = NTCREATEX_ACTION_TRUNCATED; break; case NTCREATEX_DISP_CREATE: @@ -1487,7 +1497,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, io->generic.out.oplock_level = oplock_granted; io->generic.out.file.ntvfs = h; io->generic.out.create_action = stream_existed? - NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED; + create_action:NTCREATEX_ACTION_CREATED; + io->generic.out.create_time = name->dos.create_time; io->generic.out.access_time = name->dos.access_time; io->generic.out.write_time = name->dos.write_time; -- cgit From 70eb8d54aec9cb97d8f6675c4dcac2510e1916bb Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 22:44:35 +1000 Subject: fixed current_op.mismatch for more cases (This used to be commit 8a2a31d050a31308036545414f8d180ec8148f1d) --- source4/torture/gentest_smb2.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c index e50c4969d5..5a209180e3 100644 --- a/source4/torture/gentest_smb2.c +++ b/source4/torture/gentest_smb2.c @@ -878,7 +878,10 @@ static bool compare_status(NTSTATUS status1, NTSTATUS status2) if (NT_STATUS_EQUAL(status1, status2)) return true; /* one code being an error and the other OK is always an error */ - if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) return false; + if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) { + current_op.mismatch = nt_errstr(status1); + return false; + } /* if we are ignoring one of the status codes then consider this a match */ if (ignore_pattern(nt_errstr(status1)) || @@ -932,6 +935,7 @@ again: oplocks[i][j].got_break, oplocks[i][j].handle, oplocks[i][j].level); + current_op.mismatch = "oplock break"; return false; } } @@ -976,6 +980,7 @@ again: printf("Notify count inconsistent %d %d\n", notifies[0][j].notify_count, notifies[i][j].notify_count); + current_op.mismatch = "notify count"; return false; } @@ -1003,6 +1008,7 @@ again: printf("Notify action %d inconsistent %d %d\n", n, not1.nttrans.out.changes[n].action, not2.nttrans.out.changes[n].action); + current_op.mismatch = "notify action"; return false; } if (strcmp(not1.nttrans.out.changes[n].name.s, @@ -1010,6 +1016,7 @@ again: printf("Notify name %d inconsistent %s %s\n", n, not1.nttrans.out.changes[n].name.s, not2.nttrans.out.changes[n].name.s); + current_op.mismatch = "notify name"; return false; } if (not1.nttrans.out.changes[n].name.private_length != @@ -1017,6 +1024,7 @@ again: printf("Notify name length %d inconsistent %d %d\n", n, not1.nttrans.out.changes[n].name.private_length, not2.nttrans.out.changes[n].name.private_length); + current_op.mismatch = "notify name length"; return false; } } @@ -1049,6 +1057,7 @@ again: if (!compare_status(status[i], status[0])) { \ printf("status different in %s - %s %s\n", #call, \ nt_errstr(status[0]), nt_errstr(status[i])); \ + current_op.mismatch = nt_errstr(status[0]); \ return false; \ } \ } \ @@ -1114,6 +1123,7 @@ again: #define CHECK_WSTR_EQUAL(field) do { \ if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \ + current_op.mismatch = #field; \ printf("%s is NULL!\n", #field); \ return false; \ } \ @@ -1852,7 +1862,8 @@ static void backtrack_analyze(struct event_context *ev, if (ret == options.numops) { /* this chunk is needed */ base += chunk; - } else if (strcmp(mismatch, current_op.mismatch)) { + } else if (mismatch != current_op.mismatch && + strcmp(mismatch, current_op.mismatch)) { base += chunk; printf("Different error in backtracking\n"); } else if (ret < base) { -- cgit From c793faf9986a754d4b68b9feb080878d130601e3 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 28 May 2008 22:44:54 +1000 Subject: check the set of file attributes which are ignored (This used to be commit c818f56d8ea3ddc6f4cc61e9d5ed6fd195280a5d) --- source4/torture/smb2/create.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index 733b2c2e8a..58d38a2cb3 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -52,7 +52,7 @@ static bool test_create_gentest(struct torture_context *torture, struct smb2_tre struct smb2_create io; NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(tree); - uint32_t access_mask, file_attributes, denied_mask; + uint32_t access_mask, file_attributes, file_attributes_set, denied_mask; ZERO_STRUCT(io); io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; @@ -115,7 +115,8 @@ static bool test_create_gentest(struct torture_context *torture, struct smb2_tre for (i=0;i<32;i++) { io.in.desired_access = 1< Date: Thu, 29 May 2008 18:23:00 +1000 Subject: fixed offset for maximal access response (This used to be commit ddd0bb32510d615c7b943fb4ce4c9c275b98ab89) --- source4/libcli/smb2/create.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/libcli/smb2/create.c b/source4/libcli/smb2/create.c index 342a519376..8a40e56a00 100644 --- a/source4/libcli/smb2/create.c +++ b/source4/libcli/smb2/create.c @@ -393,7 +393,7 @@ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_request_destroy(req); return NT_STATUS_INVALID_NETWORK_RESPONSE; } - io->out.maximal_access = IVAL(io->out.blobs.blobs[i].data.data, 0); + io->out.maximal_access = IVAL(io->out.blobs.blobs[i].data.data, 4); } if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) { if (io->out.blobs.blobs[i].data.length != 32) { -- cgit From e42ded24a085a9bfaae0e4973b8dd52681b51a8a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 May 2008 18:23:20 +1000 Subject: SEC_FILE_READ_ATTRIBUTE is only automatically granted on SMB, not SMB2 (This used to be commit 7bff0691428ed3f75c1a9cbaae692bc9830640e6) --- source4/ntvfs/posix/pvfs_acl.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/ntvfs/posix/pvfs_acl.c b/source4/ntvfs/posix/pvfs_acl.c index 507c22f050..089631a307 100644 --- a/source4/ntvfs/posix/pvfs_acl.c +++ b/source4/ntvfs/posix/pvfs_acl.c @@ -464,7 +464,11 @@ NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs, return NT_STATUS_ACCESS_DENIED; } - *access_mask |= SEC_FILE_READ_ATTRIBUTE; + if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) { + /* on SMB, this bit is always granted, even if not + asked for */ + *access_mask |= SEC_FILE_READ_ATTRIBUTE; + } return NT_STATUS_OK; } @@ -518,8 +522,11 @@ NTSTATUS pvfs_access_check(struct pvfs_state *pvfs, /* check the acl against the required access mask */ status = sec_access_check(sd, token, *access_mask, access_mask); - /* this bit is always granted, even if not asked for */ - *access_mask |= SEC_FILE_READ_ATTRIBUTE; + if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) { + /* on SMB, this bit is always granted, even if not + asked for */ + *access_mask |= SEC_FILE_READ_ATTRIBUTE; + } talloc_free(acl); -- cgit From 21d770a02c1e5e492c3d764881b82cbc0871ced0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 May 2008 18:23:33 +1000 Subject: querying the ACCESS_INFORMATION is always allowed (This used to be commit 25d5b94d6a700f2d294e108aeca85cffcd5bbb4f) --- source4/ntvfs/posix/pvfs_qfileinfo.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source4') diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index b9f763c2e0..3196cf2f8d 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -41,6 +41,10 @@ static uint32_t pvfs_fileinfo_access(union smb_fileinfo *info) needed = 0; break; + case RAW_FILEINFO_ACCESS_INFORMATION: + needed = 0; + break; + case RAW_FILEINFO_SEC_DESC: needed = 0; if (info->query_secdesc.in.secinfo_flags & (SECINFO_OWNER|SECINFO_GROUP)) { -- cgit From c86dc11be6e626fa81f025d7ec78226fb4249cdc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 May 2008 19:16:26 +1000 Subject: added support for returning the maximal access MXAC tag in SMB2 create (This used to be commit 4eb49335d5f0319f9aa47ded5215a2977d3336bf) --- source4/libcli/raw/interfaces.h | 9 ++++++++- source4/ntvfs/ntvfs_generic.c | 2 ++ source4/ntvfs/posix/pvfs_acl.c | 12 ++++++++++++ source4/ntvfs/posix/pvfs_open.c | 24 ++++++++++++++++++++---- source4/smb_server/smb2/fileio.c | 12 ++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/libcli/raw/interfaces.h b/source4/libcli/raw/interfaces.h index d170006d3b..19d51893a6 100644 --- a/source4/libcli/raw/interfaces.h +++ b/source4/libcli/raw/interfaces.h @@ -1354,7 +1354,7 @@ union smb_open { break; \ } \ } while (0) - /* SMBNTCreateX interface */ + /* SMBNTCreateX, nttrans and generic interface */ struct { enum smb_open_level level; struct { @@ -1377,6 +1377,9 @@ union smb_open { NTTRANS varient of the call */ struct security_descriptor *sec_desc; struct smb_ea_list *ea_list; + + /* some optional parameters from the SMB2 varient */ + bool query_maximal_access; } in; struct { union smb_handle file; @@ -1392,6 +1395,10 @@ union smb_open { uint16_t file_type; uint16_t ipc_state; uint8_t is_directory; + + /* optional return values matching SMB2 tagged + values in the call */ + uint32_t maximal_access; } out; } ntcreatex, nttrans, generic; diff --git a/source4/ntvfs/ntvfs_generic.c b/source4/ntvfs/ntvfs_generic.c index 9227295696..d705758475 100644 --- a/source4/ntvfs/ntvfs_generic.c +++ b/source4/ntvfs/ntvfs_generic.c @@ -233,6 +233,7 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs, io->smb2.out.size = io2->generic.out.size; io->smb2.out.file_attr = io2->generic.out.attrib; io->smb2.out.reserved2 = 0; + io->smb2.out.maximal_access = io2->generic.out.maximal_access; break; default: @@ -522,6 +523,7 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs, io2->generic.in.fname = io->smb2.in.fname; io2->generic.in.sec_desc = io->smb2.in.sec_desc; io2->generic.in.ea_list = &io->smb2.in.eas; + io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access; /* we don't support timewarp yet */ if (io->smb2.in.timewarp != 0) { diff --git a/source4/ntvfs/posix/pvfs_acl.c b/source4/ntvfs/posix/pvfs_acl.c index 089631a307..623b1ae5e9 100644 --- a/source4/ntvfs/posix/pvfs_acl.c +++ b/source4/ntvfs/posix/pvfs_acl.c @@ -807,3 +807,15 @@ NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs, return status; } + +/* + return the maximum allowed access mask +*/ +NTSTATUS pvfs_access_maximal_allowed(struct pvfs_state *pvfs, + struct ntvfs_request *req, + struct pvfs_filename *name, + uint32_t *maximal_access) +{ + *maximal_access = SEC_FLAG_MAXIMUM_ALLOWED; + return pvfs_access_check(pvfs, req, name, maximal_access); +} diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index a1c5571258..dada9f503f 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -252,8 +252,12 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, } else { status = pvfs_access_check_create(pvfs, req, name, &access_mask); } - if (!NT_STATUS_IS_OK(status)) { - return status; + NT_STATUS_NOT_OK_RETURN(status); + + if (io->generic.in.query_maximal_access) { + status = pvfs_access_maximal_allowed(pvfs, req, name, + &io->generic.out.maximal_access); + NT_STATUS_NOT_OK_RETURN(status); } f->ntvfs = h; @@ -578,6 +582,12 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, status = pvfs_access_check_create(pvfs, req, name, &access_mask); NT_STATUS_NOT_OK_RETURN(status); + if (io->generic.in.query_maximal_access) { + status = pvfs_access_maximal_allowed(pvfs, req, name, + &io->generic.out.maximal_access); + NT_STATUS_NOT_OK_RETURN(status); + } + /* check that the parent isn't opened with delete on close set */ status = pvfs_resolve_parent(pvfs, req, name, &parent); if (NT_STATUS_IS_OK(status)) { @@ -1135,6 +1145,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, return ntvfs_map_open(ntvfs, req, io); } + ZERO_STRUCT(io->generic.out); + create_options = io->generic.in.create_options; share_access = io->generic.in.share_access; access_mask = io->generic.in.access_mask; @@ -1282,8 +1294,12 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, /* check the security descriptor */ status = pvfs_access_check(pvfs, req, name, &access_mask); - if (!NT_STATUS_IS_OK(status)) { - return status; + NT_STATUS_NOT_OK_RETURN(status); + + if (io->generic.in.query_maximal_access) { + status = pvfs_access_maximal_allowed(pvfs, req, name, + &io->generic.out.maximal_access); + NT_STATUS_NOT_OK_RETURN(status); } status = ntvfs_handle_new(pvfs->ntvfs, req, &h); diff --git a/source4/smb_server/smb2/fileio.c b/source4/smb_server/smb2/fileio.c index 086ddc690e..2c322ea587 100644 --- a/source4/smb_server/smb2/fileio.c +++ b/source4/smb_server/smb2/fileio.c @@ -36,6 +36,18 @@ static void smb2srv_create_send(struct ntvfs_request *ntvfs) DATA_BLOB blob; SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_open); + + /* setup the blobs we should give in the reply */ + if (io->smb2.out.maximal_access != 0) { + uint32_t data[2]; + SIVAL(data, 0, 0); + SIVAL(data, 4, io->smb2.out.maximal_access); + SMB2SRV_CHECK(smb2_create_blob_add(req, &io->smb2.out.blobs, + SMB2_CREATE_TAG_MXAC, + data_blob_const(data, 8))); + } + + SMB2SRV_CHECK(smb2_create_blob_push(req, &blob, io->smb2.out.blobs)); SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x58, true, blob.length)); -- cgit From 215fd9764fe9d595941a58d022a05a4f83365595 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 May 2008 19:16:44 +1000 Subject: test the maximal access return (This used to be commit 23ffec5d140463c8307fd7e444ae25781ea3d792) --- source4/torture/smb2/create.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index 58d38a2cb3..eb6b333ef5 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -41,7 +41,7 @@ if (v != correct) { \ printf("(%s) Incorrect value for %s 0x%08llx - should be 0x%08llx\n", \ __location__, #v, (unsigned long long)v, (unsigned long long)correct); \ - return false; \ + return false; \ }} while (0) /* @@ -53,6 +53,7 @@ static bool test_create_gentest(struct torture_context *torture, struct smb2_tre NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(tree); uint32_t access_mask, file_attributes, file_attributes_set, denied_mask; + union smb_fileinfo q; ZERO_STRUCT(io); io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; @@ -181,6 +182,20 @@ static bool test_create_gentest(struct torture_context *torture, struct smb2_tre status = smb2_create(tree, tmp_ctx, &io); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); + io.in.fname = FNAME; + io.in.file_attributes = 0; + io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA; + io.in.query_maximal_access = true; + status = smb2_create(tree, tmp_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_EQUAL(io.out.maximal_access, 0x001f01ff); + + q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; + q.access_information.in.file.handle = io.out.file.handle; + status = smb2_getinfo_file(tree, tmp_ctx, &q); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access); + talloc_free(tmp_ctx); smb2_deltree(tree, FNAME); -- cgit From 523a0fccf374d56e9e73642a95564f5cb246d13d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 May 2008 19:30:11 +1000 Subject: check maximal_access here too (This used to be commit 8159b1598e21daee730e185d025694e27df18d1b) --- source4/torture/smb2/create.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4') diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index eb6b333ef5..c23ff8b8ce 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -256,6 +256,7 @@ static bool test_create_blob(struct torture_context *torture, struct smb2_tree * io.in.query_maximal_access = true; status = smb2_create(tree, tmp_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); + CHECK_EQUAL(io.out.maximal_access, 0x001f01ff); status = smb2_util_close(tree, io.out.file.handle); CHECK_STATUS(status, NT_STATUS_OK); -- cgit From de4c962638835274bd68680b2d338c074d8fab88 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 May 2008 19:32:04 +1000 Subject: fix from WSPP SMB2 test 11 (This used to be commit 81612b7854725837e8487bf97b87bff6548b6ad3) --- source4/smb_server/smb2/sesssetup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c index 1aaacf897c..d386bfc72d 100644 --- a/source4/smb_server/smb2/sesssetup.c +++ b/source4/smb_server/smb2/sesssetup.c @@ -158,7 +158,8 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses } if (!smb_sess) { - status = NT_STATUS_USER_SESSION_DELETED; + /* see WSPP test suite - test 11 */ + status = NT_STATUS_REQUEST_NOT_ACCEPTED; goto failed; } -- cgit From 383d10577cdee64c3d41682413445569ea3d202e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 May 2008 20:46:18 +1000 Subject: fixed the error code for bad SMB2 ioctls (This used to be commit b1d2d388ecff96dfcc17da24796f36c40cbb3eed) --- source4/ntvfs/posix/pvfs_ioctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/ntvfs/posix/pvfs_ioctl.c b/source4/ntvfs/posix/pvfs_ioctl.c index d0360e67ed..92d3eae061 100644 --- a/source4/ntvfs/posix/pvfs_ioctl.c +++ b/source4/ntvfs/posix/pvfs_ioctl.c @@ -73,7 +73,8 @@ NTSTATUS pvfs_ioctl(struct ntvfs_module_context *ntvfs, case RAW_IOCTL_SMB2: case RAW_IOCTL_SMB2_NO_HANDLE: - return NT_STATUS_FS_DRIVER_REQUIRED; + /* see WSPP SMB2 test 46 */ + return NT_STATUS_INVALID_DEVICE_REQUEST; } return NT_STATUS_INVALID_LEVEL; -- cgit From 8eef2e34128d713b741307a8c7b1650217698e06 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 May 2008 21:32:08 +1000 Subject: merged gentest.c and gentest_smb2.c The one gentest tool now covers both SMB and SMB2, using the command line switch --smb2 for SMB2 (This used to be commit d1125a303a31fbe08a9bd0064ec132b4d7cbb131) --- source4/torture/config.mk | 17 - source4/torture/gentest.c | 2225 ++++++++++++++++++++++++++++------------ source4/torture/gentest_smb2.c | 2122 -------------------------------------- 3 files changed, 1575 insertions(+), 2789 deletions(-) delete mode 100644 source4/torture/gentest_smb2.c (limited to 'source4') diff --git a/source4/torture/config.mk b/source4/torture/config.mk index 2857b99582..5a1746c215 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -262,23 +262,6 @@ gentest_OBJ_FILES = $(torturesrcdir)/gentest.o MANPAGES += $(torturesrcdir)/man/gentest.1 -################################# -# Start BINARY gentest_smb2 -[BINARY::gentest_smb2] -INSTALLDIR = BINDIR -PRIVATE_DEPENDENCIES = \ - LIBSAMBA-HOSTCONFIG \ - LIBSAMBA-UTIL \ - LIBPOPT \ - POPT_SAMBA \ - POPT_CREDENTIALS \ - LIBCLI_SMB \ - LIBCLI_RAW -# End BINARY gentest_smb2 -################################# - -gentest_smb2_OBJ_FILES = $(torturesrcdir)/gentest_smb2.o - ################################# # Start BINARY masktest [BINARY::masktest] diff --git a/source4/torture/gentest.c b/source4/torture/gentest.c index 068b6bdc2f..fd6bd5cc0a 100644 --- a/source4/torture/gentest.c +++ b/source4/torture/gentest.c @@ -1,7 +1,9 @@ /* Unix SMB/CIFS implementation. - generic testing tool - Copyright (C) Andrew Tridgell 2003 + + generic testing tool - version with both SMB and SMB2 support + + Copyright (C) Andrew Tridgell 2003-2008 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 @@ -25,12 +27,17 @@ #include "libcli/raw/request.h" #include "libcli/libcli.h" #include "libcli/raw/libcliraw.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" #include "librpc/gen_ndr/security.h" +#include "librpc/gen_ndr/ndr_security.h" #include "auth/credentials/credentials.h" #include "libcli/resolve/resolve.h" #include "auth/gensec/gensec.h" #include "param/param.h" #include "dynconfig/dynconfig.h" +#include "libcli/security/security.h" +#include "libcli/raw/raw_proto.h" #define NSERVERS 2 #define NINSTANCES 2 @@ -49,14 +56,20 @@ static struct gentest_options { const char *seeds_file; int use_preset_seeds; int fast_reconnect; + int mask_indexing; + int no_eas; + int no_acls; int skip_cleanup; + int valid; + int smb2; } options; /* mapping between open handles on the server and local handles */ static struct { bool active; uint_t instance; - uint_t server_fnum[NSERVERS]; + struct smb2_handle smb2_handle[NSERVERS]; /* SMB2 */ + uint16_t smb_handle[NSERVERS]; /* SMB */ const char *name; } *open_handles; static uint_t num_open_handles; @@ -64,7 +77,8 @@ static uint_t num_open_handles; /* state information for the servers. We open NINSTANCES connections to each server */ static struct { - struct smbcli_state *cli[NINSTANCES]; + struct smb2_tree *smb2_tree[NINSTANCES]; + struct smbcli_tree *smb_tree[NINSTANCES]; char *server_name; char *share_name; struct cli_credentials *credentials; @@ -80,7 +94,8 @@ static struct { /* oplock break info */ static struct { bool got_break; - uint16_t fnum; + struct smb2_handle smb2_handle; + uint16_t smb_handle; uint16_t handle; uint8_t level; bool do_close; @@ -100,14 +115,19 @@ static struct { NTSTATUS status; uint_t opnum; TALLOC_CTX *mem_ctx; + const char *mismatch; } current_op; +static struct smb2_handle bad_smb2_handle; #define BAD_HANDLE 0xFFFE -static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private); -static void idle_func(struct smbcli_transport *transport, void *private); +static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle, + uint8_t level, void *private_data); +static void idle_func_smb2(struct smb2_transport *transport, void *private); +static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private); +static void idle_func_smb(struct smbcli_transport *transport, void *private); /* check if a string should be ignored. This is used as the basis @@ -139,8 +159,15 @@ static bool connect_servers_fast(void) for (h=0;htree, - open_handles[h].server_fnum[i])))) { + NTSTATUS status; + if (options.smb2) { + status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance], + open_handles[h].smb2_handle[i]); + } else { + status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], + open_handles[h].smb_handle[i]); + } + if (NT_STATUS_IS_ERR(status)) { return false; } open_handles[h].active = false; @@ -161,7 +188,7 @@ static bool connect_servers(struct event_context *ev, { int i, j; - if (options.fast_reconnect && servers[0].cli[0]) { + if (options.fast_reconnect && servers[0].smb2_tree[0]) { if (connect_servers_fast()) { return true; } @@ -170,17 +197,21 @@ static bool connect_servers(struct event_context *ev, /* close any existing connections */ for (i=0;itransport, oplock_handler, NULL); - smbcli_transport_idle_handler(servers[i].cli[j]->transport, idle_func, 50000, NULL); + if (options.smb2) { + servers[i].smb2_tree[j]->session->transport->oplock.handler = oplock_handler_smb2; + servers[i].smb2_tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j); + smb2_transport_idle_handler(servers[i].smb2_tree[j]->session->transport, + idle_func_smb2, 50000, NULL); + } else { + smbcli_oplock_handler(servers[i].smb_tree[j]->session->transport, oplock_handler_smb, + (void *)(uintptr_t)((i<<8)|j)); + smbcli_transport_idle_handler(servers[i].smb_tree[j]->session->transport, idle_func_smb, + 50000, (void *)(uintptr_t)((i<<8)|j)); + } } } @@ -218,33 +269,98 @@ static bool connect_servers(struct event_context *ev, static uint_t time_skew(void) { uint_t ret; - ret = labs(servers[0].cli[0]->transport->negotiate.server_time - - servers[1].cli[0]->transport->negotiate.server_time); + if (options.smb2) { + ret = labs(servers[0].smb2_tree[0]->session->transport->negotiate.system_time - + servers[1].smb2_tree[0]->session->transport->negotiate.system_time); + } else { + ret = labs(servers[0].smb_tree[0]->session->transport->negotiate.server_time - + servers[1].smb_tree[0]->session->transport->negotiate.server_time); + } return ret + 300; } + +static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2) +{ + return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0; +} + /* - turn an fnum for an instance into a handle + turn a server handle into a local handle */ -static uint_t fnum_to_handle(int server, int instance, uint16_t fnum) +static uint_t fnum_to_handle_smb2(int server, int instance, struct smb2_handle server_handle) { uint_t i; for (i=0;itree, - open_handles[h].server_fnum[i])))) { + NTSTATUS status; + status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], + open_handles[h].smb_handle[i]); + if (NT_STATUS_IS_ERR(status)) { printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n", - smbcli_errstr(servers[i].cli[open_handles[h].instance]->tree)); + nt_errstr(status)); } } printf("Recovered handle %d\n", h); num_open_handles--; } for (i=0;itransport; - - tid = SVAL(req->in.hdr, HDR_TID); - - notify.nttrans.level = RAW_NOTIFY_NTTRANS; - status = smb_raw_changenotify_recv(req, current_op.mem_ctx, ¬ify); - if (NT_STATUS_IS_OK(status)) { - printf("notify tid=%d num_changes=%d action=%d name=%s\n", - tid, - notify.nttrans.out.num_changes, - notify.nttrans.out.changes[0].action, - notify.nttrans.out.changes[0].name.s); + struct smb_ea_list eas; + int i; + if (options.no_eas) { + ZERO_STRUCT(eas); + return eas; } - - for (i=0;itransport && - tid == servers[i].cli[j]->tree->tid) { - notifies[i][j].notify_count++; - notifies[i][j].status = status; - notifies[i][j].notify = notify; - } - } + eas.num_eas = gen_int_range(0, 3); + eas.eas = talloc_array(current_op.mem_ctx, struct ea_struct, eas.num_eas); + for (i=0;itransport && - tid == servers[i].cli[j]->tree->tid) { + if (transport == servers[i].smb_tree[j]->session->transport && + tid == servers[i].smb_tree[j]->tid) { oplocks[i][j].got_break = true; - oplocks[i][j].fnum = fnum; - oplocks[i][j].handle = fnum_to_handle(i, j, fnum); + oplocks[i][j].smb_handle = fnum; + oplocks[i][j].handle = fnum_to_handle_smb(i, j, fnum); oplocks[i][j].level = level; oplocks[i][j].do_close = do_close; - tree = servers[i].cli[j]->tree; + tree = servers[i].smb_tree[j]; } } } @@ -784,7 +1012,7 @@ static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uin return false; } - req->async.fn = oplock_handler_close_recv; + req->async.fn = oplock_handler_close_recv_smb; req->async.private = NULL; return true; @@ -796,83 +1024,212 @@ static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uin an operation on another connection blocking until that break is acked we check for operations on all transports in the idle function */ -static void idle_func(struct smbcli_transport *transport, void *private) +static void idle_func_smb(struct smbcli_transport *transport, void *private) { int i, j; for (i=0;itransport) { - smbcli_transport_process(servers[i].cli[j]->transport); + if (servers[i].smb_tree[j] && + transport != servers[i].smb_tree[j]->session->transport) { + smbcli_transport_process(servers[i].smb_tree[j]->session->transport); } } } } - -/* - compare NTSTATUS, using checking ignored patterns -*/ -static bool compare_status(NTSTATUS status1, NTSTATUS status2) +static void oplock_handler_close_recv_smb2(struct smb2_request *req) { - if (NT_STATUS_EQUAL(status1, status2)) return true; + NTSTATUS status; + struct smb2_close io; + status = smb2_close_recv(req, &io); + if (!NT_STATUS_IS_OK(status)) { + printf("close failed in oplock_handler\n"); + smb_panic("close failed in oplock_handler"); + } +} - /* one code being an error and the other OK is always an error */ - if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) return false; +static void oplock_handler_ack_callback_smb2(struct smb2_request *req) +{ + NTSTATUS status; + struct smb2_break br; - /* if we are ignoring one of the status codes then consider this a match */ - if (ignore_pattern(nt_errstr(status1)) || - ignore_pattern(nt_errstr(status2))) { - return true; + status = smb2_break_recv(req, &br); + if (!NT_STATUS_IS_OK(status)) { + printf("oplock break ack failed in oplock_handler\n"); + smb_panic("oplock break ack failed in oplock_handler"); } - return false; } - -/* - check for pending packets on all connections -*/ -static void check_pending(void) +static bool send_oplock_ack_smb2(struct smb2_tree *tree, struct smb2_handle handle, + uint8_t level) { - int i, j; + struct smb2_break br; + struct smb2_request *req; - msleep(20); + ZERO_STRUCT(br); + br.in.file.handle = handle; + br.in.oplock_level = level; + br.in.reserved = gen_reserved8(); + br.in.reserved2 = gen_reserved32(); - for (j=0;jtransport); - } - } + req = smb2_break_send(tree, &br); + if (req == NULL) return false; + req->async.fn = oplock_handler_ack_callback_smb2; + req->async.private_data = NULL; + return true; } /* - check that the same oplock breaks have been received by all instances + the oplock handler will either ack the break or close the file */ -static bool check_oplocks(const char *call) +static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle, + uint8_t level, void *private_data) { - int i, j; - int tries = 0; + struct smb2_close io; + unsigned i, j; + bool do_close; + struct smb2_tree *tree = NULL; + struct smb2_request *req; -again: - check_pending(); + srandom(current_op.seed); + do_close = gen_chance(50); - for (j=0;j> 8; + j = ((uintptr_t)private_data) & 0xFF; + + if (i >= NSERVERS || j >= NINSTANCES) { + printf("Bad private_data in oplock_handler\n"); + return false; + } + + oplocks[i][j].got_break = true; + oplocks[i][j].smb2_handle = *handle; + oplocks[i][j].handle = fnum_to_handle_smb2(i, j, *handle); + oplocks[i][j].level = level; + oplocks[i][j].do_close = do_close; + tree = talloc_get_type(servers[i].smb2_tree[j], struct smb2_tree); + + if (!tree) { + printf("Oplock break not for one of our trees!?\n"); + return false; + } + + if (!do_close) { + printf("oplock ack handle=%d\n", oplocks[i][j].handle); + return send_oplock_ack_smb2(tree, *handle, level); + } + + printf("oplock close fnum=%d\n", oplocks[i][j].handle); + + ZERO_STRUCT(io); + io.in.file.handle = *handle; + io.in.flags = 0; + req = smb2_close_send(tree, &io); + + if (req == NULL) { + printf("WARNING: close failed in oplock_handler_close\n"); + return false; + } + + req->async.fn = oplock_handler_close_recv_smb2; + req->async.private_data = NULL; + + return true; +} + + +/* + the idle function tries to cope with getting an oplock break on a connection, and + an operation on another connection blocking until that break is acked + we check for operations on all transports in the idle function +*/ +static void idle_func_smb2(struct smb2_transport *transport, void *private) +{ + int i, j; + for (i=0;isession->transport) { + // smb2_transport_process(servers[i].smb2_tree[j]->session->transport); + } + } + } + +} + + +/* + compare NTSTATUS, using checking ignored patterns +*/ +static bool compare_status(NTSTATUS status1, NTSTATUS status2) +{ + if (NT_STATUS_EQUAL(status1, status2)) return true; + + /* one code being an error and the other OK is always an error */ + if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) { + current_op.mismatch = nt_errstr(status1); + return false; + } + + /* if we are ignoring one of the status codes then consider this a match */ + if (ignore_pattern(nt_errstr(status1)) || + ignore_pattern(nt_errstr(status2))) { + return true; + } + current_op.mismatch = nt_errstr(status1); + return false; +} + +/* + check for pending packets on all connections +*/ +static void check_pending(void) +{ + int i, j; + + msleep(20); + + for (j=0;jsession->transport); + } + } +} + +/* + check that the same oplock breaks have been received by all instances +*/ +static bool check_oplocks(const char *call) +{ + int i, j; + int tries = 0; + + if (!options.use_oplocks || options.smb2) { + /* no smb2 oplocks in gentest yet */ + return true; + } + +again: + check_pending(); + + for (j=0;jtree; \ + struct treetype *tree = servers[i].treefield[instance]; \ status[i] = call; \ } \ current_op.status = status[0]; \ @@ -984,43 +1350,92 @@ again: if (!compare_status(status[i], status[0])) { \ printf("status different in %s - %s %s\n", #call, \ nt_errstr(status[0]), nt_errstr(status[i])); \ + current_op.mismatch = nt_errstr(status[0]); \ return false; \ } \ } \ - if (!check_oplocks(#call)) return false; \ - if (!check_notifies(#call)) return false; \ + if (!check_oplocks(#call)) return false; \ + if (!check_notifies(#call)) return false; \ if (!NT_STATUS_IS_OK(status[0])) { \ return true; \ } \ } while(0) -#define ADD_HANDLE(name, field) do { \ - uint16_t fnums[NSERVERS]; \ +#define GEN_CALL_SMB(call) GEN_CALL(call, smbcli_tree, smb_tree) +#define GEN_CALL_SMB2(call) GEN_CALL(call, smb2_tree, smb2_tree) + +#define ADD_HANDLE_SMB2(name, field) do { \ + struct smb2_handle handles[NSERVERS]; \ + int i; \ + for (i=0;idacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ + printf("Mismatch in %s\n", #field); \ + return false; \ + } \ +} while(0) + +#define CHECK_ATTRIB(field) do { \ + if (!options.mask_indexing) { \ + CHECK_EQUAL(field); \ + } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ (int)parm[0].field, (int)parm[1].field); \ return false; \ @@ -1029,10 +1444,12 @@ again: #define CHECK_WSTR_EQUAL(field) do { \ if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \ + current_op.mismatch = #field; \ printf("%s is NULL!\n", #field); \ return false; \ } \ if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - %s %s\n", #field, \ parm[0].field.s, parm[1].field.s); \ return false; \ @@ -1042,6 +1459,7 @@ again: #define CHECK_BLOB_EQUAL(field) do { \ if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s\n", #field); \ return false; \ } \ @@ -1051,6 +1469,7 @@ again: #define CHECK_TIMES_EQUAL(field) do { \ if (labs(parm[0].field - parm[1].field) > time_skew() && \ !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ (int)parm[0].field, (int)parm[1].field); \ return false; \ @@ -1061,6 +1480,7 @@ again: if (labs(nt_time_to_unix(parm[0].field) - \ nt_time_to_unix(parm[1].field)) > time_skew() && \ !ignore_pattern(#field)) { \ + current_op.mismatch = #field; \ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ (int)nt_time_to_unix(parm[0].field), \ (int)nt_time_to_unix(parm[1].field)); \ @@ -1068,89 +1488,305 @@ again: } \ } while(0) + /* - generate openx operations + compare returned fileinfo structures */ -static bool handler_openx(int instance) +static bool cmp_fileinfo(int instance, + union smb_fileinfo parm[NSERVERS], + NTSTATUS status[NSERVERS]) { - union smb_open parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - - parm[0].openx.level = RAW_OPEN_OPENX; - parm[0].openx.in.flags = gen_openx_flags(); - parm[0].openx.in.open_mode = gen_openx_mode(); - parm[0].openx.in.search_attrs = gen_attrib(); - parm[0].openx.in.file_attrs = gen_attrib(); - parm[0].openx.in.write_time = gen_timet(); - parm[0].openx.in.open_func = gen_openx_func(); - parm[0].openx.in.size = gen_io_count(); - parm[0].openx.in.timeout = gen_timeout(); - parm[0].openx.in.fname = gen_fname_open(instance); + int i; + enum smb_fileinfo_level level = parm[0].generic.level; - if (!options.use_oplocks) { - /* mask out oplocks */ - parm[0].openx.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK| - OPENX_FLAGS_REQUEST_BATCH_OPLOCK); + if (level == RAW_FILEINFO_ALL_INFORMATION && + options.smb2) { + level = RAW_FILEINFO_SMB2_ALL_INFORMATION; } - - GEN_COPY_PARM; - GEN_CALL(smb_raw_open(tree, current_op.mem_ctx, &parm[i])); - - CHECK_EQUAL(openx.out.attrib); - CHECK_EQUAL(openx.out.size); - CHECK_EQUAL(openx.out.access); - CHECK_EQUAL(openx.out.ftype); - CHECK_EQUAL(openx.out.devstate); - CHECK_EQUAL(openx.out.action); - CHECK_EQUAL(openx.out.access_mask); - CHECK_EQUAL(openx.out.unknown); - CHECK_TIMES_EQUAL(openx.out.write_time); - /* open creates a new file handle */ - ADD_HANDLE(parm[0].openx.in.fname, openx.out.file.fnum); + switch (level) { + case RAW_FILEINFO_GENERIC: + return false; - return true; -} + case RAW_FILEINFO_GETATTR: + CHECK_ATTRIB(getattr.out.attrib); + CHECK_EQUAL(getattr.out.size); + CHECK_TIMES_EQUAL(getattr.out.write_time); + break; + case RAW_FILEINFO_GETATTRE: + CHECK_TIMES_EQUAL(getattre.out.create_time); + CHECK_TIMES_EQUAL(getattre.out.access_time); + CHECK_TIMES_EQUAL(getattre.out.write_time); + CHECK_EQUAL(getattre.out.size); + CHECK_EQUAL(getattre.out.alloc_size); + CHECK_ATTRIB(getattre.out.attrib); + break; -/* - generate open operations -*/ -static bool handler_open(int instance) -{ - union smb_open parm[NSERVERS]; - NTSTATUS status[NSERVERS]; + case RAW_FILEINFO_STANDARD: + CHECK_TIMES_EQUAL(standard.out.create_time); + CHECK_TIMES_EQUAL(standard.out.access_time); + CHECK_TIMES_EQUAL(standard.out.write_time); + CHECK_EQUAL(standard.out.size); + CHECK_EQUAL(standard.out.alloc_size); + CHECK_ATTRIB(standard.out.attrib); + break; - parm[0].openold.level = RAW_OPEN_OPEN; - parm[0].openold.in.open_mode = gen_bits_mask2(0xF, 0xFFFF); - parm[0].openold.in.search_attrs = gen_attrib(); - parm[0].openold.in.fname = gen_fname_open(instance); + case RAW_FILEINFO_EA_SIZE: + CHECK_TIMES_EQUAL(ea_size.out.create_time); + CHECK_TIMES_EQUAL(ea_size.out.access_time); + CHECK_TIMES_EQUAL(ea_size.out.write_time); + CHECK_EQUAL(ea_size.out.size); + CHECK_EQUAL(ea_size.out.alloc_size); + CHECK_ATTRIB(ea_size.out.attrib); + CHECK_EQUAL(ea_size.out.ea_size); + break; - if (!options.use_oplocks) { - /* mask out oplocks */ - parm[0].openold.in.open_mode &= ~(OPENX_FLAGS_REQUEST_OPLOCK| - OPENX_FLAGS_REQUEST_BATCH_OPLOCK); - } - - GEN_COPY_PARM; - GEN_CALL(smb_raw_open(tree, current_op.mem_ctx, &parm[i])); + case RAW_FILEINFO_ALL_EAS: + CHECK_EQUAL(all_eas.out.num_eas); + for (i=0;igeneric.level = levels[i].level; -} - -/* - compare returned fileinfo structures -*/ -static bool cmp_fileinfo(int instance, - union smb_fileinfo parm[NSERVERS], - NTSTATUS status[NSERVERS]) -{ - int i; - - switch (parm[0].generic.level) { - case RAW_FILEINFO_GENERIC: - return false; - case RAW_FILEINFO_GETATTR: - CHECK_EQUAL(getattr.out.attrib); - CHECK_EQUAL(getattr.out.size); - CHECK_TIMES_EQUAL(getattr.out.write_time); + switch (info->generic.level) { + case RAW_SFILEINFO_SETATTR: + info->setattr.in.attrib = gen_attrib(); + info->setattr.in.write_time = gen_timet(); break; - - case RAW_FILEINFO_GETATTRE: - CHECK_TIMES_EQUAL(getattre.out.create_time); - CHECK_TIMES_EQUAL(getattre.out.access_time); - CHECK_TIMES_EQUAL(getattre.out.write_time); - CHECK_EQUAL(getattre.out.size); - CHECK_EQUAL(getattre.out.alloc_size); - CHECK_EQUAL(getattre.out.attrib); + case RAW_SFILEINFO_SETATTRE: + info->setattre.in.create_time = gen_timet(); + info->setattre.in.access_time = gen_timet(); + info->setattre.in.write_time = gen_timet(); break; - - case RAW_FILEINFO_STANDARD: - CHECK_TIMES_EQUAL(standard.out.create_time); - CHECK_TIMES_EQUAL(standard.out.access_time); - CHECK_TIMES_EQUAL(standard.out.write_time); - CHECK_EQUAL(standard.out.size); - CHECK_EQUAL(standard.out.alloc_size); - CHECK_EQUAL(standard.out.attrib); + case RAW_SFILEINFO_STANDARD: + info->standard.in.create_time = gen_timet(); + info->standard.in.access_time = gen_timet(); + info->standard.in.write_time = gen_timet(); break; - - case RAW_FILEINFO_EA_SIZE: - CHECK_TIMES_EQUAL(ea_size.out.create_time); - CHECK_TIMES_EQUAL(ea_size.out.access_time); - CHECK_TIMES_EQUAL(ea_size.out.write_time); - CHECK_EQUAL(ea_size.out.size); - CHECK_EQUAL(ea_size.out.alloc_size); - CHECK_EQUAL(ea_size.out.attrib); - CHECK_EQUAL(ea_size.out.ea_size); + case RAW_SFILEINFO_EA_SET: { + static struct ea_struct ea; + info->ea_set.in.num_eas = 1; + info->ea_set.in.eas = &ea; + info->ea_set.in.eas[0] = gen_ea_struct(); + } break; - - case RAW_FILEINFO_ALL_EAS: - CHECK_EQUAL(all_eas.out.num_eas); - for (i=0;ibasic_info.in.create_time = gen_nttime(); + info->basic_info.in.access_time = gen_nttime(); + info->basic_info.in.write_time = gen_nttime(); + info->basic_info.in.change_time = gen_nttime(); + info->basic_info.in.attrib = gen_attrib(); break; - - case RAW_FILEINFO_IS_NAME_VALID: + case RAW_SFILEINFO_DISPOSITION_INFO: + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + info->disposition_info.in.delete_on_close = gen_bool(); break; - - case RAW_FILEINFO_BASIC_INFO: - case RAW_FILEINFO_BASIC_INFORMATION: - CHECK_NTTIMES_EQUAL(basic_info.out.create_time); - CHECK_NTTIMES_EQUAL(basic_info.out.access_time); - CHECK_NTTIMES_EQUAL(basic_info.out.write_time); - CHECK_NTTIMES_EQUAL(basic_info.out.change_time); - CHECK_EQUAL(basic_info.out.attrib); + case RAW_SFILEINFO_ALLOCATION_INFO: + case RAW_SFILEINFO_ALLOCATION_INFORMATION: + info->allocation_info.in.alloc_size = gen_alloc_size(); + break; + case RAW_SFILEINFO_END_OF_FILE_INFO: + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + info->end_of_file_info.in.size = gen_offset(); + break; + case RAW_SFILEINFO_RENAME_INFORMATION: + case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: + info->rename_information.in.overwrite = gen_bool(); + info->rename_information.in.root_fid = gen_root_fid(instance); + info->rename_information.in.new_name = gen_fname_open(instance); + break; + case RAW_SFILEINFO_POSITION_INFORMATION: + info->position_information.in.position = gen_offset(); + break; + case RAW_SFILEINFO_MODE_INFORMATION: + info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); + break; + case RAW_SFILEINFO_GENERIC: + case RAW_SFILEINFO_SEC_DESC: + case RAW_SFILEINFO_UNIX_BASIC: + case RAW_SFILEINFO_UNIX_LINK: + case RAW_SFILEINFO_UNIX_HLINK: + case RAW_SFILEINFO_1023: + case RAW_SFILEINFO_1025: + case RAW_SFILEINFO_1029: + case RAW_SFILEINFO_1032: + case RAW_SFILEINFO_1039: + case RAW_SFILEINFO_1040: + case RAW_SFILEINFO_UNIX_INFO2: + /* Untested */ break; + } +} +#endif - case RAW_FILEINFO_STANDARD_INFO: - case RAW_FILEINFO_STANDARD_INFORMATION: - CHECK_EQUAL(standard_info.out.alloc_size); - CHECK_EQUAL(standard_info.out.size); - CHECK_EQUAL(standard_info.out.nlink); - CHECK_EQUAL(standard_info.out.delete_pending); - CHECK_EQUAL(standard_info.out.directory); +/* + generate a fileinfo query structure +*/ +static void gen_setfileinfo(int instance, union smb_setfileinfo *info) +{ + int i; + #undef LVL + #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v} + struct levels { + enum smb_setfileinfo_level level; + const char *name; + }; + struct levels smb_levels[] = { + LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), + LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), + LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION), + LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), + LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION), + LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), + LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040), + }; + struct levels smb2_levels[] = { + LVL(BASIC_INFORMATION), + LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), + LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION), + LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), + LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040) + }; + struct levels *levels = options.smb2?smb2_levels:smb_levels; + uint32_t num_levels = options.smb2?ARRAY_SIZE(smb2_levels):ARRAY_SIZE(smb_levels); + + do { + i = gen_int_range(0, num_levels-1); + } while (ignore_pattern(levels[i].name)); + + info->generic.level = levels[i].level; + + switch (info->generic.level) { + case RAW_SFILEINFO_SETATTR: + info->setattr.in.attrib = gen_attrib(); + info->setattr.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_SETATTRE: + info->setattre.in.create_time = gen_timet(); + info->setattre.in.access_time = gen_timet(); + info->setattre.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_STANDARD: + info->standard.in.create_time = gen_timet(); + info->standard.in.access_time = gen_timet(); + info->standard.in.write_time = gen_timet(); + break; + case RAW_SFILEINFO_EA_SET: { + static struct ea_struct ea; + info->ea_set.in.num_eas = 1; + info->ea_set.in.eas = &ea; + info->ea_set.in.eas[0] = gen_ea_struct(); + break; + } + case RAW_SFILEINFO_BASIC_INFO: + case RAW_SFILEINFO_BASIC_INFORMATION: + info->basic_info.in.create_time = gen_nttime(); + info->basic_info.in.access_time = gen_nttime(); + info->basic_info.in.write_time = gen_nttime(); + info->basic_info.in.change_time = gen_nttime(); + info->basic_info.in.attrib = gen_attrib(); + break; + case RAW_SFILEINFO_DISPOSITION_INFO: + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + info->disposition_info.in.delete_on_close = gen_bool(); + break; + case RAW_SFILEINFO_ALLOCATION_INFO: + case RAW_SFILEINFO_ALLOCATION_INFORMATION: + info->allocation_info.in.alloc_size = gen_alloc_size(); + break; + case RAW_SFILEINFO_END_OF_FILE_INFO: + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + info->end_of_file_info.in.size = gen_offset(); + break; + case RAW_SFILEINFO_RENAME_INFORMATION: + case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: + info->rename_information.in.overwrite = gen_bool(); + info->rename_information.in.root_fid = gen_root_fid(instance); + info->rename_information.in.new_name = gen_fname_open(instance); + break; + case RAW_SFILEINFO_POSITION_INFORMATION: + info->position_information.in.position = gen_offset(); + break; + case RAW_SFILEINFO_MODE_INFORMATION: + info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); break; - case RAW_FILEINFO_EA_INFO: - case RAW_FILEINFO_EA_INFORMATION: - CHECK_EQUAL(ea_info.out.ea_size); + case RAW_SFILEINFO_GENERIC: + case RAW_SFILEINFO_SEC_DESC: + case RAW_SFILEINFO_1023: + case RAW_SFILEINFO_1025: + case RAW_SFILEINFO_1029: + case RAW_SFILEINFO_1032: + case RAW_SFILEINFO_1039: + case RAW_SFILEINFO_1040: + case RAW_SFILEINFO_UNIX_BASIC: + case RAW_SFILEINFO_UNIX_INFO2: + case RAW_SFILEINFO_UNIX_LINK: + case RAW_SFILEINFO_UNIX_HLINK: + /* Untested */ break; + } +} + + + +/* + generate a fileinfo query structure +*/ +static void gen_fileinfo_smb(int instance, union smb_fileinfo *info) +{ + int i; + #undef LVL + #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v} + struct { + enum smb_fileinfo_level level; + const char *name; + } levels[] = { + LVL(GETATTR), LVL(GETATTRE), LVL(STANDARD), + LVL(EA_SIZE), LVL(ALL_EAS), LVL(IS_NAME_VALID), + LVL(BASIC_INFO), LVL(STANDARD_INFO), LVL(EA_INFO), + LVL(NAME_INFO), LVL(ALL_INFO), LVL(ALT_NAME_INFO), + LVL(STREAM_INFO), LVL(COMPRESSION_INFO), LVL(BASIC_INFORMATION), + LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION), + LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION), + LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(ALL_INFORMATION), + LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION), + LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION) + }; + do { + i = gen_int_range(0, ARRAY_SIZE(levels)-1); + } while (ignore_pattern(levels[i].name)); + + info->generic.level = levels[i].level; +} + +/* + generate qpathinfo operations +*/ +static bool handler_smb_qpathinfo(int instance) +{ + union smb_fileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].generic.in.file.path = gen_fname_open(instance); + + gen_fileinfo_smb(instance, &parm[0]); + + GEN_COPY_PARM; + GEN_CALL_SMB(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i])); + + return cmp_fileinfo(instance, parm, status); +} + +/* + generate qfileinfo operations +*/ +static bool handler_smb_qfileinfo(int instance) +{ + union smb_fileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].generic.in.file.fnum = gen_fnum(instance); + + gen_fileinfo_smb(instance, &parm[0]); + + GEN_COPY_PARM; + GEN_SET_FNUM_SMB(generic.in.file.fnum); + GEN_CALL_SMB(smb_raw_fileinfo(tree, current_op.mem_ctx, &parm[i])); + + return cmp_fileinfo(instance, parm, status); +} + + +/* + generate setpathinfo operations +*/ +static bool handler_smb_spathinfo(int instance) +{ + union smb_setfileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].generic.in.file.path = gen_fname_open(instance); + + gen_setfileinfo(instance, &parm[0]); + + GEN_COPY_PARM; + + /* a special case for the fid in a RENAME */ + if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION && + parm[0].rename_information.in.root_fid != 0) { + GEN_SET_FNUM_SMB(rename_information.in.root_fid); + } + + GEN_CALL_SMB(smb_raw_setpathinfo(tree, &parm[i])); + + return true; +} + + +/* + generate setfileinfo operations +*/ +static bool handler_smb_sfileinfo(int instance) +{ + union smb_setfileinfo parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + parm[0].generic.in.file.fnum = gen_fnum(instance); + + gen_setfileinfo(instance, &parm[0]); + + GEN_COPY_PARM; + GEN_SET_FNUM_SMB(generic.in.file.fnum); + GEN_CALL_SMB(smb_raw_setfileinfo(tree, &parm[i])); + + return true; +} + + +/* + this is called when a change notify reply comes in +*/ +static void async_notify_smb(struct smbcli_request *req) +{ + union smb_notify notify; + NTSTATUS status; + int i, j; + uint16_t tid; + struct smbcli_transport *transport = req->transport; + + tid = SVAL(req->in.hdr, HDR_TID); + + notify.nttrans.level = RAW_NOTIFY_NTTRANS; + status = smb_raw_changenotify_recv(req, current_op.mem_ctx, ¬ify); + if (NT_STATUS_IS_OK(status) && notify.nttrans.out.num_changes > 0) { + printf("notify tid=%d num_changes=%d action=%d name=%s\n", + tid, + notify.nttrans.out.num_changes, + notify.nttrans.out.changes[0].action, + notify.nttrans.out.changes[0].name.s); + } + + for (i=0;isession->transport && + tid == servers[i].smb_tree[j]->tid) { + notifies[i][j].notify_count++; + notifies[i][j].status = status; + notifies[i][j].notify = notify; + } + } + } +} + +/* + generate change notify operations +*/ +static bool handler_smb_notify(int instance) +{ + union smb_notify parm[NSERVERS]; + int n; + + ZERO_STRUCT(parm[0]); + parm[0].nttrans.level = RAW_NOTIFY_NTTRANS; + parm[0].nttrans.in.buffer_size = gen_io_count(); + parm[0].nttrans.in.completion_filter = gen_bits_mask(0xFF); + parm[0].nttrans.in.file.fnum = gen_fnum(instance); + parm[0].nttrans.in.recursive = gen_bool(); + + GEN_COPY_PARM; + GEN_SET_FNUM_SMB(nttrans.in.file.fnum); + + for (n=0;nasync.fn = async_notify_smb; + } + + return true; +} + + +/* + generate ntcreatex operations +*/ +static bool handler_smb2_create(int instance) +{ + struct smb2_create parm[NSERVERS]; + NTSTATUS status[NSERVERS]; + + ZERO_STRUCT(parm[0]); + parm[0].in.security_flags = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF); + parm[0].in.oplock_level = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF); + parm[0].in.impersonation_level = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF); + parm[0].in.create_flags = gen_reserved64(); + parm[0].in.reserved = gen_reserved64(); + parm[0].in.desired_access = gen_access_mask(); + parm[0].in.file_attributes = gen_attrib(); + parm[0].in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF); + parm[0].in.create_disposition = gen_open_disp(); + parm[0].in.create_options = gen_create_options(); + parm[0].in.fname = gen_fname_open(instance); + parm[0].in.eas = gen_ea_list(); + parm[0].in.alloc_size = gen_alloc_size(); + parm[0].in.durable_open = gen_bool(); + parm[0].in.query_maximal_access = gen_bool(); + parm[0].in.timewarp = gen_timewarp(); + parm[0].in.query_on_disk_id = gen_bool(); + parm[0].in.sec_desc = gen_sec_desc(); + + if (!options.use_oplocks) { + /* mask out oplocks */ + parm[0].in.oplock_level = 0; + } + + if (options.valid) { + parm[0].in.security_flags &= 3; + parm[0].in.oplock_level &= 9; + parm[0].in.impersonation_level &= 3; + } + + GEN_COPY_PARM; + GEN_CALL_SMB2(smb2_create(tree, current_op.mem_ctx, &parm[i])); + + CHECK_EQUAL(out.oplock_level); + CHECK_EQUAL(out.reserved); + CHECK_EQUAL(out.create_action); + CHECK_NTTIMES_EQUAL(out.create_time); + CHECK_NTTIMES_EQUAL(out.access_time); + CHECK_NTTIMES_EQUAL(out.write_time); + CHECK_NTTIMES_EQUAL(out.change_time); + CHECK_EQUAL(out.alloc_size); + CHECK_EQUAL(out.size); + CHECK_ATTRIB(out.file_attr); + CHECK_EQUAL(out.reserved2); + CHECK_EQUAL(out.maximal_access); + + /* ntcreatex creates a new file handle */ + ADD_HANDLE_SMB2(parm[0].in.fname, out.file.handle); + + return true; +} + +/* + generate close operations +*/ +static bool handler_smb2_close(int instance) +{ + struct smb2_close parm[NSERVERS]; + NTSTATUS status[NSERVERS]; - case RAW_FILEINFO_NAME_INFO: - case RAW_FILEINFO_NAME_INFORMATION: - CHECK_WSTR_EQUAL(name_info.out.fname); - break; + ZERO_STRUCT(parm[0]); + parm[0].in.file.handle.data[0] = gen_fnum_close(instance); + parm[0].in.flags = gen_bits_mask2(0x1, 0xFFFF); - case RAW_FILEINFO_ALL_INFO: - case RAW_FILEINFO_ALL_INFORMATION: - CHECK_NTTIMES_EQUAL(all_info.out.create_time); - CHECK_NTTIMES_EQUAL(all_info.out.access_time); - CHECK_NTTIMES_EQUAL(all_info.out.write_time); - CHECK_NTTIMES_EQUAL(all_info.out.change_time); - CHECK_EQUAL(all_info.out.attrib); - CHECK_EQUAL(all_info.out.alloc_size); - CHECK_EQUAL(all_info.out.size); - CHECK_EQUAL(all_info.out.nlink); - CHECK_EQUAL(all_info.out.delete_pending); - CHECK_EQUAL(all_info.out.directory); - CHECK_EQUAL(all_info.out.ea_size); - CHECK_WSTR_EQUAL(all_info.out.fname); - break; + GEN_COPY_PARM; + GEN_SET_FNUM_SMB2(in.file.handle); + GEN_CALL_SMB2(smb2_close(tree, &parm[i])); - case RAW_FILEINFO_ALT_NAME_INFO: - case RAW_FILEINFO_ALT_NAME_INFORMATION: - CHECK_WSTR_EQUAL(alt_name_info.out.fname); - break; + CHECK_EQUAL(out.flags); + CHECK_EQUAL(out._pad); + CHECK_NTTIMES_EQUAL(out.create_time); + CHECK_NTTIMES_EQUAL(out.access_time); + CHECK_NTTIMES_EQUAL(out.write_time); + CHECK_NTTIMES_EQUAL(out.change_time); + CHECK_EQUAL(out.alloc_size); + CHECK_EQUAL(out.size); + CHECK_ATTRIB(out.file_attr); - case RAW_FILEINFO_STREAM_INFO: - case RAW_FILEINFO_STREAM_INFORMATION: - CHECK_EQUAL(stream_info.out.num_streams); - for (i=0;isession->transport)); + + return true; +} + + /* generate a fileinfo query structure */ -static void gen_setfileinfo(int instance, union smb_setfileinfo *info) +static void gen_fileinfo_smb2(int instance, union smb_fileinfo *info) { int i; - #undef LVL - #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v} + #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v} struct { - enum smb_setfileinfo_level level; + enum smb_fileinfo_level level; const char *name; } levels[] = { -#if 0 - /* disabled until win2003 can handle them ... */ - LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), - LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), -#endif - LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION), - LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), - LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION), - LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), - LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040) + LVL(BASIC_INFORMATION), + LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION), + LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION), + LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION), + LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION), + LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION), + LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC), }; do { i = gen_int_range(0, ARRAY_SIZE(levels)-1); } while (ignore_pattern(levels[i].name)); info->generic.level = levels[i].level; - - switch (info->generic.level) { - case RAW_SFILEINFO_SETATTR: - info->setattr.in.attrib = gen_attrib(); - info->setattr.in.write_time = gen_timet(); - break; - case RAW_SFILEINFO_SETATTRE: - info->setattre.in.create_time = gen_timet(); - info->setattre.in.access_time = gen_timet(); - info->setattre.in.write_time = gen_timet(); - break; - case RAW_SFILEINFO_STANDARD: - info->standard.in.create_time = gen_timet(); - info->standard.in.access_time = gen_timet(); - info->standard.in.write_time = gen_timet(); - break; - case RAW_SFILEINFO_EA_SET: { - static struct ea_struct ea; - info->ea_set.in.num_eas = 1; - info->ea_set.in.eas = &ea; - info->ea_set.in.eas[0] = gen_ea_struct(); - } - break; - case RAW_SFILEINFO_BASIC_INFO: - case RAW_SFILEINFO_BASIC_INFORMATION: - info->basic_info.in.create_time = gen_nttime(); - info->basic_info.in.access_time = gen_nttime(); - info->basic_info.in.write_time = gen_nttime(); - info->basic_info.in.change_time = gen_nttime(); - info->basic_info.in.attrib = gen_attrib(); - break; - case RAW_SFILEINFO_DISPOSITION_INFO: - case RAW_SFILEINFO_DISPOSITION_INFORMATION: - info->disposition_info.in.delete_on_close = gen_bool(); - break; - case RAW_SFILEINFO_ALLOCATION_INFO: - case RAW_SFILEINFO_ALLOCATION_INFORMATION: - info->allocation_info.in.alloc_size = gen_alloc_size(); - break; - case RAW_SFILEINFO_END_OF_FILE_INFO: - case RAW_SFILEINFO_END_OF_FILE_INFORMATION: - info->end_of_file_info.in.size = gen_offset(); - break; - case RAW_SFILEINFO_RENAME_INFORMATION: - case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: - info->rename_information.in.overwrite = gen_bool(); - info->rename_information.in.root_fid = gen_root_fid(instance); - info->rename_information.in.new_name = gen_fname_open(instance); - break; - case RAW_SFILEINFO_POSITION_INFORMATION: - info->position_information.in.position = gen_offset(); - break; - case RAW_SFILEINFO_MODE_INFORMATION: - info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); - break; - case RAW_SFILEINFO_GENERIC: - case RAW_SFILEINFO_SEC_DESC: - case RAW_SFILEINFO_UNIX_BASIC: - case RAW_SFILEINFO_UNIX_LINK: - case RAW_SFILEINFO_UNIX_HLINK: - case RAW_SFILEINFO_1023: - case RAW_SFILEINFO_1025: - case RAW_SFILEINFO_1029: - case RAW_SFILEINFO_1032: - case RAW_SFILEINFO_1039: - case RAW_SFILEINFO_1040: - case RAW_SFILEINFO_UNIX_INFO2: - /* Untested */ - break; - } } /* - generate setpathinfo operations + generate qfileinfo operations */ -static bool handler_spathinfo(int instance) +static bool handler_smb2_qfileinfo(int instance) { - union smb_setfileinfo parm[NSERVERS]; + union smb_fileinfo parm[NSERVERS]; NTSTATUS status[NSERVERS]; - parm[0].generic.in.file.path = gen_fname_open(instance); + parm[0].generic.in.file.handle.data[0] = gen_fnum(instance); - gen_setfileinfo(instance, &parm[0]); + gen_fileinfo_smb2(instance, &parm[0]); GEN_COPY_PARM; + GEN_SET_FNUM_SMB2(generic.in.file.handle); + GEN_CALL_SMB2(smb2_getinfo_file(tree, current_op.mem_ctx, &parm[i])); - /* a special case for the fid in a RENAME */ - if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION && - parm[0].rename_information.in.root_fid != 0) { - GEN_SET_FNUM(rename_information.in.root_fid); - } - - GEN_CALL(smb_raw_setpathinfo(tree, &parm[i])); - - return true; + return cmp_fileinfo(instance, parm, status); } /* generate setfileinfo operations */ -static bool handler_sfileinfo(int instance) +static bool handler_smb2_sfileinfo(int instance) { union smb_setfileinfo parm[NSERVERS]; NTSTATUS status[NSERVERS]; @@ -1826,36 +2744,8 @@ static bool handler_sfileinfo(int instance) gen_setfileinfo(instance, &parm[0]); GEN_COPY_PARM; - GEN_SET_FNUM(generic.in.file.fnum); - GEN_CALL(smb_raw_setfileinfo(tree, &parm[i])); - - return true; -} - - -/* - generate change notify operations -*/ -static bool handler_notify(int instance) -{ - union smb_notify parm[NSERVERS]; - int n; - - ZERO_STRUCT(parm[0]); - parm[0].nttrans.level = RAW_NOTIFY_NTTRANS; - parm[0].nttrans.in.buffer_size = gen_io_count(); - parm[0].nttrans.in.completion_filter = gen_bits_mask(0xFF); - parm[0].nttrans.in.file.fnum = gen_fnum(instance); - parm[0].nttrans.in.recursive = gen_bool(); - - GEN_COPY_PARM; - GEN_SET_FNUM(nttrans.in.file.fnum); - - for (n=0;ntree, &parm[n]); - req->async.fn = async_notify; - } + GEN_SET_FNUM_SMB2(generic.in.file.handle); + GEN_CALL_SMB2(smb2_setinfo_file(tree, &parm[i])); return true; } @@ -1866,20 +2756,30 @@ static bool handler_notify(int instance) static void wipe_files(void) { int i; + NTSTATUS status; if (options.skip_cleanup) { return; } for (i=0;itree, "\\gentest"); + int n; + if (options.smb2) { + n = smb2_deltree(servers[i].smb2_tree[0], "gentest"); + } else { + n = smbcli_deltree(servers[i].smb_tree[0], "gentest"); + } if (n == -1) { printf("Failed to wipe tree on server %d\n", i); exit(1); } - if (NT_STATUS_IS_ERR(smbcli_mkdir(servers[i].cli[0]->tree, "\\gentest"))) { - printf("Failed to create \\gentest - %s\n", - smbcli_errstr(servers[i].cli[0]->tree)); + if (options.smb2) { + status = smb2_util_mkdir(servers[i].smb2_tree[0], "gentest"); + } else { + status = smbcli_mkdir(servers[i].smb_tree[0], "gentest"); + } + if (NT_STATUS_IS_ERR(status)) { + printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status)); exit(1); } if (n > 0) { @@ -1917,27 +2817,39 @@ static void dump_seeds(void) static struct { const char *name; bool (*handler)(int instance); + bool smb2; int count, success_count; } gen_ops[] = { - {"OPEN", handler_open}, - {"OPENX", handler_openx}, - {"NTCREATEX", handler_ntcreatex}, - {"CLOSE", handler_close}, - {"UNLINK", handler_unlink}, - {"MKDIR", handler_mkdir}, - {"RMDIR", handler_rmdir}, - {"RENAME", handler_rename}, - {"NTRENAME", handler_ntrename}, - {"READX", handler_readx}, - {"WRITEX", handler_writex}, - {"CHKPATH", handler_chkpath}, - {"LOCKINGX", handler_lockingx}, - {"QPATHINFO", handler_qpathinfo}, - {"QFILEINFO", handler_qfileinfo}, - {"SPATHINFO", handler_spathinfo}, - {"SFILEINFO", handler_sfileinfo}, - {"NOTIFY", handler_notify}, - {"SEEK", handler_seek}, + {"CREATE", handler_smb2_create, true}, + {"CLOSE", handler_smb2_close, true}, + {"READ", handler_smb2_read, true}, + {"WRITE", handler_smb2_write, true}, + {"LOCK", handler_smb2_lock, true}, + {"FLUSH", handler_smb2_flush, true}, + {"ECHO", handler_smb2_echo, true}, + {"QFILEINFO", handler_smb2_qfileinfo, true}, + {"SFILEINFO", handler_smb2_sfileinfo, true}, + + {"OPEN", handler_smb_open, false}, + {"OPENX", handler_smb_openx, false}, + {"NTCREATEX", handler_smb_ntcreatex, false}, + {"CLOSE", handler_smb_close, false}, + {"UNLINK", handler_smb_unlink, false}, + {"MKDIR", handler_smb_mkdir, false}, + {"RMDIR", handler_smb_rmdir, false}, + {"RENAME", handler_smb_rename, false}, + {"NTRENAME", handler_smb_ntrename, false}, + {"READX", handler_smb_readx, false}, + {"WRITEX", handler_smb_writex, false}, + {"CHKPATH", handler_smb_chkpath, false}, + {"SEEK", handler_smb_seek, false}, + {"LOCKINGX", handler_smb_lockingx, false}, + {"QPATHINFO", handler_smb_qpathinfo, false}, + {"QFILEINFO", handler_smb_qfileinfo, false}, + {"SPATHINFO", handler_smb_spathinfo, false}, + {"SFILEINFO", handler_smb_sfileinfo, false}, + {"NOTIFY", handler_smb_notify, false}, + {"SEEK", handler_smb_seek, false}, }; @@ -1981,7 +2893,8 @@ static int run_test(struct event_context *ev, struct loadparm_context *lp_ctx) /* generate a non-ignored operation */ do { which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1); - } while (ignore_pattern(gen_ops[which_op].name)); + } while (ignore_pattern(gen_ops[which_op].name) || + gen_ops[which_op].smb2 != options.smb2); DEBUG(3,("Generating op %s on instance %d\n", gen_ops[which_op].name, instance)); @@ -2030,6 +2943,7 @@ static void backtrack_analyze(struct event_context *ev, struct loadparm_context *lp_ctx) { int chunk, ret; + const char *mismatch = current_op.mismatch; chunk = options.numops / 2; @@ -2056,6 +2970,10 @@ static void backtrack_analyze(struct event_context *ev, if (ret == options.numops) { /* this chunk is needed */ base += chunk; + } else if (mismatch != current_op.mismatch && + strcmp(mismatch, current_op.mismatch)) { + base += chunk; + printf("Different error in backtracking\n"); } else if (ret < base) { printf("damn - inconsistent errors! found early error\n"); options.numops = ret+1; @@ -2189,6 +3107,7 @@ static bool split_unc_name(const char *unc, char **server, char **share) enum {OPT_UNCLIST=1000}; struct poptOption long_options[] = { POPT_AUTOHELP + {"smb2", 0, POPT_ARG_NONE, &options.smb2, 0, "use SMB2 protocol", NULL}, {"seed", 0, POPT_ARG_INT, &options.seed, 0, "Seed to use for randomizer", NULL}, {"num-ops", 0, POPT_ARG_INT, &options.numops, 0, "num ops", NULL}, {"oplocks", 0, POPT_ARG_NONE, &options.use_oplocks,0, "use oplocks", NULL}, @@ -2202,7 +3121,11 @@ static bool split_unc_name(const char *unc, char **server, char **share) {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL}, {"seedsfile", 0, POPT_ARG_STRING, &options.seeds_file, 0, "seed file", NULL}, { "user", 'U', POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" }, + {"maskindexing", 0, POPT_ARG_NONE, &options.mask_indexing, 0, "mask out the indexed file attrib", NULL}, + {"noeas", 0, POPT_ARG_NONE, &options.no_eas, 0, "don't use extended attributes", NULL}, + {"noacls", 0, POPT_ARG_NONE, &options.no_acls, 0, "don't use ACLs", NULL}, {"skip-cleanup", 0, POPT_ARG_NONE, &options.skip_cleanup, 0, "don't delete files at start", NULL}, + {"valid", 0, POPT_ARG_NONE, &options.valid, 0, "generate only valid fields", NULL}, POPT_COMMON_SAMBA POPT_COMMON_CONNECTION POPT_COMMON_CREDENTIALS @@ -2210,6 +3133,8 @@ static bool split_unc_name(const char *unc, char **server, char **share) { NULL } }; + memset(&bad_smb2_handle, 0xFF, sizeof(bad_smb2_handle)); + setlinebuf(stdout); options.seed = time(NULL); options.numops = 1000; diff --git a/source4/torture/gentest_smb2.c b/source4/torture/gentest_smb2.c deleted file mode 100644 index 5a209180e3..0000000000 --- a/source4/torture/gentest_smb2.c +++ /dev/null @@ -1,2122 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - generic testing tool - version with SMB2 support - - Copyright (C) Andrew Tridgell 2003-2008 - - 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 3 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, see . -*/ - -#include "includes.h" -#include "lib/cmdline/popt_common.h" -#include "lib/events/events.h" -#include "system/time.h" -#include "system/filesys.h" -#include "libcli/raw/request.h" -#include "libcli/libcli.h" -#include "libcli/raw/libcliraw.h" -#include "libcli/smb2/smb2.h" -#include "libcli/smb2/smb2_calls.h" -#include "librpc/gen_ndr/security.h" -#include "librpc/gen_ndr/ndr_security.h" -#include "auth/credentials/credentials.h" -#include "libcli/resolve/resolve.h" -#include "auth/gensec/gensec.h" -#include "param/param.h" -#include "dynconfig/dynconfig.h" -#include "libcli/security/security.h" - -#define NSERVERS 2 -#define NINSTANCES 2 - -/* global options */ -static struct gentest_options { - int showall; - int analyze; - int analyze_always; - int analyze_continuous; - uint_t max_open_handles; - uint_t seed; - uint_t numops; - int use_oplocks; - char **ignore_patterns; - const char *seeds_file; - int use_preset_seeds; - int fast_reconnect; - int mask_indexing; - int no_eas; - int no_acls; - int skip_cleanup; - int valid; -} options; - -/* mapping between open handles on the server and local handles */ -static struct { - bool active; - uint_t instance; - struct smb2_handle server_handle[NSERVERS]; - const char *name; -} *open_handles; -static uint_t num_open_handles; - -/* state information for the servers. We open NINSTANCES connections to - each server */ -static struct { - struct smb2_tree *tree[NINSTANCES]; - char *server_name; - char *share_name; - struct cli_credentials *credentials; -} servers[NSERVERS]; - -/* the seeds and flags for each operation */ -static struct { - uint_t seed; - bool disabled; -} *op_parms; - - -/* oplock break info */ -static struct { - bool got_break; - struct smb2_handle server_handle; - uint16_t handle; - uint8_t level; - bool do_close; -} oplocks[NSERVERS][NINSTANCES]; - -/* change notify reply info */ -static struct { - int notify_count; - NTSTATUS status; - union smb_notify notify; -} notifies[NSERVERS][NINSTANCES]; - -/* info relevant to the current operation */ -static struct { - const char *name; - uint_t seed; - NTSTATUS status; - uint_t opnum; - TALLOC_CTX *mem_ctx; - const char *mismatch; -} current_op; - -static struct smb2_handle bad_smb2_handle; - - -#define BAD_HANDLE 0xFFFE - -static bool oplock_handler(struct smb2_transport *transport, const struct smb2_handle *handle, - uint8_t level, void *private_data); -static void idle_func(struct smb2_transport *transport, void *private); - -/* - check if a string should be ignored. This is used as the basis - for all error ignore settings -*/ -static bool ignore_pattern(const char *str) -{ - int i; - if (!options.ignore_patterns) return false; - - for (i=0;options.ignore_patterns[i];i++) { - if (strcmp(options.ignore_patterns[i], str) == 0 || - gen_fnmatch(options.ignore_patterns[i], str) == 0) { - DEBUG(2,("Ignoring '%s'\n", str)); - return true; - } - } - return false; -} - -/***************************************************** -connect to the servers -*******************************************************/ -static bool connect_servers_fast(void) -{ - int h, i; - - /* close all open files */ - for (h=0;husername, j); - - cli_credentials_set_workstation(servers[i].credentials, - "gentest", CRED_SPECIFIED); - - status = smb2_connect(NULL, servers[i].server_name, - servers[i].share_name, - lp_resolve_context(lp_ctx), - servers[i].credentials, - &servers[i].tree[j], - ev); - if (!NT_STATUS_IS_OK(status)) { - printf("Failed to connect to \\\\%s\\%s - %s\n", - servers[i].server_name, servers[i].share_name, - nt_errstr(status)); - return false; - } - - servers[i].tree[j]->session->transport->oplock.handler = oplock_handler; - servers[i].tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j); - smb2_transport_idle_handler(servers[i].tree[j]->session->transport, idle_func, 50000, NULL); - } - } - - return true; -} - -/* - work out the time skew between the servers - be conservative -*/ -static uint_t time_skew(void) -{ - uint_t ret; - ret = labs(servers[0].tree[0]->session->transport->negotiate.system_time - - servers[1].tree[0]->session->transport->negotiate.system_time); - return ret + 300; -} - - -static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2) -{ - return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0; -} - -/* - turn a server handle into a local handle -*/ -static uint_t fnum_to_handle(int server, int instance, struct smb2_handle server_handle) -{ - uint_t i; - for (i=0;i 0 && count++ < 10*options.max_open_handles) { - h = random() % options.max_open_handles; - if (open_handles[h].active && - open_handles[h].instance == instance) { - return h; - } - } - return BAD_HANDLE; -} - -/* - return a file handle, but skewed so we don't close the last - couple of handles too readily -*/ -static uint16_t gen_fnum_close(int instance) -{ - if (num_open_handles < 5) { - if (gen_chance(90)) return BAD_HANDLE; - } - - return gen_fnum(instance); -} - -/* - generate an integer in a specified range -*/ -static int gen_int_range(uint64_t min, uint64_t max) -{ - uint_t r = random(); - return min + (r % (1+max-min)); -} - -/* - return a fnum for use as a root fid - be careful to call GEN_SET_FNUM() when you use this! -*/ -static uint16_t gen_root_fid(int instance) -{ - if (gen_chance(5)) return gen_fnum(instance); - return 0; -} - -/* - generate a file offset -*/ -static int gen_offset(void) -{ - if (gen_chance(20)) return 0; -// if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF); - return gen_int_range(0, 1024*1024); -} - -/* - generate a io count -*/ -static int gen_io_count(void) -{ - if (gen_chance(20)) return 0; -// if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF); - return gen_int_range(0, 4096); -} - -/* - generate a filename -*/ -static const char *gen_fname(void) -{ - const char *names[] = {"gentest\\gentest.dat", - "gentest\\foo", - "gentest\\foo2.sym", - "gentest\\foo3.dll", - "gentest\\foo4", - "gentest\\foo4:teststream1", - "gentest\\foo4:teststream2", - "gentest\\foo5.exe", - "gentest\\foo5.exe:teststream3", - "gentest\\foo5.exe:teststream4", - "gentest\\foo6.com", - "gentest\\blah", - "gentest\\blah\\blergh.txt", - "gentest\\blah\\blergh2", - "gentest\\blah\\blergh3.txt", - "gentest\\blah\\blergh4", - "gentest\\blah\\blergh5.txt", - "gentest\\blah\\blergh5", - "gentest\\blah\\.", -#if 0 - /* this causes problem with w2k3 */ - "gentest\\blah\\..", -#endif - "gentest\\a_very_long_name.bin", - "gentest\\x.y", - "gentest\\blah"}; - int i; - - do { - i = gen_int_range(0, ARRAY_SIZE(names)-1); - } while (ignore_pattern(names[i])); - - return names[i]; -} - -/* - generate a filename with a higher chance of choosing an already - open file -*/ -static const char *gen_fname_open(int instance) -{ - uint16_t h; - h = gen_fnum(instance); - if (h == BAD_HANDLE) { - return gen_fname(); - } - return open_handles[h].name; -} - -/* - generate a wildcard pattern -*/ -static const char *gen_pattern(void) -{ - int i; - const char *names[] = {"gentest\\*.dat", - "gentest\\*", - "gentest\\*.*", - "gentest\\blah\\*.*", - "gentest\\blah\\*", - "gentest\\?"}; - - if (gen_chance(50)) return gen_fname(); - - do { - i = gen_int_range(0, ARRAY_SIZE(names)-1); - } while (ignore_pattern(names[i])); - - return names[i]; -} - -static uint32_t gen_bits_levels(int nlevels, ...) -{ - va_list ap; - uint32_t pct; - uint32_t mask; - int i; - va_start(ap, nlevels); - for (i=0;iasync.fn = oplock_handler_ack_callback; - req->async.private_data = NULL; - return true; -} - -/* - the oplock handler will either ack the break or close the file -*/ -static bool oplock_handler(struct smb2_transport *transport, const struct smb2_handle *handle, - uint8_t level, void *private_data) -{ - struct smb2_close io; - unsigned i, j; - bool do_close; - struct smb2_tree *tree = NULL; - struct smb2_request *req; - - srandom(current_op.seed); - do_close = gen_chance(50); - - i = ((uintptr_t)private_data) >> 8; - j = ((uintptr_t)private_data) & 0xFF; - - if (i >= NSERVERS || j >= NINSTANCES) { - printf("Bad private_data in oplock_handler\n"); - return false; - } - - oplocks[i][j].got_break = true; - oplocks[i][j].server_handle = *handle; - oplocks[i][j].handle = fnum_to_handle(i, j, *handle); - oplocks[i][j].level = level; - oplocks[i][j].do_close = do_close; - tree = talloc_get_type(servers[i].tree[j], struct smb2_tree); - - if (!tree) { - printf("Oplock break not for one of our trees!?\n"); - return false; - } - - if (!do_close) { - printf("oplock ack handle=%d\n", oplocks[i][j].handle); - return send_oplock_ack(tree, *handle, level); - } - - printf("oplock close fnum=%d\n", oplocks[i][j].handle); - - ZERO_STRUCT(io); - io.in.file.handle = *handle; - io.in.flags = 0; - req = smb2_close_send(tree, &io); - - if (req == NULL) { - printf("WARNING: close failed in oplock_handler_close\n"); - return false; - } - - req->async.fn = oplock_handler_close_recv; - req->async.private_data = NULL; - - return true; -} - - -/* - the idle function tries to cope with getting an oplock break on a connection, and - an operation on another connection blocking until that break is acked - we check for operations on all transports in the idle function -*/ -static void idle_func(struct smb2_transport *transport, void *private) -{ - int i, j; - for (i=0;isession->transport) { - // smb2_transport_process(servers[i].tree[j]->session->transport); - } - } - } - -} - - -/* - compare NTSTATUS, using checking ignored patterns -*/ -static bool compare_status(NTSTATUS status1, NTSTATUS status2) -{ - if (NT_STATUS_EQUAL(status1, status2)) return true; - - /* one code being an error and the other OK is always an error */ - if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) { - current_op.mismatch = nt_errstr(status1); - return false; - } - - /* if we are ignoring one of the status codes then consider this a match */ - if (ignore_pattern(nt_errstr(status1)) || - ignore_pattern(nt_errstr(status2))) { - return true; - } - current_op.mismatch = nt_errstr(status1); - return false; -} - -#if 0 -/* - check for pending packets on all connections -*/ -static void check_pending(void) -{ - int i, j; - - msleep(20); - - for (j=0;jsession->transport); - } - } -} -#endif - -/* - check that the same oplock breaks have been received by all instances -*/ -static bool check_oplocks(const char *call) -{ -#if 0 - int i, j; - int tries = 0; - -again: - check_pending(); - - for (j=0;jdacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \ - current_op.mismatch = #field; \ - printf("Mismatch in %s\n", #field); \ - return false; \ - } \ -} while(0) - -#define CHECK_ATTRIB(field) do { \ - if (!options.mask_indexing) { \ - CHECK_EQUAL(field); \ - } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \ - current_op.mismatch = #field; \ - printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ - (int)parm[0].field, (int)parm[1].field); \ - return false; \ - } \ -} while(0) - -#define CHECK_WSTR_EQUAL(field) do { \ - if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \ - current_op.mismatch = #field; \ - printf("%s is NULL!\n", #field); \ - return false; \ - } \ - if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \ - current_op.mismatch = #field; \ - printf("Mismatch in %s - %s %s\n", #field, \ - parm[0].field.s, parm[1].field.s); \ - return false; \ - } \ - CHECK_EQUAL(field.private_length); \ -} while(0) - -#define CHECK_BLOB_EQUAL(field) do { \ - if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \ - current_op.mismatch = #field; \ - printf("Mismatch in %s\n", #field); \ - return false; \ - } \ - CHECK_EQUAL(field.length); \ -} while(0) - -#define CHECK_NTTIMES_EQUAL(field) do { \ - if (labs(nt_time_to_unix(parm[0].field) - \ - nt_time_to_unix(parm[1].field)) > time_skew() && \ - !ignore_pattern(#field)) { \ - current_op.mismatch = #field; \ - printf("Mismatch in %s - 0x%x 0x%x\n", #field, \ - (int)nt_time_to_unix(parm[0].field), \ - (int)nt_time_to_unix(parm[1].field)); \ - return false; \ - } \ -} while(0) - -/* - generate ntcreatex operations -*/ -static bool handler_create(int instance) -{ - struct smb2_create parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - - ZERO_STRUCT(parm[0]); - parm[0].in.security_flags = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF); - parm[0].in.oplock_level = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF); - parm[0].in.impersonation_level = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF); - parm[0].in.create_flags = gen_reserved64(); - parm[0].in.reserved = gen_reserved64(); - parm[0].in.desired_access = gen_access_mask(); - parm[0].in.file_attributes = gen_attrib(); - parm[0].in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF); - parm[0].in.create_disposition = gen_open_disp(); - parm[0].in.create_options = gen_create_options(); - parm[0].in.fname = gen_fname_open(instance); - parm[0].in.eas = gen_ea_list(); - parm[0].in.alloc_size = gen_alloc_size(); - parm[0].in.durable_open = gen_bool(); - parm[0].in.query_maximal_access = gen_bool(); - parm[0].in.timewarp = gen_timewarp(); - parm[0].in.query_on_disk_id = gen_bool(); - parm[0].in.sec_desc = gen_sec_desc(); - - if (!options.use_oplocks) { - /* mask out oplocks */ - parm[0].in.oplock_level = 0; - } - - if (options.valid) { - parm[0].in.security_flags &= 3; - parm[0].in.oplock_level &= 9; - parm[0].in.impersonation_level &= 3; - } - - GEN_COPY_PARM; - GEN_CALL(smb2_create(tree, current_op.mem_ctx, &parm[i])); - - CHECK_EQUAL(out.oplock_level); - CHECK_EQUAL(out.reserved); - CHECK_EQUAL(out.create_action); - CHECK_NTTIMES_EQUAL(out.create_time); - CHECK_NTTIMES_EQUAL(out.access_time); - CHECK_NTTIMES_EQUAL(out.write_time); - CHECK_NTTIMES_EQUAL(out.change_time); - CHECK_EQUAL(out.alloc_size); - CHECK_EQUAL(out.size); - CHECK_ATTRIB(out.file_attr); - CHECK_EQUAL(out.reserved2); - CHECK_EQUAL(out.maximal_access); - - /* ntcreatex creates a new file handle */ - ADD_HANDLE(parm[0].in.fname, out.file.handle); - - return true; -} - -/* - generate close operations -*/ -static bool handler_close(int instance) -{ - struct smb2_close parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - - ZERO_STRUCT(parm[0]); - parm[0].in.file.handle.data[0] = gen_fnum_close(instance); - parm[0].in.flags = gen_bits_mask2(0x1, 0xFFFF); - - GEN_COPY_PARM; - GEN_SET_FNUM(in.file.handle); - GEN_CALL(smb2_close(tree, &parm[i])); - - CHECK_EQUAL(out.flags); - CHECK_EQUAL(out._pad); - CHECK_NTTIMES_EQUAL(out.create_time); - CHECK_NTTIMES_EQUAL(out.access_time); - CHECK_NTTIMES_EQUAL(out.write_time); - CHECK_NTTIMES_EQUAL(out.change_time); - CHECK_EQUAL(out.alloc_size); - CHECK_EQUAL(out.size); - CHECK_ATTRIB(out.file_attr); - - REMOVE_HANDLE(in.file.handle); - - return true; -} - -/* - generate read operations -*/ -static bool handler_read(int instance) -{ - struct smb2_read parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - - parm[0].in.file.handle.data[0] = gen_fnum(instance); - parm[0].in.reserved = gen_reserved8(); - parm[0].in.length = gen_io_count(); - parm[0].in.offset = gen_offset(); - parm[0].in.min_count = gen_io_count(); - parm[0].in.channel = gen_bits_mask2(0x0, 0xFFFFFFFF); - parm[0].in.remaining = gen_bits_mask2(0x0, 0xFFFFFFFF); - parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF); - parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF); - - GEN_COPY_PARM; - GEN_SET_FNUM(in.file.handle); - GEN_CALL(smb2_read(tree, current_op.mem_ctx, &parm[i])); - - CHECK_EQUAL(out.remaining); - CHECK_EQUAL(out.reserved); - CHECK_EQUAL(out.data.length); - - return true; -} - -/* - generate write operations -*/ -static bool handler_write(int instance) -{ - struct smb2_write parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - - parm[0].in.file.handle.data[0] = gen_fnum(instance); - parm[0].in.offset = gen_offset(); - parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF); - parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF); - parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL, - gen_io_count()); - - GEN_COPY_PARM; - GEN_SET_FNUM(in.file.handle); - GEN_CALL(smb2_write(tree, &parm[i])); - - CHECK_EQUAL(out._pad); - CHECK_EQUAL(out.nwritten); - CHECK_EQUAL(out.unknown1); - - return true; -} - -/* - generate lockingx operations -*/ -static bool handler_lock(int instance) -{ - struct smb2_lock parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - int n; - - parm[0].level = RAW_LOCK_LOCKX; - parm[0].in.file.handle.data[0] = gen_fnum(instance); - parm[0].in.lock_count = gen_lock_count(); - parm[0].in.reserved = gen_reserved32(); - - parm[0].in.locks = talloc_array(current_op.mem_ctx, - struct smb2_lock_element, - parm[0].in.lock_count); - for (n=0;nsession->transport)); - - return true; -} - - - -/* - generate a fileinfo query structure -*/ -static void gen_fileinfo(int instance, union smb_fileinfo *info) -{ - int i; - #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v} - struct { - enum smb_fileinfo_level level; - const char *name; - } levels[] = { - LVL(BASIC_INFORMATION), - LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION), - LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION), - LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION), - LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION), - LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION), - LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC), - }; - do { - i = gen_int_range(0, ARRAY_SIZE(levels)-1); - } while (ignore_pattern(levels[i].name)); - - info->generic.level = levels[i].level; -} - -/* - compare returned fileinfo structures -*/ -static bool cmp_fileinfo(int instance, - union smb_fileinfo parm[NSERVERS], - NTSTATUS status[NSERVERS]) -{ - int i; - - switch (parm[0].generic.level) { - case RAW_FILEINFO_GENERIC: - return false; - - /* SMB1 specific values */ - case RAW_FILEINFO_GETATTR: - case RAW_FILEINFO_GETATTRE: - case RAW_FILEINFO_STANDARD: - case RAW_FILEINFO_EA_SIZE: - case RAW_FILEINFO_ALL_EAS: - case RAW_FILEINFO_IS_NAME_VALID: - case RAW_FILEINFO_BASIC_INFO: - case RAW_FILEINFO_STANDARD_INFO: - case RAW_FILEINFO_EA_INFO: - case RAW_FILEINFO_NAME_INFO: - case RAW_FILEINFO_ALL_INFO: - case RAW_FILEINFO_ALT_NAME_INFO: - case RAW_FILEINFO_STREAM_INFO: - case RAW_FILEINFO_COMPRESSION_INFO: - return false; - - case RAW_FILEINFO_BASIC_INFORMATION: - CHECK_NTTIMES_EQUAL(basic_info.out.create_time); - CHECK_NTTIMES_EQUAL(basic_info.out.access_time); - CHECK_NTTIMES_EQUAL(basic_info.out.write_time); - CHECK_NTTIMES_EQUAL(basic_info.out.change_time); - CHECK_ATTRIB(basic_info.out.attrib); - break; - - case RAW_FILEINFO_STANDARD_INFORMATION: - CHECK_EQUAL(standard_info.out.alloc_size); - CHECK_EQUAL(standard_info.out.size); - CHECK_EQUAL(standard_info.out.nlink); - CHECK_EQUAL(standard_info.out.delete_pending); - CHECK_EQUAL(standard_info.out.directory); - break; - - case RAW_FILEINFO_EA_INFORMATION: - CHECK_EQUAL(ea_info.out.ea_size); - break; - - case RAW_FILEINFO_NAME_INFORMATION: - CHECK_WSTR_EQUAL(name_info.out.fname); - break; - - case RAW_FILEINFO_ALT_NAME_INFORMATION: - CHECK_WSTR_EQUAL(alt_name_info.out.fname); - break; - - case RAW_FILEINFO_STREAM_INFORMATION: - CHECK_EQUAL(stream_info.out.num_streams); - for (i=0;igeneric.level = levels[i].level; - - switch (info->generic.level) { - case RAW_SFILEINFO_SETATTR: - case RAW_SFILEINFO_SETATTRE: - case RAW_SFILEINFO_STANDARD: - case RAW_SFILEINFO_EA_SET: - case RAW_SFILEINFO_BASIC_INFO: - case RAW_SFILEINFO_DISPOSITION_INFO: - case RAW_SFILEINFO_END_OF_FILE_INFO: - case RAW_SFILEINFO_ALLOCATION_INFO: - break; - - case RAW_SFILEINFO_BASIC_INFORMATION: - info->basic_info.in.create_time = gen_nttime(); - info->basic_info.in.access_time = gen_nttime(); - info->basic_info.in.write_time = gen_nttime(); - info->basic_info.in.change_time = gen_nttime(); - info->basic_info.in.attrib = gen_attrib(); - break; - case RAW_SFILEINFO_DISPOSITION_INFORMATION: - info->disposition_info.in.delete_on_close = gen_bool(); - break; - case RAW_SFILEINFO_ALLOCATION_INFORMATION: - info->allocation_info.in.alloc_size = gen_alloc_size(); - break; - case RAW_SFILEINFO_END_OF_FILE_INFORMATION: - info->end_of_file_info.in.size = gen_offset(); - break; - case RAW_SFILEINFO_RENAME_INFORMATION: - case RAW_SFILEINFO_RENAME_INFORMATION_SMB2: - info->rename_information.in.overwrite = gen_bool(); - info->rename_information.in.root_fid = gen_root_fid(instance); - info->rename_information.in.new_name = gen_fname_open(instance); - break; - case RAW_SFILEINFO_POSITION_INFORMATION: - info->position_information.in.position = gen_offset(); - break; - case RAW_SFILEINFO_MODE_INFORMATION: - info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF); - break; - case RAW_SFILEINFO_GENERIC: - case RAW_SFILEINFO_SEC_DESC: - case RAW_SFILEINFO_1023: - case RAW_SFILEINFO_1025: - case RAW_SFILEINFO_1029: - case RAW_SFILEINFO_1032: - case RAW_SFILEINFO_1039: - case RAW_SFILEINFO_1040: - case RAW_SFILEINFO_UNIX_BASIC: - case RAW_SFILEINFO_UNIX_INFO2: - case RAW_SFILEINFO_UNIX_LINK: - case RAW_SFILEINFO_UNIX_HLINK: - /* Untested */ - break; - } -} - -/* - generate setfileinfo operations -*/ -static bool handler_sfileinfo(int instance) -{ - union smb_setfileinfo parm[NSERVERS]; - NTSTATUS status[NSERVERS]; - - parm[0].generic.in.file.fnum = gen_fnum(instance); - - gen_setfileinfo(instance, &parm[0]); - - GEN_COPY_PARM; - GEN_SET_FNUM(generic.in.file.handle); - GEN_CALL(smb2_setinfo_file(tree, &parm[i])); - - return true; -} - -/* - wipe any relevant files -*/ -static void wipe_files(void) -{ - int i; - NTSTATUS status; - - if (options.skip_cleanup) { - return; - } - - for (i=0;i 0) { - printf("Deleted %d files on server %d\n", n, i); - } - } -} - -/* - dump the current seeds - useful for continuing a backtrack -*/ -static void dump_seeds(void) -{ - int i; - FILE *f; - - if (!options.seeds_file) { - return; - } - f = fopen("seeds.tmp", "w"); - if (!f) return; - - for (i=0;i 0 && base+chunk < options.numops && options.numops > 1; ) { - int i, max; - - chunk = MIN(chunk, options.numops / 2); - - /* mark this range as disabled */ - max = MIN(options.numops, base+chunk); - for (i=base;i 0); - - printf("Reduced to %d ops\n", options.numops); - ret = run_test(ev, lp_ctx); - if (ret != options.numops - 1) { - printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops); - } -} - -/* - start the main gentest process -*/ -static bool start_gentest(struct event_context *ev, - struct loadparm_context *lp_ctx) -{ - int op; - int ret; - - /* allocate the open_handles array */ - open_handles = calloc(options.max_open_handles, sizeof(open_handles[0])); - - srandom(options.seed); - op_parms = calloc(options.numops, sizeof(op_parms[0])); - - /* generate the seeds - after this everything is deterministic */ - if (options.use_preset_seeds) { - int numops; - char **preset = file_lines_load(options.seeds_file, &numops, NULL); - if (!preset) { - printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno)); - exit(1); - } - if (numops < options.numops) { - options.numops = numops; - } - for (op=0;op "); - - lp_ctx = cmdline_lp_ctx; - servers[0].credentials = cli_credentials_init(talloc_autofree_context()); - servers[1].credentials = cli_credentials_init(talloc_autofree_context()); - cli_credentials_guess(servers[0].credentials, lp_ctx); - cli_credentials_guess(servers[1].credentials, lp_ctx); - - while((opt = poptGetNextOpt(pc)) != -1) { - switch (opt) { - case OPT_UNCLIST: - lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc)); - break; - case 'U': - if (username_count == 2) { - usage(pc); - exit(1); - } - cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), CRED_SPECIFIED); - username_count++; - break; - } - } - - if (ignore_file) { - options.ignore_patterns = file_lines_load(ignore_file, NULL, NULL); - } - - argv_new = discard_const_p(char *, poptGetArgs(pc)); - argc_new = argc; - for (i=0; i= 3)) { - usage(pc); - exit(1); - } - - setlinebuf(stdout); - - setup_logging("gentest", DEBUG_STDOUT); - - if (argc < 3 || argv[1][0] == '-') { - usage(pc); - exit(1); - } - - setup_logging(argv[0], DEBUG_STDOUT); - - for (i=0;i Date: Thu, 29 May 2008 22:22:42 +1000 Subject: don't mask out SEC_FILE_READ_ATTRIBUTE on SMB2 (This used to be commit 1dfa50a48040bdc1166be2dbe1063fd8a79166f8) --- source4/ntvfs/posix/pvfs_acl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/ntvfs/posix/pvfs_acl.c b/source4/ntvfs/posix/pvfs_acl.c index 623b1ae5e9..9a9200e4f0 100644 --- a/source4/ntvfs/posix/pvfs_acl.c +++ b/source4/ntvfs/posix/pvfs_acl.c @@ -500,7 +500,9 @@ NTSTATUS pvfs_access_check(struct pvfs_state *pvfs, /* expand the generic access bits to file specific bits */ *access_mask = pvfs_translate_mask(*access_mask); - *access_mask &= ~SEC_FILE_READ_ATTRIBUTE; + if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) { + *access_mask &= ~SEC_FILE_READ_ATTRIBUTE; + } status = pvfs_acl_load(pvfs, name, -1, acl); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { -- cgit From b33dba845e4e583a25c2f88b8439b8dde205dc89 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 30 May 2008 07:28:29 +1000 Subject: don't emulate broken SMB2 locking behaviour from windows (This used to be commit c50e7a15f9a7f2c5821b5ee468f9ade6eaa0ed55) --- source4/ntvfs/posix/pvfs_lock.c | 14 ++------- source4/torture/smb2/lock.c | 70 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 15 deletions(-) (limited to 'source4') diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c index baa92880f1..822b28246a 100644 --- a/source4/ntvfs/posix/pvfs_lock.c +++ b/source4/ntvfs/posix/pvfs_lock.c @@ -68,13 +68,8 @@ static void pvfs_lock_async_failed(struct pvfs_state *pvfs, int i, NTSTATUS status) { - /* in SMB2 mode we also try to unlock failing lock */ - if (req->ctx->protocol != PROTOCOL_SMB2) { - i--; - } - /* undo the locks we just did */ - for (;i>=0;i--) { + for (i--;i>=0;i--) { brl_unlock(pvfs->brl_context, f->brl_handle, locks[i].pid, @@ -390,12 +385,9 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, DLIST_ADD(f->pending_list, pending); return NT_STATUS_OK; } - /* in SMB2 mode we also try to unlock failing lock */ - if (req->ctx->protocol != PROTOCOL_SMB2) { - i--; - } + /* undo the locks we just did */ - for (;i>=0;i--) { + for (i--;i>=0;i--) { brl_unlock(pvfs->brl_context, f->brl_handle, locks[i].pid, diff --git a/source4/torture/smb2/lock.c b/source4/torture/smb2/lock.c index 5a36ac3eae..35ad839610 100644 --- a/source4/torture/smb2/lock.c +++ b/source4/torture/smb2/lock.c @@ -106,7 +106,11 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree lck.in.reserved = 0x123ab3; status = smb2_lock(tree, &lck); - CHECK_STATUS(status, NT_STATUS_OK); + if (torture_setting_bool(torture, "windows", false)) { + CHECK_STATUS(status, NT_STATUS_OK); + } else { + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + } CHECK_VALUE(lck.out.reserved, 0); lck.in.reserved = 0x123ab4; @@ -115,7 +119,11 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree lck.in.reserved = 0x123ab5; status = smb2_lock(tree, &lck); - CHECK_STATUS(status, NT_STATUS_OK); + if (torture_setting_bool(torture, "windows", false)) { + CHECK_STATUS(status, NT_STATUS_OK); + } else { + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + } CHECK_VALUE(lck.out.reserved, 0); lck.in.lock_count = 0x0001; @@ -133,14 +141,22 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); status = smb2_lock(tree, &lck); - CHECK_STATUS(status, NT_STATUS_OK); + if (torture_setting_bool(torture, "windows", false)) { + CHECK_STATUS(status, NT_STATUS_OK); + } else { + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + } CHECK_VALUE(lck.out.reserved, 0); status = smb2_lock(tree, &lck); CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); status = smb2_lock(tree, &lck); - CHECK_STATUS(status, NT_STATUS_OK); + if (torture_setting_bool(torture, "windows", false)) { + CHECK_STATUS(status, NT_STATUS_OK); + } else { + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + } CHECK_VALUE(lck.out.reserved, 0); el[0].flags = 0x00000000; @@ -473,6 +489,51 @@ static bool test_lock_rw_exclusiv(struct torture_context *torture, struct smb2_t return test_lock_read_write(torture, tree, &s); } + +static bool test_lock_auto_unlock(struct torture_context *torture, struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_handle h; + uint8_t buf[200]; + struct smb2_lock lck; + struct smb2_lock_element el[2]; + + ZERO_STRUCT(buf); + + status = torture_smb2_testfile(tree, "autounlock.txt", &h); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf)); + CHECK_STATUS(status, NT_STATUS_OK); + + ZERO_STRUCT(lck); + lck.in.locks = el; + lck.in.lock_count = 0x0001; + lck.in.file.handle = h; + el[0].offset = 0; + el[0].length = 1; + el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + status = smb2_lock(tree, &lck); + if (torture_setting_bool(torture, "windows", false)) { + CHECK_STATUS(status, NT_STATUS_OK); + } else { + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + } + + + +done: + return ret; +} + + /* basic testing of SMB2 locking */ struct torture_suite *torture_smb2_lock_init(void) @@ -483,6 +544,7 @@ struct torture_suite *torture_smb2_lock_init(void) torture_suite_add_1smb2_test(suite, "RW-NONE", test_lock_rw_none); torture_suite_add_1smb2_test(suite, "RW-SHARED", test_lock_rw_shared); torture_suite_add_1smb2_test(suite, "RW-EXCLUSIV", test_lock_rw_exclusiv); + torture_suite_add_1smb2_test(suite, "AUTO-UNLOCK", test_lock_auto_unlock); suite->description = talloc_strdup(suite, "SMB2-LOCK tests"); -- cgit From 6ef9674caa67c1f086285f1bee17c6f390778588 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 30 May 2008 07:28:53 +1000 Subject: the docs shows that this is a o16s32 blob (This used to be commit a6d28e2b330a20e95b745966bb5eb153bdc58ed1) --- source4/smb_server/smb2/fileinfo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/smb_server/smb2/fileinfo.c b/source4/smb_server/smb2/fileinfo.c index d6db61eaba..942000133c 100644 --- a/source4/smb_server/smb2/fileinfo.c +++ b/source4/smb_server/smb2/fileinfo.c @@ -55,8 +55,7 @@ static void smb2srv_getinfo_send(struct ntvfs_request *ntvfs) SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, true, op->info->out.blob.length)); - /* TODO: this is maybe a o16s32_blob */ - SMB2SRV_CHECK(smb2_push_o16s16_blob(&req->out, 0x02, op->info->out.blob)); + SMB2SRV_CHECK(smb2_push_o16s32_blob(&req->out, 0x02, op->info->out.blob)); SSVAL(req->out.body, 0x06, 0); smb2srv_send_reply(req); -- cgit From 0613d0b2184319146697f817809d2fa9916f7ac5 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 07:54:09 +1000 Subject: Remove test from samba4-skip, it is avoided in samba4_tests.sh Andrew Bartlett (This used to be commit df8c0bb8f9367b425080a43ed6f1d3384dde340b) --- source4/samba4-skip | 1 - 1 file changed, 1 deletion(-) (limited to 'source4') diff --git a/source4/samba4-skip b/source4/samba4-skip index 4ac35a3c78..b4d81b8b87 100644 --- a/source4/samba4-skip +++ b/source4/samba4-skip @@ -10,7 +10,6 @@ raw.hold.oplock # Not a test, but a way to block other clients for a test raw.ping.pong # Needs second server to test rpc.samr_accessmask raw.scan.eamax -samba4.ntvfs.cifs.raw.qfileinfo.ipc base.utable base.smb smb2.notify -- cgit From b9babfe4cc70b96f4f1df037244cd27eae580c94 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 14:26:47 +1000 Subject: Fix up provision and samdb tests. This fixes up the provision to operate with a target directory - it must override the smb.conf in this case. Andrew Bartlett (This used to be commit 89fc39f7edb214065aff461bc225f41443eae3c7) --- source4/scripting/python/samba/provision.py | 5 +++-- source4/scripting/python/samba/tests/samdb.py | 25 ++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 71c1ac3187..b7112e16c3 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -930,8 +930,9 @@ def provision(setup_dir, message, session_info, if aci is None: aci = "# no aci for local ldb" - if smbconf is None: - os.makedirs(os.path.join(targetdir, "etc")) + if targetdir is not None: + if (not os.path.exists(os.path.join(targetdir, "etc"))): + os.makedirs(os.path.join(targetdir, "etc")) smbconf = os.path.join(targetdir, "etc", "smb.conf") # only install a new smb.conf if there isn't one there already diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py index 7e8ba053d4..fcf93a3fc6 100644 --- a/source4/scripting/python/samba/tests/samdb.py +++ b/source4/scripting/python/samba/tests/samdb.py @@ -19,12 +19,13 @@ from samba.auth import system_session from samba.credentials import Credentials import os -from samba.provision import setup_samdb, guess_names, setup_templatesdb +from samba.provision import setup_samdb, guess_names, setup_templatesdb, make_smbconf from samba.samdb import SamDB from samba.tests import cmdline_loadparm, TestCaseInTempDir from samba import security from unittest import TestCase import uuid +import param class SamDBTestCase(TestCaseInTempDir): def setUp(self): @@ -43,9 +44,22 @@ class SamDBTestCase(TestCaseInTempDir): hostguid = str(uuid.uuid4()) path = os.path.join(self.tempdir, "samdb.ldb") session_info = system_session() - names = guess_names(lp=cmdline_loadparm, hostname="foo", - domain="EXAMPLE.COM", dnsdomain="example.com", - serverrole="domain controller", + + hostname="foo" + domain="EXAMPLE" + dnsdomain="example.com" + serverrole="domain controller" + + smbconf = os.path.join(self.tempdir, "smb.conf") + make_smbconf(smbconf, setup_path, hostname, domain, dnsdomain, serverrole, + self.tempdir) + + lp = param.LoadParm() + lp.load(smbconf) + + names = guess_names(lp=lp, hostname=hostname, + domain=domain, dnsdomain=dnsdomain, + serverrole=severrole, domaindn=self.domaindn, configdn=configdn, schemadn=schemadn) setup_templatesdb(os.path.join(self.tempdir, "templates.ldb"), @@ -58,9 +72,10 @@ class SamDBTestCase(TestCaseInTempDir): policyguid, False, "secret", "secret", "secret", invocationid, "secret", "domain controller") + def tearDown(self): for f in ['templates.ldb', 'schema.ldb', 'configuration.ldb', - 'users.ldb', 'samdb.ldb']: + 'users.ldb', 'samdb.ldb', 'smb.conf']: os.remove(os.path.join(self.tempdir, f)) super(SamDBTestCase, self).tearDown() -- cgit From b34bc408e741919b893a325616de432e8a630e10 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 14:36:24 +1000 Subject: Don't pass an smb.conf to provision tests. These tests will create their own smb.conf in their prefix anyway. Andrew Bartlett (This used to be commit c0322e8e27d67655b7498b27df0829aa5682a345) --- source4/selftest/samba4_tests.sh | 6 +++--- source4/setup/tests/blackbox_newuser.sh | 9 ++++----- source4/setup/tests/blackbox_provision.sh | 23 +++++++++++------------ source4/setup/tests/blackbox_setpassword.sh | 9 ++++----- 4 files changed, 22 insertions(+), 25 deletions(-) (limited to 'source4') diff --git a/source4/selftest/samba4_tests.sh b/source4/selftest/samba4_tests.sh index 9693451c47..c79c8a5c1e 100755 --- a/source4/selftest/samba4_tests.sh +++ b/source4/selftest/samba4_tests.sh @@ -353,6 +353,6 @@ rm -rf $PREFIX/upgrade plantest "blackbox.upgrade" none $PYTHON setup/upgrade $CONFIGURATION --targetdir=$PREFIX/upgrade ../testdata/samba3 ../testdata/samba3/smb.conf rm -rf $PREFIX/provision mkdir $PREFIX/provision -plantest "blackbox.provision.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_provision.sh "$PREFIX/provision" "$CONFIGURATION" -plantest "blackbox.setpassword.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_setpassword.sh "$PREFIX/provision" "$CONFIGURATION" -plantest "blackbox.newuser.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_newuser.sh "$PREFIX/provision" "$CONFIGURATION" +plantest "blackbox.provision.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_provision.sh "$PREFIX/provision" +plantest "blackbox.setpassword.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_setpassword.sh "$PREFIX/provision" +plantest "blackbox.newuser.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_newuser.sh "$PREFIX/provision" diff --git a/source4/setup/tests/blackbox_newuser.sh b/source4/setup/tests/blackbox_newuser.sh index fed5f7d263..3e534f2b52 100755 --- a/source4/setup/tests/blackbox_newuser.sh +++ b/source4/setup/tests/blackbox_newuser.sh @@ -1,20 +1,19 @@ #!/bin/sh -if [ $# -lt 2 ]; then +if [ $# -lt 1 ]; then cat < Date: Fri, 30 May 2008 14:58:47 +1000 Subject: Reorder the linking of objects into a binary. The hope here is to get 'main' closer to the front of the binary, which might help linking of PPC with gcov (we were overflowing the 24bit limit on the TOC) Andrew Bartlett (This used to be commit 7646574411b753794f1b8712612a91940407f8d7) --- source4/build/smb_build/makefile.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4') diff --git a/source4/build/smb_build/makefile.pm b/source4/build/smb_build/makefile.pm index 73801c25fd..0ea31062f7 100644 --- a/source4/build/smb_build/makefile.pm +++ b/source4/build/smb_build/makefile.pm @@ -208,9 +208,9 @@ sub Binary($$) $self->_prepare_list($ctx, "LINK_FLAGS"); if (defined($ctx->{USE_HOSTCC}) && $ctx->{USE_HOSTCC} eq "YES") { -$self->output("\$(call host_binary_link_template, $ctx->{RESULT_BINARY}, \$($ctx->{NAME}_DEPEND_LIST) \$($ctx->{NAME}_FULL_OBJ_LIST), \$($ctx->{NAME}_LINK_FLAGS))\n"); +$self->output("\$(call host_binary_link_template, $ctx->{RESULT_BINARY}, \$($ctx->{NAME}_FULL_OBJ_LIST) \$($ctx->{NAME}_DEPEND_LIST), \$($ctx->{NAME}_LINK_FLAGS))\n"); } else { -$self->output("\$(call binary_link_template, $ctx->{RESULT_BINARY}, \$($ctx->{NAME}_DEPEND_LIST) \$($ctx->{NAME}_FULL_OBJ_LIST), \$($ctx->{NAME}_LINK_FLAGS))\n"); +$self->output("\$(call binary_link_template, $ctx->{RESULT_BINARY}, \$($ctx->{NAME}_FULL_OBJ_LIST) \$($ctx->{NAME}_DEPEND_LIST), \$($ctx->{NAME}_LINK_FLAGS))\n"); } } -- cgit From d579540085133d3a3b273a653cea7f8da10ed5db Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 15:09:59 +1000 Subject: Fix rpcecho test. (This used to be commit df8399ba9dee9d1c706a3e56451c9f2cade96dae) --- source4/scripting/python/samba/tests/dcerpc/rpcecho.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py index bbbd0d76ec..96bb3923a6 100644 --- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py +++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py @@ -27,7 +27,7 @@ class RpcEchoTests(RpcInterfaceTestCase): self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm()) def test_two_contexts(self): - self.conn2 = echo.rpcecho("ncalrpc:", basis_connection=self.conn) + self.conn2 = echo.rpcecho("ncalrpc:", self.get_loadparm(), basis_connection=self.conn) self.assertEquals(3, self.conn2.AddOne(2)) def test_abstract_syntax(self): -- cgit From b6b1f3b0072be88ba0ca2d44c6a7b1cbc57b4868 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 15:21:40 +1000 Subject: Place the NTP signd socket in the selftest area (This used to be commit e2fa3788110698cd3340dfed8acd36744a27a5e5) --- source4/selftest/target/Samba4.pm | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source4') diff --git a/source4/selftest/target/Samba4.pm b/source4/selftest/target/Samba4.pm index a12939b0a1..9f771ab8a3 100644 --- a/source4/selftest/target/Samba4.pm +++ b/source4/selftest/target/Samba4.pm @@ -521,6 +521,7 @@ sub provision($$$$$$) my $ncalrpcdir = "$prefix_abs/ncalrpc"; my $lockdir = "$prefix_abs/lockdir"; my $winbindd_socket_dir = "$prefix_abs/winbind_socket"; + my $ntp_signd_socket_dir = "$prefix_abs/ntp_signd_socket"; my $winbindd_priv_pipe_dir = "$privatedir/smbd.tmp/winbind_pipe"; my $nsswrap_passwd = "$etcdir/passwd"; my $nsswrap_group = "$etcdir/group"; @@ -556,6 +557,7 @@ sub provision($$$$$$) modules dir = $self->{bindir}/modules js include = $srcdir/scripting/libjs winbindd socket directory = $winbindd_socket_dir + ntp signd socket directory = $ntp_signd_socket_dir winbind separator = / name resolve order = bcast interfaces = $interfaces -- cgit From 21377a7ea9800636a8bc96b3863f97062d7bf9d1 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 15:26:10 +1000 Subject: Fix the samba4.dcerpc.bare.python test. The loadparm context isn't really optional, as otherwise we can't find the right server to connect to. Andrew Bartlett (This used to be commit 2b5acb5e95b46dd39c6f54b5bb7e15ddb180f7ec) --- source4/scripting/python/samba/tests/dcerpc/bare.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/tests/dcerpc/bare.py b/source4/scripting/python/samba/tests/dcerpc/bare.py index d75ffc381e..fae699a249 100644 --- a/source4/scripting/python/samba/tests/dcerpc/bare.py +++ b/source4/scripting/python/samba/tests/dcerpc/bare.py @@ -20,27 +20,28 @@ from samba.dcerpc import ClientConnection from unittest import TestCase +from samba.tests import cmdline_loadparm class BareTestCase(TestCase): def test_bare(self): # Connect to the echo pipe x = ClientConnection("ncalrpc:localhost[DEFAULT]", - ("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), lp_ctx=cmdline_loadparm) self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) def test_alter_context(self): x = ClientConnection("ncalrpc:localhost[DEFAULT]", - ("12345778-1234-abcd-ef00-0123456789ac", 1)) + ("12345778-1234-abcd-ef00-0123456789ac", 1), lp_ctx=cmdline_loadparm) y = ClientConnection("ncalrpc:localhost", ("60a15ec5-4de8-11d7-a637-005056a20182", 1), - basis_connection=x) + basis_connection=x, lp_ctx=cmdline_loadparm) x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1)) # FIXME: self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4)) def test_two_connections(self): x = ClientConnection("ncalrpc:localhost[DEFAULT]", - ("60a15ec5-4de8-11d7-a637-005056a20182", 1)) + ("60a15ec5-4de8-11d7-a637-005056a20182", 1), lp_ctx=cmdline_loadparm) y = ClientConnection("ncalrpc:localhost", ("60a15ec5-4de8-11d7-a637-005056a20182", 1), - basis_connection=x) + basis_connection=x, lp_ctx=cmdline_loadparm) self.assertEquals("\x01\x00\x00\x00", y.request(0, chr(0) * 4)) -- cgit From 07e6a0fd8a873be7ce047d01ac775c6e68b7616c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 30 May 2008 16:11:07 +1000 Subject: fixed a segv in the python messaging code on 64 bit systems (This used to be commit 7598c8389745fcc77da341b4af2dcef6a01db700) --- source4/lib/messaging/pymessaging.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4') diff --git a/source4/lib/messaging/pymessaging.c b/source4/lib/messaging/pymessaging.c index 1c22fb431a..869508fca6 100644 --- a/source4/lib/messaging/pymessaging.c +++ b/source4/lib/messaging/pymessaging.c @@ -127,12 +127,15 @@ static PyObject *py_messaging_send(PyObject *self, PyObject *args, PyObject *kwa NTSTATUS status; struct server_id server; const char *kwnames[] = { "target", "msg_type", "data", NULL }; + int length; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ois#|:send", - discard_const_p(char *, kwnames), &target, &msg_type, &data.data, &data.length)) { + discard_const_p(char *, kwnames), &target, &msg_type, &data.data, &length)) { return NULL; } + data.length = length; + if (!server_id_from_py(target, &server)) return NULL; -- cgit From 27f465619b2d8e01397b6d15434c9f2c577c5457 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 30 May 2008 16:19:22 +1000 Subject: two more places where the wrong type is passed to PyArg_ParseTupleAndKeywords() (This used to be commit db6122ec104e80ee2e02b1170ff808b6456b780b) --- source4/lib/messaging/pymessaging.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'source4') diff --git a/source4/lib/messaging/pymessaging.c b/source4/lib/messaging/pymessaging.c index 869508fca6..41c9c82b1f 100644 --- a/source4/lib/messaging/pymessaging.c +++ b/source4/lib/messaging/pymessaging.c @@ -162,11 +162,11 @@ static void py_msg_callback_wrapper(struct messaging_context *msg, void *private static PyObject *py_messaging_register(PyObject *self, PyObject *args, PyObject *kwargs) { messaging_Object *iface = (messaging_Object *)self; - uint32_t msg_type = -1; + int msg_type = -1; PyObject *callback; NTSTATUS status; const char *kwnames[] = { "callback", "msg_type", NULL }; - + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:send", discard_const_p(char *, kwnames), &callback, &msg_type)) { return NULL; @@ -175,8 +175,10 @@ static PyObject *py_messaging_register(PyObject *self, PyObject *args, PyObject Py_INCREF(callback); if (msg_type == -1) { + uint32_t msg_type32 = msg_type; status = messaging_register_tmp(iface->msg_ctx, callback, - py_msg_callback_wrapper, &msg_type); + py_msg_callback_wrapper, &msg_type32); + msg_type = msg_type32; } else { status = messaging_register(iface->msg_ctx, callback, msg_type, py_msg_callback_wrapper); @@ -192,7 +194,7 @@ static PyObject *py_messaging_register(PyObject *self, PyObject *args, PyObject static PyObject *py_messaging_deregister(PyObject *self, PyObject *args, PyObject *kwargs) { messaging_Object *iface = (messaging_Object *)self; - uint32_t msg_type = -1; + int msg_type = -1; PyObject *callback; const char *kwnames[] = { "callback", "msg_type", NULL }; -- cgit From beaa01e403dda7557a6acdf0181d79d58a33bbbe Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 30 May 2008 17:03:54 +1000 Subject: implemented client side SMB2 signing This doessn't work against Windows yet, and I've submitted a WSPP request for clarification of the docs to try and find out why. Meanwhile this is no worse than what we had, as it only gets used when the server demands signing, and we didn't work then anyway. (This used to be commit b788096add3586d7277efcd3bf5ca7f3a604cb7a) --- source4/libcli/smb2/cancel.c | 6 +- source4/libcli/smb2/config.mk | 2 +- source4/libcli/smb2/connect.c | 54 ++++++++++-- source4/libcli/smb2/notify.c | 6 +- source4/libcli/smb2/session.c | 17 +++- source4/libcli/smb2/signing.c | 165 ++++++++++++++++++++++++++++++++++++ source4/libcli/smb2/smb2.h | 22 +++-- source4/libcli/smb2/transport.c | 49 +++++++---- source4/librpc/rpc/dcerpc_connect.c | 6 +- source4/librpc/rpc/dcerpc_smb2.c | 2 +- source4/ntvfs/smb2/vfs_smb2.c | 6 +- source4/torture/gentest.c | 7 +- source4/torture/smb2/read.c | 1 - source4/torture/smb2/scan.c | 11 ++- source4/torture/smb2/util.c | 5 +- 15 files changed, 308 insertions(+), 51 deletions(-) create mode 100644 source4/libcli/smb2/signing.c (limited to 'source4') diff --git a/source4/libcli/smb2/cancel.c b/source4/libcli/smb2/cancel.c index 80127feea5..65f02187c1 100644 --- a/source4/libcli/smb2/cancel.c +++ b/source4/libcli/smb2/cancel.c @@ -61,10 +61,10 @@ NTSTATUS smb2_cancel(struct smb2_request *r) SSVAL(c->out.body, 0x02, 0); - old_timeout = c->transport->options.timeout; - c->transport->options.timeout = 0; + old_timeout = c->transport->options.request_timeout; + c->transport->options.request_timeout = 0; smb2_transport_send(c); - c->transport->options.timeout = old_timeout; + c->transport->options.request_timeout = old_timeout; if (c->state == SMB2_REQUEST_ERROR) { status = c->status; diff --git a/source4/libcli/smb2/config.mk b/source4/libcli/smb2/config.mk index 00b6305def..322bca1416 100644 --- a/source4/libcli/smb2/config.mk +++ b/source4/libcli/smb2/config.mk @@ -5,6 +5,6 @@ LIBCLI_SMB2_OBJ_FILES = $(addprefix $(libclisrcdir)/smb2/, \ transport.o request.o negprot.o session.o tcon.o \ create.o close.o connect.o getinfo.o write.o read.o \ setinfo.o find.o ioctl.o logoff.o tdis.o flush.o \ - lock.o notify.o cancel.o keepalive.o break.o util.o) + lock.o notify.o cancel.o keepalive.o break.o util.o signing.o) $(eval $(call proto_header_template,$(libclisrcdir)/smb2/smb2_proto.h,$(LIBCLI_SMB2_OBJ_FILES:.o=.c))) diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c index eabfa410ad..cdb5e3b5d4 100644 --- a/source4/libcli/smb2/connect.c +++ b/source4/libcli/smb2/connect.c @@ -33,6 +33,7 @@ struct smb2_connect_state { struct resolve_context *resolve_ctx; const char *host; const char *share; + struct smbcli_options options; struct smb2_negprot negprot; struct smb2_tree_connect tcon; struct smb2_session *session; @@ -103,6 +104,34 @@ static void continue_negprot(struct smb2_request *req) transport->negotiate.system_time = state->negprot.out.system_time; transport->negotiate.server_start_time = state->negprot.out.server_start_time; + transport->negotiate.security_mode = state->negprot.out.security_mode; + + switch (transport->options.signing) { + case SMB_SIGNING_OFF: + if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { + composite_error(c, NT_STATUS_ACCESS_DENIED); + return; + } + transport->signing.doing_signing = false; + break; + case SMB_SIGNING_SUPPORTED: + case SMB_SIGNING_AUTO: + if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { + transport->signing.doing_signing = true; + } else { + transport->signing.doing_signing = false; + } + break; + case SMB_SIGNING_REQUIRED: + if (transport->negotiate.security_mode & SMB2_NEGOTIATE_SIGNING_ENABLED) { + transport->signing.doing_signing = true; + } else { + composite_error(c, NT_STATUS_ACCESS_DENIED); + return; + } + break; + } + state->session = smb2_session_init(transport, global_loadparm, state, true); if (composite_nomem(state->session, c)) return; @@ -129,12 +158,24 @@ static void continue_socket(struct composite_context *creq) c->status = smbcli_sock_connect_recv(creq, state, &sock); if (!composite_is_ok(c)) return; - transport = smb2_transport_init(sock, state); + transport = smb2_transport_init(sock, state, &state->options); if (composite_nomem(transport, c)) return; ZERO_STRUCT(state->negprot); state->negprot.in.dialect_count = 2; - state->negprot.in.security_mode = 0; + switch (transport->options.signing) { + case SMB_SIGNING_OFF: + state->negprot.in.security_mode = 0; + break; + case SMB_SIGNING_SUPPORTED: + case SMB_SIGNING_AUTO: + state->negprot.in.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; + break; + case SMB_SIGNING_REQUIRED: + state->negprot.in.security_mode = + SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED; + break; + } state->negprot.in.capabilities = 0; unix_to_nt_time(&state->negprot.in.start_time, time(NULL)); dialects[0] = 0; @@ -178,7 +219,8 @@ struct composite_context *smb2_connect_send(TALLOC_CTX *mem_ctx, const char *share, struct resolve_context *resolve_ctx, struct cli_credentials *credentials, - struct event_context *ev) + struct event_context *ev, + struct smbcli_options *options) { struct composite_context *c; struct smb2_connect_state *state; @@ -193,6 +235,7 @@ struct composite_context *smb2_connect_send(TALLOC_CTX *mem_ctx, c->private_data = state; state->credentials = credentials; + state->options = *options; state->host = talloc_strdup(c, host); if (composite_nomem(state->host, c)) return c; state->share = talloc_strdup(c, share); @@ -232,10 +275,11 @@ NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx, struct resolve_context *resolve_ctx, struct cli_credentials *credentials, struct smb2_tree **tree, - struct event_context *ev) + struct event_context *ev, + struct smbcli_options *options) { struct composite_context *c = smb2_connect_send(mem_ctx, host, share, resolve_ctx, - credentials, ev); + credentials, ev, options); return smb2_connect_recv(c, mem_ctx, tree); } diff --git a/source4/libcli/smb2/notify.c b/source4/libcli/smb2/notify.c index 096d790a31..ef7341cae8 100644 --- a/source4/libcli/smb2/notify.c +++ b/source4/libcli/smb2/notify.c @@ -44,10 +44,10 @@ struct smb2_request *smb2_notify_send(struct smb2_tree *tree, struct smb2_notify SIVAL(req->out.body, 0x18, io->in.completion_filter); SIVAL(req->out.body, 0x1C, io->in.unknown); - old_timeout = req->transport->options.timeout; - req->transport->options.timeout = 0; + old_timeout = req->transport->options.request_timeout; + req->transport->options.request_timeout = 0; smb2_transport_send(req); - req->transport->options.timeout = old_timeout; + req->transport->options.request_timeout = old_timeout; return req; } diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c index 29af6652f2..54915d8535 100644 --- a/source4/libcli/smb2/session.c +++ b/source4/libcli/smb2/session.c @@ -164,8 +164,8 @@ static void session_request_handler(struct smb2_request *req) session_key_err = gensec_session_key(session->gensec, &session_key); if (NT_STATUS_IS_OK(session_key_err)) { - session->session_key = session_key; - } + session->transport->signing.session_key = session_key; + } } session->uid = state->io.out.uid; @@ -187,6 +187,14 @@ static void session_request_handler(struct smb2_request *req) return; } + if (session->transport->signing.doing_signing) { + c->status = smb2_start_signing(session->transport); + if (!NT_STATUS_IS_OK(c->status)) { + composite_error(c, c->status); + return; + } + } + composite_done(c); } @@ -208,7 +216,10 @@ struct composite_context *smb2_session_setup_spnego_send(struct smb2_session *se ZERO_STRUCT(state->io); state->io.in.vc_number = 0; - state->io.in.security_mode = 0; + if (session->transport->signing.doing_signing) { + state->io.in.security_mode = + SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED; + } state->io.in.capabilities = 0; state->io.in.channel = 0; state->io.in.previous_sessionid = 0; diff --git a/source4/libcli/smb2/signing.c b/source4/libcli/smb2/signing.c new file mode 100644 index 0000000000..01f7576134 --- /dev/null +++ b/source4/libcli/smb2/signing.c @@ -0,0 +1,165 @@ +/* + Unix SMB/CIFS implementation. + + SMB2 Signing Code + + Copyright (C) Andrew Tridgell 2008 + + 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 3 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, see . +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "heimdal/lib/hcrypto/sha.h" + +/* + NOTE: this code does not yet interoperate with the windows SMB2 + implementation. We are waiting on feedback on the docs to find out + why + */ + + +/* + setup signing on a transport + */ +NTSTATUS smb2_start_signing(struct smb2_transport *transport) +{ + if (transport->signing.session_key.length != 16) { + DEBUG(2,("Wrong session key length %u for SMB2 signing\n", + (unsigned)transport->signing.session_key.length)); + return NT_STATUS_ACCESS_DENIED; + } + + transport->signing.signing_started = true; + return NT_STATUS_OK; +} + +/* + sign an outgoing message + */ +NTSTATUS smb2_sign_message(struct smb2_request *req) +{ + struct smb2_request_buffer *buf = &req->out; + uint64_t session_id; + SHA256_CTX m; + uint8_t res[32]; + + if (!req->transport->signing.doing_signing || + !req->transport->signing.signing_started) { + return NT_STATUS_OK; + } + + if (buf->size < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) { + /* can't sign non-SMB2 messages */ + return NT_STATUS_OK; + } + + session_id = BVAL(buf->hdr, SMB2_HDR_SESSION_ID); + if (session_id == 0) { + /* we don't sign messages with a zero session_id. See + MS-SMB2 3.2.4.1.1 */ + return NT_STATUS_OK; + } + + if (req->transport->signing.session_key.length != 16) { + DEBUG(2,("Wrong session key length %u for SMB2 signing\n", + (unsigned)req->transport->signing.session_key.length)); + return NT_STATUS_ACCESS_DENIED; + } + + memset(buf->hdr + SMB2_HDR_SIGNATURE, 0, 16); + + SIVAL(buf->hdr, SMB2_HDR_FLAGS, IVAL(buf->hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED); + + ZERO_STRUCT(m); + SHA256_Init(&m); + SHA256_Update(&m, req->transport->signing.session_key.data, + req->transport->signing.session_key.length); + SHA256_Update(&m, buf->buffer+NBT_HDR_SIZE, buf->size-NBT_HDR_SIZE); + SHA256_Final(res, &m); + + DEBUG(5,("signed SMB2 message of size %u\n", (unsigned)buf->size - NBT_HDR_SIZE)); + + memcpy(buf->hdr + SMB2_HDR_SIGNATURE, res, 16); + + if (DEBUGLVL(5)) { + /* check our own signature */ + smb2_check_signature(req->transport, buf->buffer, buf->size); + } + + return NT_STATUS_OK; +} + +/* + check an incoming signature + */ +NTSTATUS smb2_check_signature(struct smb2_transport *transport, + uint8_t *buffer, uint_t length) +{ + uint64_t session_id; + SHA256_CTX m; + uint8_t res[SHA256_DIGEST_LENGTH]; + uint8_t sig[16]; + + if (!transport->signing.signing_started || + !transport->signing.doing_signing) { + return NT_STATUS_OK; + } + + if (length < NBT_HDR_SIZE + SMB2_HDR_SIGNATURE + 16) { + /* can't check non-SMB2 messages */ + return NT_STATUS_OK; + } + + session_id = BVAL(buffer+NBT_HDR_SIZE, SMB2_HDR_SESSION_ID); + if (session_id == 0) { + /* don't sign messages with a zero session_id. See + MS-SMB2 3.2.4.1.1 */ + return NT_STATUS_OK; + } + + if (transport->signing.session_key.length == 0) { + /* we don't have the session key yet */ + return NT_STATUS_OK; + } + + if (transport->signing.session_key.length != 16) { + DEBUG(2,("Wrong session key length %u for SMB2 signing\n", + (unsigned)transport->signing.session_key.length)); + return NT_STATUS_ACCESS_DENIED; + } + + memcpy(sig, buffer+NBT_HDR_SIZE+SMB2_HDR_SIGNATURE, 16); + + memset(buffer + NBT_HDR_SIZE + SMB2_HDR_SIGNATURE, 0, 16); + + ZERO_STRUCT(m); + SHA256_Init(&m); + SHA256_Update(&m, transport->signing.session_key.data, 16); + SHA256_Update(&m, buffer+NBT_HDR_SIZE, length-NBT_HDR_SIZE); + SHA256_Final(res, &m); + + memcpy(buffer+NBT_HDR_SIZE+SMB2_HDR_SIGNATURE, sig, 16); + + if (memcmp(res, sig, 16) != 0) { + DEBUG(0,("Bad SMB2 signature for message of size %u\n", length)); + dump_data(0, sig, 16); + dump_data(0, res, 16); + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h index b55da05e21..0903509528 100644 --- a/source4/libcli/smb2/smb2.h +++ b/source4/libcli/smb2/smb2.h @@ -23,20 +23,24 @@ #define __LIBCLI_SMB2_SMB2_H__ #include "libcli/raw/request.h" +#include "libcli/raw/libcliraw.h" struct smb2_handle; -struct smb2_options { - uint32_t timeout; +struct smb2_signing_context { + bool doing_signing; + bool signing_started; + DATA_BLOB session_key; }; /* - information returned from the negotiate response + information returned from the negotiate process */ struct smb2_negotiate { DATA_BLOB secblob; NTTIME system_time; NTTIME server_start_time; + uint16_t security_mode; }; /* this is the context for the smb2 transport layer */ @@ -44,7 +48,6 @@ struct smb2_transport { /* socket level info */ struct smbcli_socket *socket; - struct smb2_options options; struct smb2_negotiate negotiate; /* next seqnum to allocate */ @@ -74,6 +77,9 @@ struct smb2_transport { /* private data passed to the oplock handler */ void *private_data; } oplock; + + struct smbcli_options options; + struct smb2_signing_context signing; }; @@ -92,7 +98,6 @@ struct smb2_session { struct smb2_transport *transport; struct gensec_security *gensec; uint64_t uid; - DATA_BLOB session_key; }; @@ -193,6 +198,13 @@ struct smb2_request { #define SMB2_HDR_SIGNATURE 0x30 /* 16 bytes */ #define SMB2_HDR_BODY 0x40 +/* header flags */ +#define SMB2_HDR_FLAG_REDIRECT 0x01 +#define SMB2_HDR_FLAG_ASYNC 0x02 +#define SMB2_HDR_FLAG_CHAINED 0x04 +#define SMB2_HDR_FLAG_SIGNED 0x08 +#define SMB2_HDR_FLAG_DFS 0x10000000 + /* SMB2 opcodes */ #define SMB2_OP_NEGPROT 0x00 #define SMB2_OP_SESSSETUP 0x01 diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c index 8eb60a06f1..561b6e528e 100644 --- a/source4/libcli/smb2/transport.c +++ b/source4/libcli/smb2/transport.c @@ -74,7 +74,8 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob); create a transport structure based on an established socket */ struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock, - TALLOC_CTX *parent_ctx) + TALLOC_CTX *parent_ctx, + struct smbcli_options *options) { struct smb2_transport *transport; @@ -82,6 +83,7 @@ struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock, if (!transport) return NULL; transport->socket = talloc_steal(transport, sock); + transport->options = *options; /* setup the stream -> packet parser */ transport->packet = packet_init(transport); @@ -112,8 +114,6 @@ struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock, talloc_set_destructor(transport, transport_destructor); - transport->options.timeout = 30; - return transport; } @@ -140,27 +140,24 @@ void smb2_transport_dead(struct smb2_transport *transport, NTSTATUS status) } } -static bool smb2_handle_oplock_break(struct smb2_transport *transport, - const DATA_BLOB *blob) +static NTSTATUS smb2_handle_oplock_break(struct smb2_transport *transport, + const DATA_BLOB *blob) { uint8_t *hdr; uint16_t opcode; - uint64_t seqnum; hdr = blob->data+NBT_HDR_SIZE; if (blob->length < (SMB2_MIN_SIZE+0x18)) { DEBUG(1,("Discarding smb2 oplock reply of size %u\n", - blob->length)); - return false; + (unsigned)blob->length)); + return NT_STATUS_INVALID_NETWORK_RESPONSE; } opcode = SVAL(hdr, SMB2_HDR_OPCODE); - seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID); - if ((opcode != SMB2_OP_BREAK) || - (seqnum != UINT64_MAX)) { - return false; + if (opcode != SMB2_OP_BREAK) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; } if (transport->oplock.handler) { @@ -173,9 +170,11 @@ static bool smb2_handle_oplock_break(struct smb2_transport *transport, transport->oplock.handler(transport, &h, level, transport->oplock.private_data); + } else { + DEBUG(5,("Got SMB2 oplock break with no handler\n")); } - return true; + return NT_STATUS_OK; } /* @@ -194,6 +193,7 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob) uint16_t buffer_code; uint32_t dynamic_size; uint32_t i; + NTSTATUS status; buffer = blob.data; len = blob.length; @@ -205,14 +205,20 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob) goto error; } - if (smb2_handle_oplock_break(transport, &blob)) { + status = smb2_check_signature(transport, buffer, len); + if (!NT_STATUS_IS_OK(status)) { talloc_free(buffer); - return NT_STATUS_OK; + return status; } - + flags = IVAL(hdr, SMB2_HDR_FLAGS); seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID); + /* see MS-SMB2 3.2.5.19 */ + if (seqnum == UINT64_MAX) { + return smb2_handle_oplock_break(transport, &blob); + } + /* match the incoming request against the list of pending requests */ for (req=transport->pending_recv; req; req=req->next) { if (req->seqnum == seqnum) break; @@ -340,6 +346,13 @@ void smb2_transport_send(struct smb2_request *req) return; } + status = smb2_sign_message(req); + if (!NT_STATUS_IS_OK(status)) { + req->state = SMB2_REQUEST_ERROR; + req->status = status; + return; + } + blob = data_blob_const(req->out.buffer, req->out.size); status = packet_send(req->transport->packet, blob); if (!NT_STATUS_IS_OK(status)) { @@ -352,9 +365,9 @@ void smb2_transport_send(struct smb2_request *req) DLIST_ADD(req->transport->pending_recv, req); /* add a timeout */ - if (req->transport->options.timeout) { + if (req->transport->options.request_timeout) { event_add_timed(req->transport->socket->event.ctx, req, - timeval_current_ofs(req->transport->options.timeout, 0), + timeval_current_ofs(req->transport->options.request_timeout, 0), smb2_timeout_handler, req); } diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c index a22cad9a4a..318b8fe36d 100644 --- a/source4/librpc/rpc/dcerpc_connect.c +++ b/source4/librpc/rpc/dcerpc_connect.c @@ -218,6 +218,7 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send( struct composite_context *c; struct pipe_np_smb2_state *s; struct composite_context *conn_req; + struct smbcli_options options; /* composite context allocation and setup */ c = composite_create(mem_ctx, io->pipe->conn->event_ctx); @@ -240,11 +241,14 @@ static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send( cli_credentials_guess(s->io.creds, lp_ctx); } + lp_smbcli_options(lp_ctx, &options); + /* send smb2 connect request */ conn_req = smb2_connect_send(mem_ctx, s->io.binding->host, "IPC$", s->io.resolve_ctx, s->io.creds, - c->event_ctx); + c->event_ctx, + &options); composite_continue(c, conn_req, continue_smb2_connect, c); return c; } diff --git a/source4/librpc/rpc/dcerpc_smb2.c b/source4/librpc/rpc/dcerpc_smb2.c index 4767165fba..211015a4cf 100644 --- a/source4/librpc/rpc/dcerpc_smb2.c +++ b/source4/librpc/rpc/dcerpc_smb2.c @@ -376,7 +376,7 @@ static NTSTATUS smb2_session_key(struct dcerpc_connection *c, DATA_BLOB *session { struct smb2_private *smb = talloc_get_type(c->transport.private_data, struct smb2_private); - *session_key = smb->tree->session->session_key; + *session_key = smb->tree->session->transport->signing.session_key; if (session_key->data == NULL) { return NT_STATUS_NO_USER_SESSION_KEY; } diff --git a/source4/ntvfs/smb2/vfs_smb2.c b/source4/ntvfs/smb2/vfs_smb2.c index cc09daf83f..68b475a084 100644 --- a/source4/ntvfs/smb2/vfs_smb2.c +++ b/source4/ntvfs/smb2/vfs_smb2.c @@ -162,9 +162,9 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, struct composite_context *creq; struct share_config *scfg = ntvfs->ctx->config; struct smb2_tree *tree; - struct cli_credentials *credentials; bool machine_account; + struct smbcli_options options; /* Here we need to determine which server to connect to. * For now we use parametric options, type cifs. @@ -224,10 +224,12 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_PARAMETER; } + lp_smbcli_options(ntvfs->ctx->lp_ctx, &options); + creq = smb2_connect_send(private, host, remote_share, lp_resolve_context(ntvfs->ctx->lp_ctx), credentials, - ntvfs->ctx->event_ctx); + ntvfs->ctx->event_ctx, &options); status = smb2_connect_recv(creq, private, &tree); NT_STATUS_NOT_OK_RETURN(status); diff --git a/source4/torture/gentest.c b/source4/torture/gentest.c index fd6bd5cc0a..07d394fad6 100644 --- a/source4/torture/gentest.c +++ b/source4/torture/gentest.c @@ -213,6 +213,9 @@ static bool connect_servers(struct event_context *ev, for (i=0;iusername, j); @@ -226,10 +229,8 @@ static bool connect_servers(struct event_context *ev, lp_resolve_context(lp_ctx), servers[i].credentials, &servers[i].smb2_tree[j], - ev); + ev, &smb_options); } else { - struct smbcli_options smb_options; - lp_smbcli_options(lp_ctx, &smb_options); status = smbcli_tree_full_connection(NULL, &servers[i].smb_tree[j], servers[i].server_name, diff --git a/source4/torture/smb2/read.c b/source4/torture/smb2/read.c index 1f306028f6..548bd1ce61 100644 --- a/source4/torture/smb2/read.c +++ b/source4/torture/smb2/read.c @@ -180,7 +180,6 @@ static bool test_read_dir(struct torture_context *torture, struct smb2_tree *tre bool ret = true; NTSTATUS status; struct smb2_handle h; - uint8_t buf[100]; struct smb2_read rd; TALLOC_CTX *tmp_ctx = talloc_new(tree); diff --git a/source4/torture/smb2/scan.c b/source4/torture/smb2/scan.c index 889d343a49..1ce796be4d 100644 --- a/source4/torture/smb2/scan.c +++ b/source4/torture/smb2/scan.c @@ -203,17 +203,20 @@ bool torture_smb2_scan(struct torture_context *torture) NTSTATUS status; int opcode; struct smb2_request *req; + struct smbcli_options options; + + lp_smbcli_options(torture->lp_ctx, &options); status = smb2_connect(mem_ctx, host, share, lp_resolve_context(torture->lp_ctx), credentials, &tree, - torture->ev); + torture->ev, &options); if (!NT_STATUS_IS_OK(status)) { printf("Connection failed - %s\n", nt_errstr(status)); return false; } - tree->session->transport->options.timeout = 3; + tree->session->transport->options.request_timeout = 3; for (opcode=0;opcode<1000;opcode++) { req = smb2_request_init_tree(tree, opcode, 2, false, 0); @@ -224,12 +227,12 @@ bool torture_smb2_scan(struct torture_context *torture) status = smb2_connect(mem_ctx, host, share, lp_resolve_context(torture->lp_ctx), credentials, &tree, - torture->ev); + torture->ev, &options); if (!NT_STATUS_IS_OK(status)) { printf("Connection failed - %s\n", nt_errstr(status)); return false; } - tree->session->transport->options.timeout = 3; + tree->session->transport->options.request_timeout = 3; } else { status = smb2_request_destroy(req); printf("active opcode %4d gave status %s\n", opcode, nt_errstr(status)); diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c index af4f345104..3a437acbab 100644 --- a/source4/torture/smb2/util.c +++ b/source4/torture/smb2/util.c @@ -270,11 +270,14 @@ bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tr const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = cmdline_credentials; + struct smbcli_options options; + + lp_smbcli_options(tctx->lp_ctx, &options); status = smb2_connect(tctx, host, share, lp_resolve_context(tctx->lp_ctx), credentials, tree, - tctx->ev); + tctx->ev, &options); if (!NT_STATUS_IS_OK(status)) { printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n", host, share, nt_errstr(status)); -- cgit From 9c1519c065a4411b3eb37e8d7738269238950227 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 30 May 2008 17:23:56 +1000 Subject: Skip the samba4.samdb.python test. I'll need to talk to jelmer about why this doesn't work... Andrew Bartlett (This used to be commit 75122e88e53aaa9930af85887e939fb329f51e2d) --- source4/samba4-skip | 1 + 1 file changed, 1 insertion(+) (limited to 'source4') diff --git a/source4/samba4-skip b/source4/samba4-skip index 0b2d852284..79c69a5ffd 100644 --- a/source4/samba4-skip +++ b/source4/samba4-skip @@ -50,3 +50,4 @@ nss.test # Fails samba4.samba3sam.python # Conversion from EJS not yet finished raw.offline # Samba 4 doesn't have much offline support yet winreg* #Does not authenticate against the target server +^samba4.samdb.python #Not working yet -- cgit