From af0d863ce78a4afb1e2add837613a665d54031eb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 14:10:13 +0100 Subject: [PATCH 01/34] pvfs_oplock: move pvfs_oplock_release() parts into a helper function metze (This used to be commit 2b8934e4ab2dd9673928a6c9a291aedac1ebaa95) --- source4/ntvfs/posix/pvfs_oplock.c | 99 +++++++++++++++++-------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c index cf30ddbc59b..b830ad2adc6 100644 --- a/source4/ntvfs/posix/pvfs_oplock.c +++ b/source4/ntvfs/posix/pvfs_oplock.c @@ -32,6 +32,58 @@ struct pvfs_oplock { struct messaging_context *msg_ctx; }; +static NTSTATUS pvfs_oplock_release_internal(struct pvfs_file_handle *h, + uint8_t oplock_break) +{ + struct odb_lock *olck; + NTSTATUS status; + + if (h->fd == -1) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + if (!h->have_opendb_entry) { + return NT_STATUS_FOOBAR; + } + + if (!h->oplock) { + return NT_STATUS_FOOBAR; + } + + olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); + if (olck == NULL) { + DEBUG(0,("Unable to lock opendb for oplock update\n")); + return NT_STATUS_FOOBAR; + } + + if (oplock_break == OPLOCK_BREAK_TO_NONE) { + h->oplock->level = OPLOCK_NONE; + } else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) { + h->oplock->level = OPLOCK_LEVEL_II; + } else { + /* fallback to level II in case of a invalid value */ + DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break)); + h->oplock->level = OPLOCK_LEVEL_II; + } + status = odb_update_oplock(olck, h, h->oplock->level); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable to update oplock level for '%s' - %s\n", + h->name->full_name, nt_errstr(status))); + talloc_free(olck); + return status; + } + + talloc_free(olck); + + /* after a break to none, we no longer have an oplock attached */ + if (h->oplock->level == OPLOCK_NONE) { + talloc_free(h->oplock); + h->oplock = NULL; + } + + return NT_STATUS_OK; +} + /* receive oplock breaks and forward them to the client */ @@ -140,8 +192,6 @@ NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs, { struct pvfs_state *pvfs = ntvfs->private_data; struct pvfs_file *f; - struct pvfs_file_handle *h; - struct odb_lock *olck; uint8_t oplock_break; NTSTATUS status; @@ -150,52 +200,15 @@ NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - h = f->handle; - - if (h->fd == -1) { - return NT_STATUS_FILE_IS_A_DIRECTORY; - } - - if (!h->have_opendb_entry) { - return NT_STATUS_FOOBAR; - } - - if (!h->oplock) { - return NT_STATUS_FOOBAR; - } - - olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); - if (olck == NULL) { - DEBUG(0,("Unable to lock opendb for oplock update\n")); - return NT_STATUS_FOOBAR; - } - oplock_break = (lck->lockx.in.mode >> 8) & 0xFF; - if (oplock_break == OPLOCK_BREAK_TO_NONE) { - h->oplock->level = OPLOCK_NONE; - } else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) { - h->oplock->level = OPLOCK_LEVEL_II; - } else { - /* fallback to level II in case of a invalid value */ - DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break)); - h->oplock->level = OPLOCK_LEVEL_II; - } - status = odb_update_oplock(olck, h, h->oplock->level); + + status = pvfs_oplock_release_internal(f->handle, oplock_break); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Unable to update oplock level for '%s' - %s\n", - h->name->full_name, nt_errstr(status))); - talloc_free(olck); + DEBUG(0,("%s: failed to release the oplock[0x%02X]: %s\n", + __FUNCTION__, oplock_break, nt_errstr(status))); return status; } - talloc_free(olck); - - /* after a break to none, we no longer have an oplock attached */ - if (h->oplock->level == OPLOCK_NONE) { - talloc_free(h->oplock); - h->oplock = NULL; - } - return NT_STATUS_OK; } From 1f5301c1d2182993d8f8cdaa65763408faff080d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 14:11:53 +0100 Subject: [PATCH 02/34] pvfs_oplock: only a break level2 oplocks... It seems that I've tested this in the wrong way before. metze (This used to be commit 21772fa33d772a9df6ff04a0ed1b0d8f4f533295) --- source4/ntvfs/posix/pvfs_oplock.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c index b830ad2adc6..3f581e54430 100644 --- a/source4/ntvfs/posix/pvfs_oplock.c +++ b/source4/ntvfs/posix/pvfs_oplock.c @@ -218,7 +218,7 @@ NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f) struct odb_lock *olck; NTSTATUS status; - if (h->oplock && h->oplock->level == OPLOCK_EXCLUSIVE) { + if (h->oplock && h->oplock->level != OPLOCK_LEVEL_II) { return NT_STATUS_OK; } @@ -228,16 +228,6 @@ NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f) return NT_STATUS_FOOBAR; } - if (h->oplock && h->oplock->level == OPLOCK_BATCH) { - status = odb_update_oplock(olck, h, OPLOCK_LEVEL_II); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Unable to update oplock level for '%s' - %s\n", - h->name->full_name, nt_errstr(status))); - talloc_free(olck); - return status; - } - } - status = odb_break_oplocks(olck); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to break level2 oplocks to none for '%s' - %s\n", From eb26c896a2523c8d635b5b34c21a0c43e20d10b6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 14:16:17 +0100 Subject: [PATCH 03/34] pvfs_oplock: auto release oplocks after a timeout Remember that we sent an oplock break to a client and don't resend. If the filesystem layer tries to send a new break and the client has not released after a former oplock break after the timeout interval, we need to auto release the oplock. metze (This used to be commit bfb0888578677856b2b6b72471f542d0d5d7b838) --- source4/ntvfs/posix/pvfs_oplock.c | 67 ++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c index 3f581e54430..dfa3697af7b 100644 --- a/source4/ntvfs/posix/pvfs_oplock.c +++ b/source4/ntvfs/posix/pvfs_oplock.c @@ -22,6 +22,7 @@ #include "includes.h" #include "lib/messaging/messaging.h" #include "lib/messaging/irpc.h" +#include "system/time.h" #include "vfs_posix.h" @@ -29,6 +30,8 @@ struct pvfs_oplock { struct pvfs_file_handle *handle; struct pvfs_file *file; uint32_t level; + struct timeval break_to_level_II; + struct timeval break_to_none; struct messaging_context *msg_ctx; }; @@ -93,13 +96,65 @@ static void pvfs_oplock_break(struct pvfs_oplock *opl, uint8_t level) struct pvfs_file *f = opl->file; struct pvfs_file_handle *h = opl->handle; struct pvfs_state *pvfs = h->pvfs; + struct timeval cur = timeval_current(); + struct timeval *last = NULL; + struct timeval end; - DEBUG(10,("pvfs_oplock_break: sending oplock break level %d for '%s' %p\n", - level, h->name->original_name, h)); - status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level); + switch (level) { + case OPLOCK_BREAK_TO_LEVEL_II: + last = &opl->break_to_level_II; + break; + case OPLOCK_BREAK_TO_NONE: + last = &opl->break_to_none; + break; + } + + if (!last) { + DEBUG(0,("%s: got unexpected level[0x%02X]\n", + __FUNCTION__, level)); + return; + } + + if (timeval_is_zero(last)) { + /* + * this is the first break we for this level + * remember the time + */ + *last = cur; + + DEBUG(0,("%s: sending oplock break level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("%s: sending oplock break failed: %s\n", + __FUNCTION__, nt_errstr(status))); + } + return; + } + + end = timeval_add(last, pvfs->oplock_break_timeout, 0); + + if (timeval_compare(&cur, &end) < 0) { + /* + * If it's not expired just ignore the break + * as we already sent the break request to the client + */ + DEBUG(0,("%s: do not resend oplock break level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + return; + } + + /* + * If the client did not send a release within the + * oplock break timeout time frame we auto release + * the oplock + */ + DEBUG(0,("%s: auto release oplock level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + status = pvfs_oplock_release_internal(h, level); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("pvfs_oplock_break: sending oplock break failed: %s\n", - nt_errstr(status))); + DEBUG(0,("%s: failed to auto release the oplock[0x%02X]: %s\n", + __FUNCTION__, level, nt_errstr(status))); } } @@ -165,7 +220,7 @@ NTSTATUS pvfs_setup_oplock(struct pvfs_file *f, uint32_t oplock_granted) return NT_STATUS_OK; } - opl = talloc(f->handle, struct pvfs_oplock); + opl = talloc_zero(f->handle, struct pvfs_oplock); NT_STATUS_HAVE_NO_MEMORY(opl); opl->handle = f->handle; From 13764eb02d5c09285bd2c4a0460dff279d80130d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 12:15:32 +0100 Subject: [PATCH 04/34] RAW-OPLOCK: add BATCH21: a self write with an oplock doesn't break it metze (This used to be commit a5476ee41c140123db160b2e36c8c7084619a738) --- source4/torture/raw/oplock.c | 70 ++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index 7ac88c09968..aab8f6fdfba 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -2204,6 +2204,75 @@ done: return ret; } +static bool test_raw_oplock_batch21(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch21.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + struct smb_echo e; + uint16_t fnum=0; + char c = 0; + ssize_t wr; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + /* + with a batch oplock we get a break + */ + torture_comment(tctx, "open with batch oplock\n"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + torture_comment(tctx, "writing should not generate a break\n"); + wr = smbcli_write(cli1->tree, fnum, 0, &c, 0, 1); + CHECK_VAL(wr, 1); + CHECK_STATUS(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_OK); + + ZERO_STRUCT(e); + e.in.repeat_count = 1; + status = smb_raw_echo(cli1->transport, &e); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + + CHECK_VAL(break_info.count, 0); + + smbcli_close(cli1->tree, fnum); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + /* basic testing of oplocks */ @@ -2237,6 +2306,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) torture_suite_add_2smb_test(suite, "BATCH18", test_raw_oplock_batch18); torture_suite_add_2smb_test(suite, "BATCH19", test_raw_oplock_batch19); torture_suite_add_2smb_test(suite, "BATCH20", test_raw_oplock_batch20); + torture_suite_add_2smb_test(suite, "BATCH21", test_raw_oplock_batch21); return suite; } From 8ff6647d29cac4c592e27aa8c9c1f6b6834576c4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 14:08:32 +0100 Subject: [PATCH 05/34] RAW-OPLOCK: add BATCH22 and test the behavior of oplock break timeouts metze (This used to be commit c459885898c9912df1ae5afff4fef2ff809dc15e) --- source4/torture/raw/oplock.c | 118 +++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index aab8f6fdfba..8a7489c84e8 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -32,6 +32,13 @@ ret = false; \ }} while (0) +#define CHECK_RANGE(v, min, max) do { \ + if ((v) < (min) || (v) > (max)) { \ + torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got %d - should be between %d and %d\n", \ + __location__, #v, (int)v, (int)min, (int)max); \ + ret = false; \ + }} while (0) + #define CHECK_STRMATCH(v, correct) do { \ if (!v || strstr((v),(correct)) == NULL) { \ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got '%s' - should be '%s'\n", \ @@ -92,6 +99,21 @@ static bool oplock_handler_ack_to_none(struct smbcli_transport *transport, return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE); } +/* + a handler function for oplock break requests. Let it timeout +*/ +static bool oplock_handler_timeout(struct smbcli_transport *transport, + uint16_t tid, uint16_t fnum, + uint8_t level, void *private) +{ + break_info.fnum = fnum; + break_info.level = level; + break_info.count++; + + printf("Let oplock break timeout\n"); + return true; +} + static void oplock_handler_close_recv(struct smbcli_request *req) { NTSTATUS status; @@ -2273,6 +2295,101 @@ done: return ret; } +static bool test_raw_oplock_batch22(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch22.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + union smb_unlink unl; + uint16_t fnum=0, fnum2=0; + char c = 0; + struct timeval tv; + int timeout = torture_setting_int(tctx, "oplocktimeout", 30); + int te; + ssize_t wr; + + if (torture_setting_bool(tctx, "samba3", false)) { + torture_skip(tctx, "BACHT22 disabled against samba3\n"); + } + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + /* + with a batch oplock we get a break + */ + torture_comment(tctx, "open with batch oplock\n"); + ZERO_STRUCT(break_info); + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE| + NTCREATEX_SHARE_ACCESS_DELETE; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + torture_comment(tctx, "a 2nd open shoud not succeed after the oplock break timeout\n"); + tv = timeval_current(); + smbcli_oplock_handler(cli1->transport, oplock_handler_timeout, cli1->tree); + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION); + te = (int)timeval_elapsed(&tv); + CHECK_RANGE(te, timeout - 1, timeout + 15); + + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.fnum, fnum); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + CHECK_VAL(break_info.failures, 0); + ZERO_STRUCT(break_info); + + torture_comment(tctx, "a 2nd open shoud succeed after the oplock release without break\n"); + tv = timeval_current(); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); + te = (int)timeval_elapsed(&tv); + /* it should come in without delay */ + CHECK_RANGE(te+1, 0, timeout); + fnum2 = io.ntcreatex.out.file.fnum; + + CHECK_VAL(break_info.count, 0); + + smbcli_close(cli1->tree, fnum); + smbcli_close(cli1->tree, fnum2); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + /* basic testing of oplocks */ @@ -2307,6 +2424,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) torture_suite_add_2smb_test(suite, "BATCH19", test_raw_oplock_batch19); torture_suite_add_2smb_test(suite, "BATCH20", test_raw_oplock_batch20); torture_suite_add_2smb_test(suite, "BATCH21", test_raw_oplock_batch21); + torture_suite_add_2smb_test(suite, "BATCH22", test_raw_oplock_batch22); return suite; } From cdafdaa0d9da5f63a9e4962df4ad47b3da017508 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 14:24:27 +0100 Subject: [PATCH 06/34] selftest: use the same oplocktimeout for smbtorture as for smbd metze (This used to be commit 18e27aef7be9b21f65f72ab4c656778ce0c23953) --- source4/selftest/samba4_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/selftest/samba4_tests.sh b/source4/selftest/samba4_tests.sh index bea41735556..8102095958c 100755 --- a/source4/selftest/samba4_tests.sh +++ b/source4/selftest/samba4_tests.sh @@ -217,7 +217,7 @@ done plantest "rpc.echo on ncacn_np over smb2" dc $smb4torture ncacn_np:"\$SERVER[smb2]" -U"\$USERNAME"%"\$PASSWORD" -W \$DOMAIN RPC-ECHO "$*" # Tests against the NTVFS POSIX backend -NTVFSARGS="--option=torture:sharedelay=100000" +NTVFSARGS="--option=torture:sharedelay=100000 --option=torture:oplocktimeout=3" smb2=`$smb4torture --list | grep "^SMB2-" | xargs` raw=`$smb4torture --list | grep "^RAW-" | xargs` base=`$smb4torture --list | grep "^BASE-" | xargs` From 0e50fb5e917117de22c5b3c32865d8a40285e362 Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Thu, 6 Mar 2008 00:03:18 -0600 Subject: [PATCH 07/34] ldb_wrap: Debug at derived samba_level, not the level of the ldb debug enum. (This used to be commit eb9a7c3b3a7f113ff58e2ebea9886f997da4e085) --- source4/lib/ldb_wrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/lib/ldb_wrap.c b/source4/lib/ldb_wrap.c index 63049b06fcc..71ba37b4797 100644 --- a/source4/lib/ldb_wrap.c +++ b/source4/lib/ldb_wrap.c @@ -63,7 +63,7 @@ static void ldb_wrap_debug(void *context, enum ldb_debug_level level, }; vasprintf(&s, fmt, ap); if (!s) return; - DEBUG(level, ("ldb: %s\n", s)); + DEBUG(samba_level, ("ldb: %s\n", s)); free(s); } From 7e0ef3fd0ef4dba827f331cbe43fa0524be91130 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 6 Mar 2008 21:55:26 +1100 Subject: [PATCH 08/34] Make Samba4 pass the NET-API-BECOMEDC test against Win2k3 (again). To make Samba4, using the python provision system, pass this test required some major rework. Untested code is broken code, and some of the refactoring for a seperate provision test (which also now passes) broke things. Similarly, the iconv work has compiled, but these codepaths have never been run (NULL pointer de-reference). In working to use a local, rather than global, loadparm context, and to support using a target directory, a few things needed to be reworked, particularly around path handling. Andrew Bartlett (This used to be commit 1169e8d7bee20477b0efbfea3534ac63c83fb3d6) --- source4/dsdb/samdb/ldb_modules/schema_fsmo.c | 3 +- source4/dsdb/schema/schema_init.c | 19 +- source4/samba4-knownfail | 1 - source4/scripting/python/samba/provision.py | 222 +++++++++----- source4/setup/provision | 26 +- source4/setup/provision.smb.conf.dc | 2 + source4/setup/provision.smb.conf.member | 2 + source4/setup/provision.smb.conf.standalone | 2 + source4/torture/libnet/libnet_BecomeDC.c | 111 ++++--- source4/torture/local/torture.c | 12 +- source4/torture/util.h | 10 +- source4/torture/util_provision.c | 305 +++---------------- 12 files changed, 278 insertions(+), 437 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c index 729fd15202c..8ceeba98048 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c +++ b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c @@ -30,6 +30,7 @@ #include "librpc/gen_ndr/ndr_drsuapi.h" #include "librpc/gen_ndr/ndr_drsblobs.h" #include "lib/util/dlinklist.h" +#include "param/param.h" static int schema_fsmo_init(struct ldb_module *module) { @@ -78,7 +79,7 @@ static int schema_fsmo_init(struct ldb_module *module) } module->private_data = schema_fsmo; - schema = talloc_zero(mem_ctx, struct dsdb_schema); + schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm"))); if (!schema) { ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index 30d0adeda73..c046cb597f5 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -29,6 +29,18 @@ #include "librpc/gen_ndr/ndr_drsblobs.h" #include "param/param.h" +struct dsdb_schema *dsdb_new_schema(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience) +{ + struct dsdb_schema *schema = talloc_zero(mem_ctx, struct dsdb_schema); + if (!schema) { + return NULL; + } + + schema->iconv_convenience = iconv_convenience; + return schema; +} + + WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr) { uint32_t i,j; @@ -1150,12 +1162,7 @@ WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf goto nomem; } - schema = talloc_zero(mem_ctx, struct dsdb_schema); - if (!schema) { - goto nomem; - } - - schema->iconv_convenience = lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")); + schema = dsdb_new_schema(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm"))); /* * load the prefixMap attribute from pf diff --git a/source4/samba4-knownfail b/source4/samba4-knownfail index 66565ca6fc9..496af316ec5 100644 --- a/source4/samba4-knownfail +++ b/source4/samba4-knownfail @@ -33,4 +33,3 @@ rpc.netlogon.*.GetTrustPasswords base.charset.*.Testing partial surrogate .*net.api.delshare.* # DelShare isn't implemented yet rap.*netservergetinfo -local.torture.provision diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ea2feb981bb..ab8c51595f1 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -32,6 +32,7 @@ from socket import gethostname, gethostbyname import param import registry import samba +from auth import system_session from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted from samba.samdb import SamDB import security @@ -65,6 +66,7 @@ class ProvisionPaths: self.dns_keytab = None self.dns = None self.winsdb = None + self.private_dir = None def check_install(lp, session_info, credentials): @@ -197,20 +199,20 @@ def provision_paths_from_lp(lp, dnsdomain): :param dnsdomain: DNS Domain name """ paths = ProvisionPaths() - private_dir = lp.get("private dir") + paths.private_dir = lp.get("private dir") paths.keytab = "secrets.keytab" paths.dns_keytab = "dns.keytab" - paths.shareconf = os.path.join(private_dir, "share.ldb") - paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") - paths.idmapdb = os.path.join(private_dir, lp.get("idmap database") or "idmap.ldb") - paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") - paths.templates = os.path.join(private_dir, "templates.ldb") - paths.dns = os.path.join(private_dir, dnsdomain + ".zone") - paths.winsdb = os.path.join(private_dir, "wins.ldb") - paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") - paths.smbconf = os.path.join(private_dir, "smb.conf") - paths.phpldapadminconfig = os.path.join(private_dir, + paths.shareconf = os.path.join(paths.private_dir, "share.ldb") + paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb") + paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb") + paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb") + paths.templates = os.path.join(paths.private_dir, "templates.ldb") + paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone") + paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") + paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") + paths.smbconf = os.path.join(paths.private_dir, "smb.conf") + paths.phpldapadminconfig = os.path.join(paths.private_dir, "phpldapadmin-config.php") paths.hklm = "hklm.ldb" paths.hkcr = "hkcr.ldb" @@ -588,7 +590,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb = SamDB(path, session_info=session_info, credentials=credentials, lp=lp) samdb.set_domain_sid(domainsid) - if lp.get("server role") == "domain controller": + if serverrole == "domain controller": samdb.set_invocation_id(invocationid) load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename) @@ -699,7 +701,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "KRBTGTPASS_B64": b64encode(krbtgtpass), }) - if lp.get("server role") == "domain controller": + if serverrole == "domain controller": message("Setting up self join") setup_self_join(samdb, configdn=configdn, schemadn=schemadn, domaindn=domaindn, invocationid=invocationid, @@ -725,13 +727,14 @@ FILL_FULL = "FULL" FILL_NT4SYNC = "NT4SYNC" FILL_DRS = "DRS" -def provision(lp, setup_dir, message, paths, session_info, - credentials, samdb_fill=FILL_FULL, realm=None, rootdn=None, +def provision(setup_dir, message, session_info, + credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, domain=None, hostname=None, hostip=None, domainsid=None, hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, invocationid=None, machinepass=None, dnspass=None, root=None, nobody=None, nogroup=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, + wheel=None, backup=None, aci=None, serverrole=None, ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): """Provision samba4 @@ -768,28 +771,6 @@ def provision(lp, setup_dir, message, paths, session_info, backup = findnss(grp.getgrnam, ["backup", "wheel", "root", "staff"])[0] if aci is None: aci = "# no aci for local ldb" - if serverrole is None: - serverrole = lp.get("server role") - assert serverrole in ("domain controller", "member server") - if invocationid is None and serverrole == "domain controller": - invocationid = uuid.random() - - if realm is None: - realm = lp.get("realm") - - if lp.get("realm").upper() != realm.upper(): - raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % - (lp.get("realm"), realm)) - - ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") - - if ldap_backend == "ldapi": - # provision-backend will set this path suggested slapd command line / fedorads.inf - ldap_backend = "ldapi://" % urllib.quote(os.path.join(lp.get("private dir"), "ldap", "ldapi"), safe="") - - assert realm is not None - realm = realm.upper() - if hostname is None: hostname = gethostname().split(".")[0].lower() @@ -800,9 +781,84 @@ def provision(lp, setup_dir, message, paths, session_info, if not valid_netbios_name(netbiosname): raise InvalidNetbiosName(netbiosname) + if targetdir is not None: + if not os.path.exists(targetdir): + os.mkdir(targetdir) + if not os.path.exists(os.path.join(targetdir, "etc")): + os.mkdir(os.path.join(targetdir, "etc")) + + if smbconf is None: + smbconf = os.path.join(targetdir, os.path.join("etc", "smb.conf")) + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(smbconf): + message("Setting up smb.conf") + assert serverrole is not None + if serverrole == "domain controller": + smbconfsuffix = "dc" + elif serverrole == "member server": + smbconfsuffix = "member" + + assert domain is not None + assert realm is not None + + default_lp = param.LoadParm() + #Load non-existant file + default_lp.load(smbconf) + + if targetdir is not None: + privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private")) + lockdir_line = "lock dir = " + os.path.abspath(targetdir) + + default_lp.set("lock dir", os.path.abspath(targetdir)) + + sysvol = os.path.join(default_lp.get("lock dir"), "sysvol") + netlogon = os.path.join(os.path.join(sysvol, "scripts")) + + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), + smbconf, { + "HOSTNAME": hostname, + "DOMAIN_CONF": domain, + "REALM_CONF": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": netlogon, + "SYSVOLPATH": sysvol, + "PRIVATEDIR_LINE": privatedir_line, + "LOCKDIR_LINE": lockdir_line + }) + + lp = param.LoadParm() + lp.load(smbconf) + + if serverrole is None: + serverrole = lp.get("server role") + assert serverrole in ("domain controller", "member server") + if invocationid is None and serverrole == "domain controller": + invocationid = uuid.random() + + if realm is None: + realm = lp.get("realm") + + assert realm is not None + realm = realm.upper() + dnsdomain = realm.lower() + + paths = provision_paths_from_lp(lp, dnsdomain) + + if targetdir is not None: + if not os.path.exists(paths.private_dir): + os.mkdir(paths.private_dir) + + ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") + + if ldap_backend == "ldapi": + # provision-backend will set this path suggested slapd command line / fedorads.inf + ldap_backend = "ldapi://" % urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="") + if serverrole == "domain controller": - domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + if domaindn is None: + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") if domain is None: domain = lp.get("workgroup") @@ -815,38 +871,25 @@ def provision(lp, setup_dir, message, paths, session_info, if not valid_netbios_name(domain): raise InvalidNetbiosName(domain) else: - domaindn = "CN=" + netbiosname + if domaindn is None: + domaindn = "CN=" + netbiosname domain = netbiosname if rootdn is None: rootdn = domaindn - configdn = "CN=Configuration," + rootdn - schemadn = "CN=Schema," + configdn + if configdn is None: + configdn = "CN=Configuration," + rootdn + if schemadn is None: + schemadn = "CN=Schema," + configdn message("set DOMAIN SID: %s" % str(domainsid)) message("Provisioning for %s in realm %s" % (domain, realm)) message("Using administrator password: %s" % adminpass) - assert paths.smbconf is not None - - # only install a new smb.conf if there isn't one there already - if not os.path.exists(paths.smbconf): - message("Setting up smb.conf") - if serverrole == "domain controller": - smbconfsuffix = "dc" - elif serverrole == "member server": - smbconfsuffix = "member" - setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), - paths.smbconf, { - "HOSTNAME": hostname, - "DOMAIN_CONF": domain, - "REALM_CONF": realm, - "SERVERROLE": serverrole, - "NETLOGONPATH": paths.netlogon, - "SYSVOLPATH": paths.sysvol, - }) - lp.load(paths.smbconf) + if lp.get("realm").upper() != realm.upper(): + raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % + (lp.get("realm"), realm)) # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): @@ -911,32 +954,52 @@ def provision(lp, setup_dir, message, paths, session_info, message("Setting up sam.ldb rootDSE marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) + # Only make a zone file on the first DC, it should be replicated with DNS replication + if serverrole == "domain controller": + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + + domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") + assert isinstance(domainguid, str) + hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", + expression="(&(objectClass=computer)(cn=%s))" % hostname, + scope=SCOPE_SUBTREE) + assert isinstance(hostguid, str) + + message("Setting up DNS zone: %s" % dnsdomain) + create_zone_file(paths.dns, setup_path, samdb, + hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, + domaindn=domaindn, dnspass=dnspass, realm=realm, + domainguid=domainguid, hostguid=hostguid) + message("Please install the zone located in %s into your DNS server" % paths.dns) + message("Setting up phpLDAPadmin configuration") create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, ldapi_url) message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) - if lp.get("server role") == "domain controller": - samdb = SamDB(paths.samdb, session_info=session_info, - credentials=credentials, lp=lp) - - domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") - assert isinstance(domainguid, str) - hostguid = samdb.searchone(basedn=domaindn, attribute="objectGUID", - expression="(&(objectClass=computer)(cn=%s))" % hostname, - scope=SCOPE_SUBTREE) - assert isinstance(hostguid, str) - - message("Setting up DNS zone: %s" % dnsdomain) - create_zone_file(paths.dns, setup_path, samdb, - hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, - domaindn=domaindn, dnspass=dnspass, realm=realm, - domainguid=domainguid, hostguid=hostguid) - message("Please install the zone located in %s into your DNS server" % paths.dns) - return domaindn +def provision_become_dc(setup_dir=None, + smbconf=None, targetdir=None, realm=None, + rootdn=None, domaindn=None, schemadn=None, configdn=None, + domain=None, hostname=None, domainsid=None, + hostguid=None, adminpass=None, krbtgtpass=None, domainguid=None, + policyguid=None, invocationid=None, machinepass=None, + dnspass=None, root=None, nobody=None, nogroup=None, users=None, + wheel=None, backup=None, aci=None, serverrole=None, + ldap_backend=None, ldap_backend_type=None, sitename=DEFAULTSITE): + + def message(text): + """print a message if quiet is not set.""" + print text + + provision(setup_dir, message, system_session(), None, + smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS, realm=realm, + rootdn=rootdn, domaindn=domaindn, schemadn=schemadn, configdn=configdn, + domain=domain, hostname=hostname, hostip="127.0.0.1", domainsid=domainsid, machinepass=machinepass, serverrole="domain controller", sitename=sitename); + def create_phpldapadmin_config(path, setup_path, ldapi_uri): """Create a PHP LDAP admin configuration file. @@ -978,7 +1041,6 @@ def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, "HOSTGUID": hostguid, }) - def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename): """Load schema for the SamDB. diff --git a/source4/setup/provision b/source4/setup/provision index 033d2491f21..606443a6edf 100755 --- a/source4/setup/provision +++ b/source4/setup/provision @@ -30,9 +30,7 @@ import samba from auth import system_session import samba.getopt as options -import param from samba.provision import (provision, - provision_paths_from_lp, FILL_FULL, FILL_NT4SYNC, FILL_DRS) @@ -113,27 +111,13 @@ if opts.realm is None or opts.domain is None: sys.exit(1) # cope with an initially blank smb.conf -private_dir = None -lp = sambaopts.get_loadparm() -if opts.targetdir is not None: - if not os.path.exists(opts.targetdir): - os.mkdir(opts.targetdir) - private_dir = os.path.join(opts.targetdir, "private") - if not os.path.exists(private_dir): - os.mkdir(private_dir) - lp.set("private dir", os.path.abspath(private_dir)) - lp.set("lock dir", os.path.abspath(opts.targetdir)) -lp.set("realm", opts.realm) -lp.set("workgroup", opts.domain) -lp.set("server role", opts.server_role or "domain controller") + +if sambaopts.get_loadparm_path() is not None: + smbconf = sambaopts.get_loadparm_path() if opts.aci is not None: print "set ACI: %s" % opts.aci -paths = provision_paths_from_lp(lp, opts.realm.lower()) -if sambaopts.get_loadparm_path() is not None: - paths.smbconf = sambaopts.get_loadparm_path() - creds = credopts.get_credentials() setup_dir = opts.setupdir @@ -146,8 +130,8 @@ if opts.blank: elif opts.partitions_only: samdb_fill = FILL_DRS -provision(lp, setup_dir, message, paths, - system_session(), creds, +provision(setup_dir, message, + system_session(), creds, smbconf=smbconf, samdb_fill=samdb_fill, realm=opts.realm, domainguid=opts.domain_guid, domainsid=opts.domain_sid, policyguid=opts.policy_guid, hostname=opts.host_name, diff --git a/source4/setup/provision.smb.conf.dc b/source4/setup/provision.smb.conf.dc index 5b8e141cbf2..e77e6990284 100644 --- a/source4/setup/provision.smb.conf.dc +++ b/source4/setup/provision.smb.conf.dc @@ -3,6 +3,8 @@ workgroup = ${DOMAIN_CONF} realm = ${REALM_CONF} server role = ${SERVERROLE} + ${PRIVATEDIR_LINE} + ${LOCKDIR_LINE} [netlogon] path = ${NETLOGONPATH} diff --git a/source4/setup/provision.smb.conf.member b/source4/setup/provision.smb.conf.member index bc37d4f3d32..1d9191d8c2e 100644 --- a/source4/setup/provision.smb.conf.member +++ b/source4/setup/provision.smb.conf.member @@ -3,3 +3,5 @@ workgroup = ${DOMAIN_CONF} realm = ${REALM_CONF} server role = ${SERVERROLE} + ${PRIVATEDIR_LINE} + ${LOCKDIR_LINE} diff --git a/source4/setup/provision.smb.conf.standalone b/source4/setup/provision.smb.conf.standalone index bc37d4f3d32..1d9191d8c2e 100644 --- a/source4/setup/provision.smb.conf.standalone +++ b/source4/setup/provision.smb.conf.standalone @@ -3,3 +3,5 @@ workgroup = ${DOMAIN_CONF} realm = ${REALM_CONF} server role = ${SERVERROLE} + ${PRIVATEDIR_LINE} + ${LOCKDIR_LINE} diff --git a/source4/torture/libnet/libnet_BecomeDC.c b/source4/torture/libnet/libnet_BecomeDC.c index 9566f5ee294..6e882d56261 100644 --- a/source4/torture/libnet/libnet_BecomeDC.c +++ b/source4/torture/libnet/libnet_BecomeDC.c @@ -56,16 +56,9 @@ struct test_become_dc_state { struct drsuapi_DsReplicaObjectListItemEx *last_object; } schema_part; - struct { - const char *samdb_ldb; - const char *domaindn_ldb; - const char *configdn_ldb; - const char *schemadn_ldb; - const char *secrets_ldb; - const char *templates_ldb; - const char *secrets_keytab; - const char *dns_keytab; - } path; + const char *targetdir; + + struct loadparm_context *lp_ctx; }; static NTSTATUS test_become_dc_prepare_db(void *private_data, @@ -73,6 +66,14 @@ static NTSTATUS test_become_dc_prepare_db(void *private_data, { struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state); struct provision_settings settings; + NTSTATUS status; + bool ok; + struct loadparm_context *lp_ctx = loadparm_init(s); + char *smbconf; + + if (!lp_ctx) { + return NT_STATUS_NO_MEMORY; + } settings.dns_name = p->dest_dsa->dns_name; settings.site_name = p->dest_dsa->site_name; @@ -80,21 +81,46 @@ static NTSTATUS test_become_dc_prepare_db(void *private_data, settings.domain_dn_str = p->domain->dn_str; settings.config_dn_str = p->forest->config_dn_str; settings.schema_dn_str = p->forest->schema_dn_str; - settings.invocation_id = &p->dest_dsa->invocation_id; settings.netbios_name = p->dest_dsa->netbios_name; settings.realm = torture_join_dom_dns_name(s->tj); settings.domain = torture_join_dom_netbios_name(s->tj); - settings.ntds_guid = &p->dest_dsa->ntds_guid; - settings.ntds_dn_str = p->dest_dsa->ntds_dn_str; settings.machine_password = cli_credentials_get_password(s->machine_account); - settings.samdb_ldb = s->path.samdb_ldb; - settings.secrets_ldb = s->path.secrets_ldb; - settings.secrets_keytab = s->path.secrets_keytab; - settings.schemadn_ldb = s->path.schemadn_ldb; - settings.configdn_ldb = s->path.configdn_ldb; - settings.domaindn_ldb = s->path.domaindn_ldb; + settings.targetdir = s->targetdir; + + status = provision_bare(s, s->lp_ctx, &settings); + + smbconf = talloc_asprintf(lp_ctx, "%s/%s", s->targetdir, "/etc/smb.conf"); + + ok = lp_load(lp_ctx, smbconf); + if (!ok) { + DEBUG(0,("Failed load freshly generated smb.conf '%s'\n", smbconf)); + return NT_STATUS_INVALID_PARAMETER; + } + + s->ldb = ldb_wrap_connect(s, lp_ctx, lp_sam_url(lp_ctx), + system_session(s, lp_ctx), + NULL, 0, NULL); + if (!s->ldb) { + DEBUG(0,("Failed to open '%s'\n", lp_sam_url(lp_ctx))); + return NT_STATUS_INTERNAL_DB_ERROR; + } + + ok = samdb_set_ntds_invocation_id(s->ldb, &p->dest_dsa->invocation_id); + if (!ok) { + DEBUG(0,("Failed to set cached ntds invocationId\n")); + return NT_STATUS_FOOBAR; + } + ok = samdb_set_ntds_objectGUID(s->ldb, &p->dest_dsa->ntds_guid); + if (!ok) { + DEBUG(0,("Failed to set cached ntds objectGUID\n")); + return NT_STATUS_FOOBAR; + } + + s->lp_ctx = lp_ctx; + + return NT_STATUS_OK; + - return provision_bare(s, s->tctx->lp_ctx, &settings); } static NTSTATUS test_become_dc_check_options(void *private_data, @@ -140,6 +166,7 @@ static NTSTATUS test_apply_schema(struct test_become_dc_state *s, struct ldb_val prefixMap_val; struct ldb_message_element *prefixMap_el; struct ldb_val schemaInfo_val; + char *sam_ldb_path; uint32_t i; int ret; bool ok; @@ -325,13 +352,14 @@ static NTSTATUS test_apply_schema(struct test_become_dc_state *s, talloc_free(s->ldb); /* this also free's the s->schema, because dsdb_set_schema() steals it */ s->schema = NULL; - DEBUG(0,("Reopen the SAM LDB with system credentials and a already stored schema: %s\n", s->path.samdb_ldb)); - s->ldb = ldb_wrap_connect(s, s->tctx->lp_ctx, s->path.samdb_ldb, + sam_ldb_path = talloc_asprintf(s, "%s/%s", s->targetdir, "private/sam.ldb"); + DEBUG(0,("Reopen the SAM LDB with system credentials and a already stored schema: %s\n", sam_ldb_path)); + s->ldb = ldb_wrap_connect(s, s->tctx->lp_ctx, sam_ldb_path, system_session(s, s->tctx->lp_ctx), NULL, 0, NULL); if (!s->ldb) { DEBUG(0,("Failed to open '%s'\n", - s->path.samdb_ldb)); + sam_ldb_path)); return NT_STATUS_INTERNAL_DB_ERROR; } @@ -392,7 +420,8 @@ static NTSTATUS test_become_dc_schema_chunk(void *private_data, } if (!s->schema) { - s->self_made_schema = talloc_zero(s, struct dsdb_schema); + s->self_made_schema = dsdb_new_schema(s, lp_iconv_convenience(s->lp_ctx)); + NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema); status = dsdb_load_oid_mappings_drsuapi(s->self_made_schema, mapping_ctr); @@ -564,33 +593,24 @@ bool torture_net_become_dc(struct torture_context *torture) struct ldb_message *msg; int ldb_ret; uint32_t i; + char *sam_ldb_path; + + char *location = NULL; + torture_assert_ntstatus_ok(torture, torture_temp_dir(torture, "libnet_BecomeDC", &location), + "torture_temp_dir should return NT_STATUS_OK" ); s = talloc_zero(torture, struct test_become_dc_state); if (!s) return false; s->tctx = torture; + s->lp_ctx = torture->lp_ctx; s->netbios_name = lp_parm_string(torture->lp_ctx, NULL, "become dc", "smbtorture dc"); if (!s->netbios_name || !s->netbios_name[0]) { s->netbios_name = "smbtorturedc"; } - s->path.samdb_ldb = talloc_asprintf(s, "%s_samdb.ldb", s->netbios_name); - if (!s->path.samdb_ldb) return false; - s->path.domaindn_ldb = talloc_asprintf(s, "%s_domain.ldb", s->netbios_name); - if (!s->path.domaindn_ldb) return false; - s->path.configdn_ldb = talloc_asprintf(s, "%s_config.ldb", s->netbios_name); - if (!s->path.configdn_ldb) return false; - s->path.schemadn_ldb = talloc_asprintf(s, "%s_schema.ldb", s->netbios_name); - if (!s->path.schemadn_ldb) return false; - s->path.secrets_ldb = talloc_asprintf(s, "%s_secrets.ldb", s->netbios_name); - if (!s->path.secrets_ldb) return false; - s->path.templates_ldb = talloc_asprintf(s, "%s_templates.ldb", s->netbios_name); - if (!s->path.templates_ldb) return false; - s->path.secrets_keytab = talloc_asprintf(s, "%s_secrets.keytab", s->netbios_name); - if (!s->path.secrets_keytab) return false; - s->path.dns_keytab = talloc_asprintf(s, "%s_dns.keytab", s->netbios_name); - if (!s->path.dns_keytab) return false; + s->targetdir = location; /* Join domain as a member server. */ s->tj = torture_join_domain(torture, s->netbios_name, @@ -664,13 +684,14 @@ bool torture_net_become_dc(struct torture_context *torture) talloc_free(s->ldb); /* this also free's the s->schema, because dsdb_set_schema() steals it */ s->schema = NULL; - DEBUG(0,("Reopen the SAM LDB with system credentials and all replicated data: %s\n", s->path.samdb_ldb)); - s->ldb = ldb_wrap_connect(s, torture->lp_ctx, s->path.samdb_ldb, - system_session(s, torture->lp_ctx), + sam_ldb_path = talloc_asprintf(s, "%s/%s", s->targetdir, "private/sam.ldb"); + DEBUG(0,("Reopen the SAM LDB with system credentials and all replicated data: %s\n", sam_ldb_path)); + s->ldb = ldb_wrap_connect(s, s->lp_ctx, sam_ldb_path, + system_session(s, s->lp_ctx), NULL, 0, NULL); if (!s->ldb) { DEBUG(0,("Failed to open '%s'\n", - s->path.samdb_ldb)); + sam_ldb_path)); ret = false; goto cleanup; } @@ -682,7 +703,7 @@ bool torture_net_become_dc(struct torture_context *torture) goto cleanup; } - if (lp_parm_bool(torture->lp_ctx, NULL, "become dc", "do not unjoin", false)) { + if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "do not unjoin", false)) { talloc_free(s); return ret; } diff --git a/source4/torture/local/torture.c b/source4/torture/local/torture.c index 3273015347c..bb6e21ed4f7 100644 --- a/source4/torture/local/torture.c +++ b/source4/torture/local/torture.c @@ -43,6 +43,9 @@ static bool test_provision(struct torture_context *tctx) { NTSTATUS status; struct provision_settings settings; + char *location = NULL; + torture_assert_ntstatus_ok(tctx, torture_temp_dir(tctx, "torture_provision", &location), + "torture_temp_dir should return NT_STATUS_OK" ); settings.dns_name = "example.com"; settings.site_name = "SOME-SITE-NAME"; @@ -57,14 +60,7 @@ static bool test_provision(struct torture_context *tctx) settings.ntds_guid = NULL; settings.ntds_dn_str = NULL; settings.machine_password = "geheim"; - settings.samdb_ldb = NULL; - settings.secrets_ldb = NULL; - settings.secrets_keytab = NULL; - settings.schemadn_ldb = NULL; - settings.configdn_ldb = NULL; - settings.domaindn_ldb = NULL; - settings.templates_ldb = NULL; - settings.dns_keytab = NULL; + settings.targetdir = location; status = provision_bare(tctx, tctx->lp_ctx, &settings); diff --git a/source4/torture/util.h b/source4/torture/util.h index c5219a5aaad..477a8281201 100644 --- a/source4/torture/util.h +++ b/source4/torture/util.h @@ -29,19 +29,13 @@ struct provision_settings { const char *schema_dn_str; const struct GUID *invocation_id; const char *netbios_name; + const char *host_ip; const char *realm; const char *domain; const struct GUID *ntds_guid; const char *ntds_dn_str; const char *machine_password; - const char *samdb_ldb; - const char *secrets_ldb; - const char *secrets_keytab; - const char *schemadn_ldb; - const char *configdn_ldb; - const char *domaindn_ldb; - const char *templates_ldb; - const char *dns_keytab; + const char *targetdir; }; NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, diff --git a/source4/torture/util_provision.c b/source4/torture/util_provision.c index 2a1e9256f58..d7c8f479e64 100644 --- a/source4/torture/util_provision.c +++ b/source4/torture/util_provision.c @@ -18,206 +18,22 @@ */ #include "includes.h" -#include "dsdb/samdb/samdb.h" -#include "lib/appweb/ejs/ejs.h" -#include "lib/appweb/ejs/ejsInternal.h" -#include "scripting/ejs/smbcalls.h" #include "auth/auth.h" #include "lib/ldb_wrap.h" #include "torture/util.h" -static EjsId eid; -static int ejs_error; - -static void test_ejs_exception(const char *reason) -{ - Ejs *ep = ejsPtr(eid); - ejsSetErrorMsg(eid, "%s", reason); - fprintf(stderr, "%s", ep->error); - ejs_error = 127; -} - -static int test_run_ejs(char *script) -{ - EjsHandle handle = 0; - MprVar result; - char *emsg; - TALLOC_CTX *mem_ctx = talloc_new(NULL); - struct MprVar *return_var; - - mprSetCtx(mem_ctx); - - if (ejsOpen(NULL, NULL, NULL) != 0) { - d_printf("ejsOpen(): unable to initialise EJS subsystem\n"); - ejs_error = 127; - goto failed; - } - - smb_setup_ejs_functions(test_ejs_exception); - - if ((eid = ejsOpenEngine(handle, 0)) == (EjsId)-1) { - d_printf("smbscript: ejsOpenEngine(): unable to initialise an EJS engine\n"); - ejs_error = 127; - goto failed; - } - - mprSetVar(ejsGetGlobalObject(eid), "ARGV", mprList("ARGV", NULL)); - - /* run the script */ - if (ejsEvalScript(eid, script, &result, &emsg) == -1) { - d_printf("smbscript: ejsEvalScript(): %s\n", emsg); - if (ejs_error == 0) ejs_error = 127; - goto failed; - } - - return_var = ejsGetReturnValue(eid); - ejs_error = mprVarToNumber(return_var); - -failed: - ejsClose(); - talloc_free(mem_ctx); - return ejs_error; -} - -static NTSTATUS provision_bare_ejs(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - struct provision_settings *settings) -{ - char *ejs; - int ret; - bool ok; - struct ldb_context *ldb; - - DEBUG(0,("Provision for Become-DC test using EJS\n")); - - DEBUG(0,("New Server[%s] in Site[%s]\n", settings->dns_name, - settings->site_name)); - - DEBUG(0,("DSA Instance [%s]\n" - "\tobjectGUID[%s]\n" - "\tinvocationId[%s]\n", - settings->ntds_dn_str, - GUID_string(mem_ctx, settings->ntds_guid), - GUID_string(mem_ctx, settings->invocation_id))); - - DEBUG(0,("Pathes under PRIVATEDIR[%s]\n" - "SAMDB[%s] SECRETS[%s] KEYTAB[%s]\n", - lp_private_dir(lp_ctx), - settings->samdb_ldb, - settings->secrets_ldb, - settings->secrets_keytab)); - - DEBUG(0,("Schema Partition[%s => %s]\n", - settings->schema_dn_str, settings->schemadn_ldb)); - - DEBUG(0,("Config Partition[%s => %s]\n", - settings->config_dn_str, settings->configdn_ldb)); - - DEBUG(0,("Domain Partition[%s => %s]\n", - settings->domain_dn_str, settings->domaindn_ldb)); - - ejs = talloc_asprintf(mem_ctx, - "libinclude(\"base.js\");\n" - "libinclude(\"provision.js\");\n" - "\n" - "function message() { print(vsprintf(arguments)); }\n" - "\n" - "var subobj = provision_guess();\n" - "subobj.ROOTDN = \"%s\";\n" - "subobj.DOMAINDN = \"%s\";\n" - "subobj.DOMAINDN_LDB = \"%s\";\n" - "subobj.CONFIGDN = \"%s\";\n" - "subobj.CONFIGDN_LDB = \"%s\";\n" - "subobj.SCHEMADN = \"%s\";\n" - "subobj.SCHEMADN_LDB = \"%s\";\n" - "subobj.HOSTNAME = \"%s\";\n" - "subobj.REALM = \"%s\";\n" - "subobj.DOMAIN = \"%s\";\n" - "subobj.DEFAULTSITE = \"%s\";\n" - "\n" - "subobj.KRBTGTPASS = \"_NOT_USED_\";\n" - "subobj.MACHINEPASS = \"%s\";\n" - "subobj.ADMINPASS = \"_NOT_USED_\";\n" - "\n" - "var paths = provision_default_paths(subobj);\n" - "paths.samdb = \"%s\";\n" - "paths.secrets = \"%s\";\n" - "paths.templates = \"%s\";\n" - "paths.keytab = \"%s\";\n" - "paths.dns_keytab = \"%s\";\n" - "\n" - "var system_session = system_session();\n" - "\n" - "var ok = provision_become_dc(subobj, message, true, paths, system_session);\n" - "assert(ok);\n" - "\n" - "return 0;\n", - settings->root_dn_str, /* subobj.ROOTDN */ - settings->domain_dn_str, /* subobj.DOMAINDN */ - settings->domaindn_ldb, /* subobj.DOMAINDN_LDB */ - settings->config_dn_str, /* subobj.CONFIGDN */ - settings->configdn_ldb, /* subobj.CONFIGDN_LDB */ - settings->schema_dn_str, /* subobj.SCHEMADN */ - settings->schemadn_ldb, /* subobj.SCHEMADN_LDB */ - settings->netbios_name, /* subobj.HOSTNAME */ - settings->realm,/* subobj.REALM */ - settings->domain,/* subobj.DOMAIN */ - settings->site_name, /* subobj.DEFAULTSITE */ - settings->machine_password,/* subobj.MACHINEPASS */ - settings->samdb_ldb, /* paths.samdb */ - settings->templates_ldb, /* paths.templates */ - settings->secrets_ldb, /* paths.secrets */ - settings->secrets_keytab, /* paths.keytab */ - settings->dns_keytab); /* paths.dns_keytab */ - NT_STATUS_HAVE_NO_MEMORY(ejs); - - ret = test_run_ejs(ejs); - if (ret != 0) { - DEBUG(0,("Failed to run ejs script: %d:\n%s", - ret, ejs)); - talloc_free(ejs); - return NT_STATUS_FOOBAR; - } - talloc_free(ejs); - - DEBUG(0,("Open the SAM LDB with system credentials: %s\n", - settings->samdb_ldb)); - - ldb = ldb_wrap_connect(mem_ctx, lp_ctx, settings->samdb_ldb, - system_session(mem_ctx, lp_ctx), - NULL, 0, NULL); - if (!ldb) { - DEBUG(0,("Failed to open '%s'\n", - settings->samdb_ldb)); - return NT_STATUS_INTERNAL_DB_ERROR; - } - - ok = samdb_set_ntds_invocation_id(ldb, settings->invocation_id); - if (!ok) { - DEBUG(0,("Failed to set cached ntds invocationId\n")); - return NT_STATUS_FOOBAR; - } - ok = samdb_set_ntds_objectGUID(ldb, settings->ntds_guid); - if (!ok) { - DEBUG(0,("Failed to set cached ntds objectGUID\n")); - return NT_STATUS_FOOBAR; - } - - return NT_STATUS_OK; -} - #include "param/param.h" #include #include "scripting/python/modules.h" -static NTSTATUS provision_bare_py(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - struct provision_settings *settings) +NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, + struct provision_settings *settings) { bool ok; PyObject *provision_mod, *provision_dict, *provision_fn, *result, *parameters; struct ldb_context *ldb; - + char *sam_ldb_path; + DEBUG(0,("Provision for Become-DC test using python\n")); py_load_samba_modules(); @@ -239,10 +55,10 @@ static NTSTATUS provision_bare_py(TALLOC_CTX *mem_ctx, return NT_STATUS_UNSUCCESSFUL; } - provision_fn = PyDict_GetItemString(provision_dict, "provision"); + provision_fn = PyDict_GetItemString(provision_dict, "provision_become_dc"); if (provision_fn == NULL) { PyErr_Print(); - DEBUG(0, ("Unable to get provision function\n")); + DEBUG(0, ("Unable to get provision_become_dc function\n")); return NT_STATUS_UNSUCCESSFUL; } @@ -256,56 +72,45 @@ static NTSTATUS provision_bare_py(TALLOC_CTX *mem_ctx, settings->ntds_guid == NULL?"None":GUID_string(mem_ctx, settings->ntds_guid), settings->invocation_id == NULL?"None":GUID_string(mem_ctx, settings->invocation_id))); - DEBUG(0,("Pathes under PRIVATEDIR[%s]\n" - "SAMDB[%s] SECRETS[%s] KEYTAB[%s]\n", - lp_private_dir(lp_ctx), - settings->samdb_ldb, - settings->secrets_ldb, - settings->secrets_keytab)); - - DEBUG(0,("Schema Partition[%s => %s]\n", - settings->schema_dn_str, settings->schemadn_ldb)); - - DEBUG(0,("Config Partition[%s => %s]\n", - settings->config_dn_str, settings->configdn_ldb)); - - DEBUG(0,("Domain Partition[%s => %s]\n", - settings->domain_dn_str, settings->domaindn_ldb)); - + DEBUG(0,("Pathes under targetdir[%s]\n", + settings->targetdir)); parameters = PyDict_New(); PyDict_SetItemString(parameters, "rootdn", PyString_FromString(settings->root_dn_str)); - if (settings->domaindn_ldb != NULL) - PyDict_SetItemString(parameters, "domaindn_ldb", - PyString_FromString(settings->domaindn_ldb)); - if (settings->config_dn_str != NULL) - PyDict_SetItemString(parameters, "configdn", - PyString_FromString(settings->config_dn_str)); - if (settings->configdn_ldb != NULL) - PyDict_SetItemString(parameters, "configdn_ldb", - PyString_FromString(settings->configdn_ldb)); - if (settings->schema_dn_str != NULL) - PyDict_SetItemString(parameters, "schema_dn_str", - PyString_FromString(settings->schema_dn_str)); - if (settings->schemadn_ldb != NULL) - PyDict_SetItemString(parameters, "schemadn_ldb", - PyString_FromString(settings->schemadn_ldb)); + if (settings->targetdir != NULL) + PyDict_SetItemString(parameters, "targetdir", + PyString_FromString(settings->targetdir)); + PyDict_SetItemString(parameters, "setup_dir", + PyString_FromString("setup")); PyDict_SetItemString(parameters, "hostname", PyString_FromString(settings->netbios_name)); - PyDict_SetItemString(parameters, "sitename", - PyString_FromString(settings->site_name)); + PyDict_SetItemString(parameters, "domain", + PyString_FromString(settings->domain)); + PyDict_SetItemString(parameters, "realm", + PyString_FromString(settings->realm)); + if (settings->root_dn_str) + PyDict_SetItemString(parameters, "rootdn", + PyString_FromString(settings->root_dn_str)); + + if (settings->domain_dn_str) + PyDict_SetItemString(parameters, "domaindn", + PyString_FromString(settings->domain_dn_str)); + + if (settings->schema_dn_str) + PyDict_SetItemString(parameters, "schemadn", + PyString_FromString(settings->schema_dn_str)); + + if (settings->config_dn_str) + PyDict_SetItemString(parameters, "configdn", + PyString_FromString(settings->config_dn_str)); + + if (settings->site_name) + PyDict_SetItemString(parameters, "sitename", + PyString_FromString(settings->site_name)); + PyDict_SetItemString(parameters, "machinepass", - PyString_FromString(settings->machine_password)); - if (settings->samdb_ldb != NULL) - PyDict_SetItemString(parameters, "samdb", - PyString_FromString(settings->samdb_ldb)); - if (settings->secrets_ldb != NULL) - PyDict_SetItemString(parameters, "secrets_ldb", - PyString_FromString(settings->secrets_ldb)); - if (settings->secrets_keytab != NULL) - PyDict_SetItemString(parameters, "secrets_keytab", - PyString_FromString(settings->secrets_keytab)); + PyString_FromString(settings->machine_password)); result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters); @@ -317,39 +122,5 @@ static NTSTATUS provision_bare_py(TALLOC_CTX *mem_ctx, return NT_STATUS_UNSUCCESSFUL; } - DEBUG(0,("Open the SAM LDB with system credentials: %s\n", - settings->samdb_ldb)); - - ldb = ldb_wrap_connect(mem_ctx, lp_ctx, settings->samdb_ldb, - system_session(mem_ctx, lp_ctx), - NULL, 0, NULL); - if (!ldb) { - DEBUG(0,("Failed to open '%s'\n", settings->samdb_ldb)); - return NT_STATUS_INTERNAL_DB_ERROR; - } - - ok = samdb_set_ntds_invocation_id(ldb, settings->invocation_id); - if (!ok) { - DEBUG(0,("Failed to set cached ntds invocationId\n")); - return NT_STATUS_FOOBAR; - } - ok = samdb_set_ntds_objectGUID(ldb, settings->ntds_guid); - if (!ok) { - DEBUG(0,("Failed to set cached ntds objectGUID\n")); - return NT_STATUS_FOOBAR; - } - return NT_STATUS_OK; } - -NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, - struct provision_settings *settings) -{ - if (getenv("PROVISION_EJS")) { - return provision_bare_ejs(mem_ctx, lp_ctx, settings); - } else { - return provision_bare_py(mem_ctx, lp_ctx, settings); - } -} - - From 85bf2abee008f73602fabccd63296338a43ebb11 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 6 Mar 2008 22:03:10 +1100 Subject: [PATCH 09/34] Ensure we get this option from the command line, not the internal smb.conf we generate. Andrew Bartlett (This used to be commit 25887c87285b1b92ce5d7cc096da483c25a2fe6c) --- source4/torture/libnet/libnet_BecomeDC.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source4/torture/libnet/libnet_BecomeDC.c b/source4/torture/libnet/libnet_BecomeDC.c index 6e882d56261..4a3f7b5f615 100644 --- a/source4/torture/libnet/libnet_BecomeDC.c +++ b/source4/torture/libnet/libnet_BecomeDC.c @@ -703,7 +703,8 @@ bool torture_net_become_dc(struct torture_context *torture) goto cleanup; } - if (lp_parm_bool(s->lp_ctx, NULL, "become dc", "do not unjoin", false)) { + /* Make sure we get this from the command line */ + if (lp_parm_bool(toture->lp_ctx, NULL, "become dc", "do not unjoin", false)) { talloc_free(s); return ret; } From c24329dc0710df7520e77d67e5d9bc43f59fd24f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 6 Mar 2008 22:04:46 +1100 Subject: [PATCH 10/34] Fix typo (This used to be commit e66be2f519584717abd7fc1f069bf7afe0d7ff60) --- source4/torture/libnet/libnet_BecomeDC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/torture/libnet/libnet_BecomeDC.c b/source4/torture/libnet/libnet_BecomeDC.c index 4a3f7b5f615..3f8edd40e84 100644 --- a/source4/torture/libnet/libnet_BecomeDC.c +++ b/source4/torture/libnet/libnet_BecomeDC.c @@ -704,7 +704,7 @@ bool torture_net_become_dc(struct torture_context *torture) } /* Make sure we get this from the command line */ - if (lp_parm_bool(toture->lp_ctx, NULL, "become dc", "do not unjoin", false)) { + if (lp_parm_bool(torture->lp_ctx, NULL, "become dc", "do not unjoin", false)) { talloc_free(s); return ret; } From 3cbe47b2aef427f7f1fe8f4aa2496fbbe31a3ade Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:11:16 +0100 Subject: [PATCH 11/34] libcli/raw: make it possible to not send CAP_LEVEL_II_OPLOCKS But the keep the default to always send it when the server supports it too. metze (This used to be commit 33caaef2e46557525a8ffb79d6dd0db46a079529) --- source4/libcli/raw/rawnegotiate.c | 4 ++++ source4/param/loadparm.c | 4 ++-- source4/torture/util_smb.c | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c index ec2ada53ff7..6c16935f214 100644 --- a/source4/libcli/raw/rawnegotiate.c +++ b/source4/libcli/raw/rawnegotiate.c @@ -187,6 +187,10 @@ NTSTATUS smb_raw_negotiate_recv(struct smbcli_request *req) transport->negotiate.capabilities &= ~CAP_STATUS32; } + if (!transport->options.use_level2_oplocks) { + transport->negotiate.capabilities &= ~CAP_LEVEL_II_OPLOCKS; + } + failed: return smbcli_request_destroy(req); } diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index d94ab92ac94..65ce7595fca 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -2614,6 +2614,6 @@ void lp_smbcli_options(struct loadparm_context *lp_ctx, options->ntstatus_support = lp_nt_status_support(lp_ctx); options->max_protocol = lp_cli_maxprotocol(lp_ctx); options->unicode = lp_unicode(lp_ctx); - options->use_oplocks = false; - options->use_level2_oplocks = false; + options->use_oplocks = true; + options->use_level2_oplocks = true; } diff --git a/source4/torture/util_smb.c b/source4/torture/util_smb.c index ddf7b85c636..ba62f3789c1 100644 --- a/source4/torture/util_smb.c +++ b/source4/torture/util_smb.c @@ -478,6 +478,9 @@ _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx, lp_smbcli_options(tctx->lp_ctx, &options); + options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true); + options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true); + status = smbcli_full_connection(mem_ctx, c, hostname, lp_smb_ports(tctx->lp_ctx), sharename, NULL, @@ -489,9 +492,6 @@ _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx, return false; } - (*c)->transport->options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", false); - (*c)->transport->options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", false); - return true; } From 87f2925252b910f2f403bdbb3f9158202cb7a2c5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:14:08 +0100 Subject: [PATCH 12/34] ntvfs: pass down the client capabilities into the ntvfs layer Note that we don't use any protocol specific values here. For now only NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS is defined others should be defined, when we find out that the ntvfs layer needs to know about it. metze (This used to be commit cc42cd5f6753ca582677fa6f403f0419eec5ab10) --- source4/ntvfs/ntvfs.h | 16 ++++++++++++++++ source4/ntvfs/ntvfs_base.c | 2 ++ source4/ntvfs/ntvfs_util.c | 1 + source4/rpc_server/srvsvc/srvsvc_ntvfs.c | 1 + source4/smb_server/smb/service.c | 6 ++++++ source4/smb_server/smb2/tcon.c | 4 ++++ 6 files changed, 30 insertions(+) diff --git a/source4/ntvfs/ntvfs.h b/source4/ntvfs/ntvfs.h index a708dbff51a..7a2edc7e2c2 100644 --- a/source4/ntvfs/ntvfs.h +++ b/source4/ntvfs/ntvfs.h @@ -181,6 +181,14 @@ struct ntvfs_context { enum protocol_types protocol; + /* + * client capabilities + * this field doesn't use protocol specific + * values! + */ +#define NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS 0x0000000000000001LLU + uint64_t client_caps; + /* * linked list of module contexts */ @@ -257,6 +265,14 @@ struct ntvfs_request { /* the smb pid is needed for locking contexts */ uint16_t smbpid; + /* + * client capabilities + * this field doesn't use protocol specific + * values! + * see NTVFS_CLIENT_CAP_* + */ + uint64_t client_caps; + /* some statictics for the management tools */ struct { /* the system time when the request arrived */ diff --git a/source4/ntvfs/ntvfs_base.c b/source4/ntvfs/ntvfs_base.c index f5a24f23a03..35becabcf9b 100644 --- a/source4/ntvfs/ntvfs_base.c +++ b/source4/ntvfs/ntvfs_base.c @@ -153,6 +153,7 @@ _PUBLIC_ bool ntvfs_interface_differs(const struct ntvfs_critical_sizes *const i */ NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, struct share_config *scfg, enum ntvfs_type type, enum protocol_types protocol, + uint64_t ntvfs_client_caps, struct event_context *ev, struct messaging_context *msg, struct loadparm_context *lp_ctx, struct server_id server_id, struct ntvfs_context **_ctx) @@ -168,6 +169,7 @@ NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, struct share_config *scfg, e ctx = talloc_zero(mem_ctx, struct ntvfs_context); NT_STATUS_HAVE_NO_MEMORY(ctx); ctx->protocol = protocol; + ctx->client_caps = ntvfs_client_caps; ctx->type = type; ctx->config = talloc_steal(ctx, scfg); ctx->event_ctx = ev; diff --git a/source4/ntvfs/ntvfs_util.c b/source4/ntvfs/ntvfs_util.c index 7432ac2c13d..ebe8008edd0 100644 --- a/source4/ntvfs/ntvfs_util.c +++ b/source4/ntvfs/ntvfs_util.c @@ -42,6 +42,7 @@ _PUBLIC_ struct ntvfs_request *ntvfs_request_create(struct ntvfs_context *ctx, T req->async_states = NULL; req->session_info = session_info; req->smbpid = smbpid; + req->client_caps = ctx->client_caps; req->statistics.request_time = request_time; async = talloc(req, struct ntvfs_async_state); diff --git a/source4/rpc_server/srvsvc/srvsvc_ntvfs.c b/source4/rpc_server/srvsvc/srvsvc_ntvfs.c index ccd6c4f74eb..43fb24c0c36 100644 --- a/source4/rpc_server/srvsvc/srvsvc_ntvfs.c +++ b/source4/rpc_server/srvsvc/srvsvc_ntvfs.c @@ -98,6 +98,7 @@ NTSTATUS srvsvc_create_ntvfs_context(struct dcesrv_call_state *dce_call, /* init ntvfs function pointers */ status = ntvfs_init_connection(c, scfg, type, PROTOCOL_NT1, + 0,/* ntvfs_client_caps */ dce_call->event_ctx, dce_call->conn->msg_ctx, dce_call->conn->dce_ctx->lp_ctx, diff --git a/source4/smb_server/smb/service.c b/source4/smb_server/smb/service.c index 35b36530261..52471c09c99 100644 --- a/source4/smb_server/smb/service.c +++ b/source4/smb_server/smb/service.c @@ -36,6 +36,7 @@ static NTSTATUS make_connection_scfg(struct smbsrv_request *req, { struct smbsrv_tcon *tcon; NTSTATUS status; + uint64_t ntvfs_caps = 0; tcon = smbsrv_smb_tcon_new(req->smb_conn, scfg->name); if (!tcon) { @@ -44,9 +45,14 @@ static NTSTATUS make_connection_scfg(struct smbsrv_request *req, } req->tcon = tcon; + if (req->smb_conn->negotiate.client_caps & CAP_LEVEL_II_OPLOCKS) { + ntvfs_caps |= NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS; + } + /* init ntvfs function pointers */ status = ntvfs_init_connection(tcon, scfg, type, req->smb_conn->negotiate.protocol, + ntvfs_caps, req->smb_conn->connection->event.ctx, req->smb_conn->connection->msg_ctx, req->smb_conn->lp_ctx, diff --git a/source4/smb_server/smb2/tcon.c b/source4/smb_server/smb2/tcon.c index 7f7d558b163..040947f84f3 100644 --- a/source4/smb_server/smb2/tcon.c +++ b/source4/smb_server/smb2/tcon.c @@ -245,6 +245,7 @@ static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon const char *service = io->smb2.in.path; struct share_config *scfg; const char *sharetype; + uint64_t ntvfs_caps = 0; if (strncmp(service, "\\\\", 2) == 0) { const char *p = strchr(service+2, '\\'); @@ -283,9 +284,12 @@ static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon } req->tcon = tcon; + ntvfs_caps = NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS; + /* init ntvfs function pointers */ status = ntvfs_init_connection(tcon, scfg, type, req->smb_conn->negotiate.protocol, + ntvfs_caps, req->smb_conn->connection->event.ctx, req->smb_conn->connection->msg_ctx, req->smb_conn->lp_ctx, From 0339ae5ad82c248b43afa9431b13cda536b18fd6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:34:37 +0100 Subject: [PATCH 13/34] pvfs_open: fix crash/leak in case pvfs_setup_oplock() fails metze (This used to be commit 5563238782e825f64a22b5f9e0a7deb687f50b19) --- source4/ntvfs/posix/pvfs_open.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index adf4c1ac185..792e35cd140 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -696,21 +696,20 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, DLIST_ADD(pvfs->files.list, f); + /* setup a destructor to avoid file descriptor leaks on + abnormal termination */ + talloc_set_destructor(f, pvfs_fnum_destructor); + talloc_set_destructor(f->handle, pvfs_handle_destructor); + if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) { oplock_granted = OPLOCK_BATCH; } else if (oplock_granted != OPLOCK_NONE) { status = pvfs_setup_oplock(f, oplock_granted); if (!NT_STATUS_IS_OK(status)) { - talloc_free(lck); return status; } } - /* setup a destructor to avoid file descriptor leaks on - abnormal termination */ - talloc_set_destructor(f, pvfs_fnum_destructor); - talloc_set_destructor(f->handle, pvfs_handle_destructor); - io->generic.out.oplock_level = oplock_granted; io->generic.out.file.ntvfs = f->ntvfs; io->generic.out.create_action = NTCREATEX_ACTION_CREATED; From b7db5f7cb57eca4bf28fd8238e5f958a6038158e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:47:27 +0100 Subject: [PATCH 14/34] opendb: add allow_level_II_oplock parameter to odb_open_file() Not all clients support a fallback to level II oplocks. metze (This used to be commit 146f1fe0b67ca0805f0e71358abc57da0c0579a9) --- source4/cluster/ctdb/opendb_ctdb.c | 1 + source4/librpc/idl/opendb.idl | 1 + source4/ntvfs/common/opendb.c | 4 +++- source4/ntvfs/common/opendb.h | 1 + source4/ntvfs/common/opendb_tdb.c | 32 ++++++++++++++++++++---------- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/source4/cluster/ctdb/opendb_ctdb.c b/source4/cluster/ctdb/opendb_ctdb.c index e84f2364d40..fe48f987601 100644 --- a/source4/cluster/ctdb/opendb_ctdb.c +++ b/source4/cluster/ctdb/opendb_ctdb.c @@ -284,6 +284,7 @@ static NTSTATUS odb_ctdb_open_file(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { diff --git a/source4/librpc/idl/opendb.idl b/source4/librpc/idl/opendb.idl index eaa626e89de..e3bc2d0f177 100644 --- a/source4/librpc/idl/opendb.idl +++ b/source4/librpc/idl/opendb.idl @@ -23,6 +23,7 @@ interface opendb /* we need a per-entry delete on close, as well as a per-file one, to cope with strange semantics on open */ boolean8 delete_on_close; + boolean8 allow_level_II_oplock; uint32 oplock_level; } opendb_entry; diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index 6c1a9c070ae..a7e5458aaf8 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -98,11 +98,13 @@ _PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { return ops->odb_open_file(lck, file_handle, path, stream_id, share_access, access_mask, delete_on_close, open_disposition, - break_to_none, oplock_level, oplock_granted); + break_to_none, allow_level_II_oplock, + oplock_level, oplock_granted); } diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h index 69a7f718ba6..1c7f815dea4 100644 --- a/source4/ntvfs/common/opendb.h +++ b/source4/ntvfs/common/opendb.h @@ -30,6 +30,7 @@ struct opendb_ops { uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted); NTSTATUS (*odb_open_file_pending)(struct odb_lock *lck, void *private); NTSTATUS (*odb_close_file)(struct odb_lock *lck, void *file_handle, diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c index 47b35f594c6..0736af3d1ef 100644 --- a/source4/ntvfs/common/opendb_tdb.c +++ b/source4/ntvfs/common/opendb_tdb.c @@ -344,7 +344,8 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb, break request and suspending this call until the break is acknowledged or the file is closed */ - if (break_to_none) { + if (break_to_none || + !file->entries[i].allow_level_II_oplock) { oplock_return = OPLOCK_BREAK_TO_NONE; } odb_oplock_break_send(odb, &file->entries[i], @@ -391,7 +392,8 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb, * send an oplock break to the holder of the * oplock and tell caller to retry later */ - if (break_to_none) { + if (break_to_none || + !file->entries[i].allow_level_II_oplock) { oplock_return = OPLOCK_BREAK_TO_NONE; } odb_oplock_break_send(odb, &file->entries[i], @@ -418,6 +420,7 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { struct odb_context *odb = lck->odb; @@ -447,13 +450,14 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, NT_STATUS_NOT_OK_RETURN(status); /* see if it conflicts */ - e.server = odb->ntvfs_ctx->server_id; - e.file_handle = file_handle; - e.stream_id = stream_id; - e.share_access = share_access; - e.access_mask = access_mask; - e.delete_on_close = delete_on_close; - e.oplock_level = OPLOCK_NONE; + e.server = odb->ntvfs_ctx->server_id; + e.file_handle = file_handle; + e.stream_id = stream_id; + e.share_access = share_access; + e.access_mask = access_mask; + e.delete_on_close = delete_on_close; + e.allow_level_II_oplock = allow_level_II_oplock; + e.oplock_level = OPLOCK_NONE; /* possibly grant an exclusive, batch or level2 oplock @@ -466,17 +470,23 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, if (file.num_entries == 0) { e.oplock_level = OPLOCK_EXCLUSIVE; *oplock_granted = EXCLUSIVE_OPLOCK_RETURN; - } else { + } else if (allow_level_II_oplock) { e.oplock_level = OPLOCK_LEVEL_II; *oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + e.oplock_level = OPLOCK_NONE; + *oplock_granted = NO_OPLOCK_RETURN; } } else if (oplock_level == OPLOCK_BATCH) { if (file.num_entries == 0) { e.oplock_level = OPLOCK_BATCH; *oplock_granted = BATCH_OPLOCK_RETURN; - } else { + } else if (allow_level_II_oplock) { e.oplock_level = OPLOCK_LEVEL_II; *oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + e.oplock_level = OPLOCK_NONE; + *oplock_granted = NO_OPLOCK_RETURN; } } else if (oplock_level == OPLOCK_LEVEL_II) { e.oplock_level = OPLOCK_LEVEL_II; From ef4ae2597d0c198f42a5144ccd49716f0cb5796b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:48:31 +0100 Subject: [PATCH 15/34] pvfs_open: pass down allow_level_II_oplock to odb_open_file() metze (This used to be commit 7c9b269b0742d435055e21f7e6cc945c21c7e332) --- source4/ntvfs/posix/pvfs_open.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 792e35cd140..47b44b9634e 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -293,7 +293,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, OPLOCK_NONE, NULL); + false, false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); @@ -347,7 +347,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, OPLOCK_NONE, NULL); + false, false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; @@ -544,6 +544,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, bool del_on_close; struct pvfs_filename *parent; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; + bool allow_level_II_oplock = false; if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) && (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) { @@ -658,10 +659,15 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, oplock_level = OPLOCK_EXCLUSIVE; } + if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) { + allow_level_II_oplock = true; + } + status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, oplock_level, &oplock_granted); + false, allow_level_II_oplock, + oplock_level, &oplock_granted); talloc_free(lck); if (!NT_STATUS_IS_OK(status)) { /* bad news, we must have hit a race - we don't delete the file @@ -1047,6 +1053,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, bool del_on_close; bool stream_existed, stream_truncate=false; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; + bool allow_level_II_oplock = false; /* use the generic mapping code to avoid implementing all the different open calls. */ @@ -1241,11 +1248,16 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, oplock_level = OPLOCK_EXCLUSIVE; } + if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) { + allow_level_II_oplock = true; + } + /* see if we are allowed to open at the same time as existing opens */ status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, oplock_level, &oplock_granted); + false, allow_level_II_oplock, + oplock_level, &oplock_granted); /* * on a sharing violation we need to retry when the file is closed by From bc9bb918a19253f412605d31d69b66785db3d761 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:49:31 +0100 Subject: [PATCH 16/34] RAW-OPLOCK: remove unused vars metze (This used to be commit 0905f3ebd1cb1ac9cefc4272208add9e5a8d7f59) --- source4/torture/raw/oplock.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index 8a7489c84e8..cb47a256f6e 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -2301,13 +2301,10 @@ static bool test_raw_oplock_batch22(struct torture_context *tctx, struct smbcli_ NTSTATUS status; bool ret = true; union smb_open io; - union smb_unlink unl; uint16_t fnum=0, fnum2=0; - char c = 0; struct timeval tv; int timeout = torture_setting_int(tctx, "oplocktimeout", 30); int te; - ssize_t wr; if (torture_setting_bool(tctx, "samba3", false)) { torture_skip(tctx, "BACHT22 disabled against samba3\n"); From 80104efb5849008379f47fed2f5b621ea23a355e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:54:07 +0100 Subject: [PATCH 17/34] RAW-OPLOCK: add BATCH23 and test with a connection with no CAP_LEVEL_II_OPLOCKS metze (This used to be commit 2192d6d2bda2afd2ba1ed0cb68bdfe590b9d50af) --- source4/torture/raw/oplock.c | 121 +++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index cb47a256f6e..a5e9c3267e5 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -24,6 +24,9 @@ #include "libcli/libcli.h" #include "torture/util.h" #include "lib/events/events.h" +#include "param/param.h" +#include "lib/cmdline/popt_common.h" +#include "libcli/resolve/resolve.h" #define CHECK_VAL(v, correct) do { \ if ((v) != (correct)) { \ @@ -153,6 +156,32 @@ static bool oplock_handler_close(struct smbcli_transport *transport, uint16_t ti return true; } +static bool open_connection_no_level2_oplocks(struct torture_context *tctx, + struct smbcli_state **c) +{ + NTSTATUS status; + + struct smbcli_options options; + + lp_smbcli_options(tctx->lp_ctx, &options); + + options.use_level2_oplocks = false; + + status = smbcli_full_connection(tctx, c, + torture_setting_string(tctx, "host", NULL), + lp_smb_ports(tctx->lp_ctx), + torture_setting_string(tctx, "share", NULL), + NULL, cmdline_credentials, + lp_resolve_context(tctx->lp_ctx), + tctx->ev, &options); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to open connection - %s\n", nt_errstr(status)); + return false; + } + + return true; +} + static bool test_raw_oplock_exclusive1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) { const char *fname = BASEDIR "\\test_exclusive1.dat"; @@ -2387,6 +2416,97 @@ done: return ret; } +static bool test_raw_oplock_batch23(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch23.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + uint16_t fnum=0, fnum2=0,fnum3=0; + struct smbcli_state *cli3 = NULL; + + if (torture_setting_bool(tctx, "samba3", false)) { + torture_skip(tctx, "BACHT23 disabled against samba3\n"); + } + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + + ret = open_connection_no_level2_oplocks(tctx, &cli3); + CHECK_VAL(ret, true); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + torture_comment(tctx, "a open and ask for a batch oplock\n"); + ZERO_STRUCT(break_info); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); + smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_levelII, cli3->tree); + + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + status = smb_raw_open(cli1->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + ZERO_STRUCT(break_info); + + torture_comment(tctx, "a 2nd open without level2 oplock support should generate a break to level2\n"); + status = smb_raw_open(cli3->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum3 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN); + + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.fnum, fnum); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II); + CHECK_VAL(break_info.failures, 0); + + ZERO_STRUCT(break_info); + + torture_comment(tctx, "a 3rd open with level2 oplock support should not generate a break\n"); + status = smb_raw_open(cli2->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum2 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); + + CHECK_VAL(break_info.count, 0); + + smbcli_close(cli1->tree, fnum); + smbcli_close(cli2->tree, fnum2); + smbcli_close(cli3->tree, fnum3); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smb_raw_exit(cli3->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + /* basic testing of oplocks */ @@ -2422,6 +2542,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) torture_suite_add_2smb_test(suite, "BATCH20", test_raw_oplock_batch20); torture_suite_add_2smb_test(suite, "BATCH21", test_raw_oplock_batch21); torture_suite_add_2smb_test(suite, "BATCH22", test_raw_oplock_batch22); + torture_suite_add_2smb_test(suite, "BATCH23", test_raw_oplock_batch23); return suite; } From 4bfc32b160fcb7a4406c38e08716b9a6d7ca3270 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:56:03 +0100 Subject: [PATCH 18/34] RAW-OPLOCK: add BATCH24 test another case with a connection with no CAP_LEVEL_II_OPLOCKS metze (This used to be commit 4fb2c9fb1f4e3ee23281ca83f8b91d252cbf53c7) --- source4/torture/raw/oplock.c | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index a5e9c3267e5..ae52092c872 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -2507,6 +2507,82 @@ done: return ret; } +static bool test_raw_oplock_batch24(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2) +{ + const char *fname = BASEDIR "\\test_batch24.dat"; + NTSTATUS status; + bool ret = true; + union smb_open io; + uint16_t fnum2=0,fnum3=0; + struct smbcli_state *cli3 = NULL; + + if (!torture_setup_dir(cli1, BASEDIR)) { + return false; + } + + /* cleanup */ + smbcli_unlink(cli1->tree, fname); + + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + + ret = open_connection_no_level2_oplocks(tctx, &cli3); + CHECK_VAL(ret, true); + + /* + base ntcreatex parms + */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + torture_comment(tctx, "a open without level support and ask for a batch oplock\n"); + ZERO_STRUCT(break_info); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); + smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_levelII, cli3->tree); + + io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; + io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | + NTCREATEX_FLAGS_REQUEST_OPLOCK | + NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; + status = smb_raw_open(cli3->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum3 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN); + + ZERO_STRUCT(break_info); + + torture_comment(tctx, "a 2nd open with level2 oplock support should generate a break to none\n"); + status = smb_raw_open(cli2->tree, tctx, &io); + CHECK_STATUS(tctx, status, NT_STATUS_OK); + fnum2 = io.ntcreatex.out.file.fnum; + CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); + + CHECK_VAL(break_info.count, 1); + CHECK_VAL(break_info.fnum, fnum3); + CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE); + CHECK_VAL(break_info.failures, 0); + + smbcli_close(cli3->tree, fnum3); + smbcli_close(cli2->tree, fnum2); + +done: + smb_raw_exit(cli1->session); + smb_raw_exit(cli2->session); + smb_raw_exit(cli3->session); + smbcli_deltree(cli1->tree, BASEDIR); + return ret; +} + /* basic testing of oplocks */ @@ -2543,6 +2619,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx) torture_suite_add_2smb_test(suite, "BATCH21", test_raw_oplock_batch21); torture_suite_add_2smb_test(suite, "BATCH22", test_raw_oplock_batch22); torture_suite_add_2smb_test(suite, "BATCH23", test_raw_oplock_batch23); + torture_suite_add_2smb_test(suite, "BATCH24", test_raw_oplock_batch24); return suite; } From e24d47ec2e2020d19167061e3c8eea670911dfde Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 16:27:13 +0100 Subject: [PATCH 19/34] RAW-OPLOCK: rename _ack_to_levelII() -> ack_to_given() Also improve the output. metze (This used to be commit d0b641a9ee36939468beb427bf6b15892342a33d) --- source4/torture/raw/oplock.c | 136 +++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 61 deletions(-) diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index ae52092c872..1926b121289 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -71,16 +71,30 @@ static struct { /* a handler function for oplock break requests. Ack it as a break to level II if possible */ -static bool oplock_handler_ack_to_levelII(struct smbcli_transport *transport, - uint16_t tid, uint16_t fnum, - uint8_t level, void *private) +static bool oplock_handler_ack_to_given(struct smbcli_transport *transport, + uint16_t tid, uint16_t fnum, + uint8_t level, void *private) { struct smbcli_tree *tree = (struct smbcli_tree *)private; + const char *name; + break_info.fnum = fnum; break_info.level = level; break_info.count++; - printf("Acking to level II in oplock handler\n"); + switch (level) { + case OPLOCK_BREAK_TO_LEVEL_II: + name = "level II"; + break; + case OPLOCK_BREAK_TO_NONE: + name = "none"; + break; + default: + name = "unknown"; + break_info.failures++; + } + printf("Acking to %s [0x%02X] in oplock handler\n", + name, level); return smbcli_oplock_ack(tree, fnum, level); } @@ -198,7 +212,7 @@ static bool test_raw_oplock_exclusive1(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -263,7 +277,7 @@ static bool test_raw_oplock_exclusive2(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -358,7 +372,7 @@ static bool test_raw_oplock_exclusive3(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -427,7 +441,7 @@ static bool test_raw_oplock_exclusive4(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -446,7 +460,7 @@ static bool test_raw_oplock_exclusive4(struct torture_context *tctx, struct smbc torture_comment(tctx, "open with exclusive oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; status = smb_raw_open(cli1->tree, tctx, &io); @@ -491,8 +505,8 @@ static bool test_raw_oplock_exclusive5(struct torture_context *tctx, struct smbc /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -511,7 +525,7 @@ static bool test_raw_oplock_exclusive5(struct torture_context *tctx, struct smbc torture_comment(tctx, "open with exclusive oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK; @@ -566,7 +580,7 @@ static bool test_raw_oplock_exclusive6(struct torture_context *tctx, struct smbc smbcli_unlink(cli1->tree, fname1); smbcli_unlink(cli1->tree, fname2); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -639,7 +653,7 @@ static bool test_raw_oplock_batch1(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -723,7 +737,7 @@ static bool test_raw_oplock_batch2(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -801,7 +815,7 @@ static bool test_raw_oplock_batch3(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -865,7 +879,7 @@ static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -884,7 +898,7 @@ static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "a self read should not cause a break\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -928,7 +942,7 @@ static bool test_raw_oplock_batch5(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -947,7 +961,7 @@ static bool test_raw_oplock_batch5(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "a 2nd open should give a break\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -993,7 +1007,7 @@ static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1012,8 +1026,8 @@ static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "a 2nd open should give a break to level II if the first open allowed shared read\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; @@ -1073,7 +1087,7 @@ static bool test_raw_oplock_batch7(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1143,7 +1157,7 @@ static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1162,7 +1176,7 @@ static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "open with batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1212,7 +1226,7 @@ static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_s /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1244,7 +1258,7 @@ static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1263,8 +1277,8 @@ static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_s torture_comment(tctx, "third oplocked open should grant level2 without break\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK; @@ -1317,7 +1331,7 @@ static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1348,7 +1362,7 @@ static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_ CHECK_VAL(break_info.failures, 0); CHECK_VAL(io.ntcreatex.out.oplock_level, 0); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1426,7 +1440,7 @@ static bool test_raw_oplock_batch11(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1447,7 +1461,7 @@ static bool test_raw_oplock_batch11(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "Test if setpathinfo set EOF breaks oplocks.\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1501,7 +1515,7 @@ static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1522,7 +1536,7 @@ static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "Test if setpathinfo allocation size breaks oplocks.\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1575,8 +1589,8 @@ static bool test_raw_oplock_batch13(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1595,7 +1609,7 @@ static bool test_raw_oplock_batch13(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "open with batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | @@ -1653,7 +1667,7 @@ static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1672,7 +1686,7 @@ static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "open with batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1729,7 +1743,7 @@ static bool test_raw_oplock_batch15(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1750,7 +1764,7 @@ static bool test_raw_oplock_batch15(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "Test if qpathinfo all info breaks a batch oplock (should not).\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK | @@ -1801,8 +1815,8 @@ static bool test_raw_oplock_batch16(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1821,7 +1835,7 @@ static bool test_raw_oplock_batch16(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "open with batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | @@ -1883,7 +1897,7 @@ static bool test_raw_oplock_batch17(struct torture_context *tctx, struct smbcli_ smbcli_unlink(cli1->tree, fname1); smbcli_unlink(cli1->tree, fname2); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -1961,7 +1975,7 @@ static bool test_raw_oplock_batch18(struct torture_context *tctx, struct smbcli_ smbcli_unlink(cli1->tree, fname1); smbcli_unlink(cli1->tree, fname2); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -2045,7 +2059,7 @@ static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_ smbcli_unlink(cli1->tree, fname2); smbcli_unlink(cli1->tree, fname3); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -2147,7 +2161,7 @@ static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_ smbcli_unlink(cli1->tree, fname2); smbcli_unlink(cli1->tree, fname3); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -2273,7 +2287,7 @@ static bool test_raw_oplock_batch21(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -2346,7 +2360,7 @@ static bool test_raw_oplock_batch22(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); /* base ntcreatex parms @@ -2395,7 +2409,7 @@ static bool test_raw_oplock_batch22(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "a 2nd open shoud succeed after the oplock release without break\n"); tv = timeval_current(); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); status = smb_raw_open(cli1->tree, tctx, &io); CHECK_STATUS(tctx, status, NT_STATUS_OK); CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN); @@ -2436,7 +2450,7 @@ static bool test_raw_oplock_batch23(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); ret = open_connection_no_level2_oplocks(tctx, &cli3); CHECK_VAL(ret, true); @@ -2458,9 +2472,9 @@ static bool test_raw_oplock_batch23(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "a open and ask for a batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); - smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_levelII, cli3->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); + smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_given, cli3->tree); io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; @@ -2523,7 +2537,7 @@ static bool test_raw_oplock_batch24(struct torture_context *tctx, struct smbcli_ /* cleanup */ smbcli_unlink(cli1->tree, fname); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); ret = open_connection_no_level2_oplocks(tctx, &cli3); CHECK_VAL(ret, true); @@ -2545,9 +2559,9 @@ static bool test_raw_oplock_batch24(struct torture_context *tctx, struct smbcli_ torture_comment(tctx, "a open without level support and ask for a batch oplock\n"); ZERO_STRUCT(break_info); - smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree); - smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree); - smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_levelII, cli3->tree); + smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree); + smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree); + smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_given, cli3->tree); io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; From 74dba5e33ce0b7b1d7e092b1029979f26fb8b727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Tue, 4 Mar 2008 12:26:05 +0100 Subject: [PATCH 20/34] Add new Windows 2008 Kerberos PAC Type 12 (apparently again undocumented). We need at least to parse this in order to correctly support kerberized session setup from w2k8 as well as local pam_winbind logons using kerberos. Guenther (cherry picked from commit 4ba62d49d740c43cf17ceef1534cf1c8a7e4a130) (This used to be commit ef0971206cda598e6bfad2ff06a3d2e9e8131682) --- source4/librpc/idl/krb5pac.idl | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/source4/librpc/idl/krb5pac.idl b/source4/librpc/idl/krb5pac.idl index efd4aa860ff..eed68e13873 100644 --- a/source4/librpc/idl/krb5pac.idl +++ b/source4/librpc/idl/krb5pac.idl @@ -31,6 +31,19 @@ interface krb5pac samr_RidWithAttributeArray res_groups; } PAC_LOGON_INFO; + typedef struct { + [value(2*strlen_m(upn_name))] uint16 upn_size; + uint16 unknown1; /* 0x10 */ + [value(2*strlen_m(domain_name))] uint16 domain_size; + uint16 unknown2; /* 0x50 */ + uint16 unknown3; /* 0x01 */ + uint16 unknown4; + uint32 unknown5; + [charset(UTF16)] uint8 upn_name[upn_size+2]; + [charset(UTF16)] uint8 domain_name[domain_size+2]; + uint32 unknown6; + } PAC_UNKNOWN_12; + typedef [public] struct { [value(0x00081001)] uint32 unknown1; [value(0xCCCCCCCC)] uint32 unknown2; @@ -44,7 +57,8 @@ interface krb5pac PAC_TYPE_SRV_CHECKSUM = 6, PAC_TYPE_KDC_CHECKSUM = 7, PAC_TYPE_LOGON_NAME = 10, - PAC_TYPE_CONSTRAINED_DELEGATION = 11 + PAC_TYPE_CONSTRAINED_DELEGATION = 11, + PAC_TYPE_UNKNOWN_12 = 12 } PAC_TYPE; typedef [public,nodiscriminant,gensize] union { @@ -52,6 +66,7 @@ interface krb5pac [case(PAC_TYPE_SRV_CHECKSUM)] PAC_SIGNATURE_DATA srv_cksum; [case(PAC_TYPE_KDC_CHECKSUM)] PAC_SIGNATURE_DATA kdc_cksum; [case(PAC_TYPE_LOGON_NAME)] PAC_LOGON_NAME logon_name; + [case(PAC_TYPE_UNKNOWN_12)] PAC_UNKNOWN_12 unknown; } PAC_INFO; typedef [public,nopush,nopull,noprint] struct { From 62af65d1e3b530c81d61c181b84934419fe840da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Thu, 6 Mar 2008 14:15:07 +0100 Subject: [PATCH 21/34] Slowly making progress on PAC_UNKNOWN_12. unknown1 and unknown2 are offset headers for the strings. Guenther (cherry picked from commit 7af70e75b9abf92921f33ec4207ad486ee2493d6) (This used to be commit ad19da7f83761948f379921560da34bb6a01e625) --- source4/librpc/idl/krb5pac.idl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source4/librpc/idl/krb5pac.idl b/source4/librpc/idl/krb5pac.idl index eed68e13873..ef2d9d4182a 100644 --- a/source4/librpc/idl/krb5pac.idl +++ b/source4/librpc/idl/krb5pac.idl @@ -33,15 +33,15 @@ interface krb5pac typedef struct { [value(2*strlen_m(upn_name))] uint16 upn_size; - uint16 unknown1; /* 0x10 */ + uint16 upn_offset; [value(2*strlen_m(domain_name))] uint16 domain_size; - uint16 unknown2; /* 0x50 */ + uint16 domain_offset; uint16 unknown3; /* 0x01 */ uint16 unknown4; uint32 unknown5; [charset(UTF16)] uint8 upn_name[upn_size+2]; [charset(UTF16)] uint8 domain_name[domain_size+2]; - uint32 unknown6; + uint32 unknown6; /* padding */ } PAC_UNKNOWN_12; typedef [public] struct { From 7eaa6b5f9a316d658c3ecf98b44a4cdf8a2de512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Thu, 6 Mar 2008 16:41:24 +0100 Subject: [PATCH 22/34] Ignore Kerberos PAC type 12. Until we worked out the PAC_TYPE_UNKNOWN_12 format (or received documentation) ignore it so that the PAC parsing can proceed. Guenther (cherry picked from commit 3630ec26c99fdea46c47117d026f9bffb2c4590a) (This used to be commit 0c1ccbc183c1d2967da2d9a17033f3b116ff7387) --- source4/librpc/idl/krb5pac.idl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source4/librpc/idl/krb5pac.idl b/source4/librpc/idl/krb5pac.idl index ef2d9d4182a..3505fc895ce 100644 --- a/source4/librpc/idl/krb5pac.idl +++ b/source4/librpc/idl/krb5pac.idl @@ -61,12 +61,17 @@ interface krb5pac PAC_TYPE_UNKNOWN_12 = 12 } PAC_TYPE; + typedef struct { + [flag(NDR_REMAINING)] DATA_BLOB remaining; + } DATA_BLOB_REM; + typedef [public,nodiscriminant,gensize] union { [case(PAC_TYPE_LOGON_INFO)] PAC_LOGON_INFO_CTR logon_info; [case(PAC_TYPE_SRV_CHECKSUM)] PAC_SIGNATURE_DATA srv_cksum; [case(PAC_TYPE_KDC_CHECKSUM)] PAC_SIGNATURE_DATA kdc_cksum; [case(PAC_TYPE_LOGON_NAME)] PAC_LOGON_NAME logon_name; - [case(PAC_TYPE_UNKNOWN_12)] PAC_UNKNOWN_12 unknown; + [case(PAC_TYPE_UNKNOWN_12)] [subcontext(0)] DATA_BLOB_REM unknown; + /* [case(PAC_TYPE_UNKNOWN_12)] PAC_UNKNOWN_12 unknown; */ } PAC_INFO; typedef [public,nopush,nopull,noprint] struct { @@ -82,10 +87,6 @@ interface krb5pac PAC_BUFFER buffers[num_buffers]; } PAC_DATA; - typedef struct { - [flag(NDR_REMAINING)] DATA_BLOB remaining; - } DATA_BLOB_REM; - typedef [public] struct { PAC_TYPE type; uint32 ndr_size; From 8b24d248b7c928fd3b20f95ede34302ca274c4ae Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Mar 2008 07:33:14 +1100 Subject: [PATCH 23/34] Start to rework provision for LDAP backends This is the start of the rework of the provision script to handle an LDAP backend correctly. For example, we must not set the 'tdb modules' against an LDAP backend such as OpenLDAP that handles subtree renames. Andrew Bartlett (This used to be commit e462a107d3bafcc546ca4d53dcc8eb32e4280745) --- source4/scripting/python/samba/__init__.py | 7 ++++++- source4/scripting/python/samba/provision.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 8d5f4250c95..e91b320c073 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -147,7 +147,12 @@ class Ldb(ldb.Ldb): k = 0 while ++k < 10 and (previous_remaining != current_remaining): # and the rest - res2 = self.search(basedn, ldb.SCOPE_SUBTREE, "(|(objectclass=*)(distinguishedName=*))", ["distinguishedName"]) + try: + res2 = self.search(basedn, ldb.SCOPE_SUBTREE, "(|(objectclass=*)(distinguishedName=*))", ["distinguishedName"]) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore missing dn errors + return + previous_remaining = current_remaining current_remaining = len(res2) for msg in res2: diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ea2feb981bb..b140071f41f 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -341,12 +341,21 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, if ldap_backend_type == "fedora-ds": backend_modules = ["nsuniqueid", "paged_searches"] + # We can handle linked attributes here, as we don't have directory-side subtree operations + tdb_modules_list = ["linked_attributes"] elif ldap_backend_type == "openldap": backend_modules = ["normalise", "entryuuid", "paged_searches"] + # OpenLDAP handles subtree renames, so we don't want to do any of these things + tdb_modules_list = None elif serverrole == "domain controller": backend_modules = ["repl_meta_data"] else: backend_modules = ["objectguid"] + + if tdb_modules_list is None: + tdb_modules_list_as_string = "" + else: + tdb_modules_list_as_string = ","+",".join(tdb_modules_list) samdb.transaction_start() try: @@ -362,7 +371,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "CONFIGDN_MOD": "naming_fsmo,instancetype", "DOMAINDN_MOD": "pdc_fsmo,password_hash,instancetype", "MODULES_LIST": ",".join(modules_list), - "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), + "TDB_MODULES_LIST": tdb_modules_list_as_string, "MODULES_LIST2": ",".join(modules_list2), "BACKEND_MOD": ",".join(backend_modules), }) From 45149fbf9d3e55e17e21ab4a6159e9b805adc06d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Mar 2008 09:05:24 +1100 Subject: [PATCH 24/34] Fixup the NET-API-USERMOD test. This test needed to be updated to handle the fact that you cannot clear the ACB_PW_EXPIRED bit, and to always use the torture comment functions (not printf directly). Andrew Bartlett (This used to be commit 2211476bbb3d8e5bca9659e886e559a36f40aff4) --- source4/torture/libnet/libnet_user.c | 4 ++-- source4/torture/libnet/userman.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source4/torture/libnet/libnet_user.c b/source4/torture/libnet/libnet_user.c index 31300a79377..5446087034b 100644 --- a/source4/torture/libnet/libnet_user.c +++ b/source4/torture/libnet/libnet_user.c @@ -339,9 +339,9 @@ static void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r, const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" }; const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" }; const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" }; - const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL), + const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED), (ACB_NORMAL | ACB_PWNOEXP), - (ACB_NORMAL) }; + (ACB_NORMAL | ACB_PW_EXPIRED) }; const char *homedir, *homedrive, *logonscript; struct timeval now; int i, testfld; diff --git a/source4/torture/libnet/userman.c b/source4/torture/libnet/userman.c index 5ce0a64022c..a5d8540d7b2 100644 --- a/source4/torture/libnet/userman.c +++ b/source4/torture/libnet/userman.c @@ -88,9 +88,9 @@ static bool test_usermod(struct torture_context *tctx, struct dcerpc_pipe *p, const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" }; const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" }; const char *homedir, *homedrive, *logonscript; - const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL), + const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED), (ACB_NORMAL | ACB_PWNOEXP), - (ACB_NORMAL) }; + (ACB_NORMAL | ACB_PW_EXPIRED) }; NTSTATUS status; struct timeval now; @@ -201,7 +201,7 @@ static bool test_usermod(struct torture_context *tctx, struct dcerpc_pipe *p, break; } - printf(((i < num_changes - 1) ? "%s," : "%s"), fldname); + torture_comment(tctx, ((i < num_changes - 1) ? "%s," : "%s"), fldname); } torture_comment(tctx, "]\n"); From 14c5f968e1f99ceabc5a42d9a38a00ea137b00ea Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Mar 2008 10:57:52 +1100 Subject: [PATCH 25/34] Rework provision scripts for more testing This fixes up some issues with testdir (was not honoured) and increases test coverage. We now check all the major provision modes. In doing so, to make it possible to call from the multiple layers of 'sh', I have allowed 'dc' to alias 'domain controller' and 'member' to alias 'member server'. Fighting shell quoting in the test system was just too hard... Also fix upgrade.py Andrew Bartlett (This used to be commit 0923de12282b0e063dd73bc3e056dd5c3663c190) --- source4/param/loadparm.c | 2 ++ source4/scripting/python/samba/provision.py | 29 ++++++++++++--------- source4/scripting/python/samba/upgrade.py | 5 +--- source4/setup/provision | 20 ++++++++------ source4/setup/provision.smb.conf.dc | 4 +-- source4/setup/provision.smb.conf.member | 4 +-- source4/setup/provision.smb.conf.standalone | 4 +-- source4/setup/tests/blackbox_provision.sh | 5 +++- 8 files changed, 41 insertions(+), 32 deletions(-) diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index 65ce7595fca..a1d29b07711 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -316,7 +316,9 @@ static const struct enum_list enum_smb_signing_vals[] = { static const struct enum_list enum_server_role[] = { {ROLE_STANDALONE, "standalone"}, {ROLE_DOMAIN_MEMBER, "member server"}, + {ROLE_DOMAIN_MEMBER, "member"}, {ROLE_DOMAIN_CONTROLLER, "domain controller"}, + {ROLE_DOMAIN_CONTROLLER, "dc"}, {-1, NULL} }; diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 37c4c5b082d..25c1a995ef5 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -572,9 +572,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, :note: This will wipe the main SAM database file! """ - assert serverrole in ("domain controller", "member server") - - erase = (fill != FILL_DRS) + erase = (fill != FILL_DRS) # Also wipes the database setup_samdb_partitions(path, setup_path, schemadn=schemadn, configdn=configdn, @@ -796,17 +794,22 @@ def provision(setup_dir, message, session_info, if not os.path.exists(os.path.join(targetdir, "etc")): os.mkdir(os.path.join(targetdir, "etc")) - if smbconf is None: - smbconf = os.path.join(targetdir, os.path.join("etc", "smb.conf")) + smbconf = os.path.join(targetdir, os.path.join("etc", "smb.conf")) # only install a new smb.conf if there isn't one there already + if not os.path.exists(smbconf): message("Setting up smb.conf") - assert serverrole is not None + if serverrole is None: + serverrole = "standalone" + + assert serverrole in ("domain controller", "member server", "standalone") if serverrole == "domain controller": smbconfsuffix = "dc" elif serverrole == "member server": smbconfsuffix = "member" + elif serverrole == "standalone": + smbconfsuffix = "standalone" assert domain is not None assert realm is not None @@ -827,8 +830,8 @@ def provision(setup_dir, message, session_info, setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), smbconf, { "HOSTNAME": hostname, - "DOMAIN_CONF": domain, - "REALM_CONF": realm, + "DOMAIN": domain, + "REALM": realm, "SERVERROLE": serverrole, "NETLOGONPATH": netlogon, "SYSVOLPATH": sysvol, @@ -841,7 +844,7 @@ def provision(setup_dir, message, session_info, if serverrole is None: serverrole = lp.get("server role") - assert serverrole in ("domain controller", "member server") + assert serverrole in ("domain controller", "member server", "standalone") if invocationid is None and serverrole == "domain controller": invocationid = uuid.random() @@ -851,6 +854,10 @@ def provision(setup_dir, message, session_info, assert realm is not None realm = realm.upper() + if lp.get("realm").upper() != realm.upper(): + raise Exception("realm '%s' in %s must match chosen realm '%s'" % + (lp.get("realm"), smbconf, realm)) + dnsdomain = realm.lower() paths = provision_paths_from_lp(lp, dnsdomain) @@ -896,10 +903,6 @@ def provision(setup_dir, message, session_info, message("Provisioning for %s in realm %s" % (domain, realm)) message("Using administrator password: %s" % adminpass) - if lp.get("realm").upper() != realm.upper(): - raise Exception("realm '%s' in smb.conf must match chosen realm '%s'" % - (lp.get("realm"), realm)) - # only install a new shares config db if there is none if not os.path.exists(paths.shareconf): message("Setting up share.ldb") diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index 01b62ff9840..c5086846d82 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -218,11 +218,9 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: serverrole = "member server" - lp.set("server role", serverrole) domainname = oldconf.get("workgroup") if domainname: domainname = str(domainname) - lp.set("workgroup", domainname) realm = oldconf.get("realm") netbiosname = oldconf.get("netbios name") @@ -235,7 +233,6 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, if realm is None: realm = domainname.lower() message("No realm specified in smb.conf file, assuming '%s'\n" % realm) - lp.set("realm", realm) domainguid = secrets_db.get_domain_guid(domainname) domainsid = secrets_db.get_sid(domainname) @@ -247,7 +244,7 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: machinepass = None - domaindn = provision(lp=lp, setup_dir=setup_dir, message=message, + domaindn = provision(setup_dir=setup_dir, message=message, samdb_fill=FILL_DRS, paths=paths, session_info=session_info, credentials=credentials, realm=realm, domain=domainname, domainsid=domainsid, domainguid=domainguid, diff --git a/source4/setup/provision b/source4/setup/provision index 606443a6edf..629bfa10e0f 100755 --- a/source4/setup/provision +++ b/source4/setup/provision @@ -88,7 +88,7 @@ parser.add_option("--ldap-backend-type", type="choice", metavar="LDAP-BACKEND-TY parser.add_option("--aci", type="string", metavar="ACI", help="An arbitary LDIF fragment, particularly useful to loading a backend ACI value into a target LDAP server. You must provide at least a realm and domain") parser.add_option("--server-role", type="choice", metavar="ROLE", - choices=["domain controller", "member server"], + choices=["domain controller", "dc", "member server", "member", "standalone"], help="Set server role to provision for (default standalone)") parser.add_option("--partitions-only", help="Configure Samba's partitions, but do not modify them (ie, join a BDC)", action="store_true") @@ -110,14 +110,18 @@ if opts.realm is None or opts.domain is None: parser.print_usage() sys.exit(1) -# cope with an initially blank smb.conf - -if sambaopts.get_loadparm_path() is not None: - smbconf = sambaopts.get_loadparm_path() +smbconf = sambaopts.get_loadparm_path() if opts.aci is not None: print "set ACI: %s" % opts.aci +if opts.server_role == "dc": + server_role = "domain controller" +elif opts.server_role == "member": + server_role = "member server" +else: + server_role = opts.server_role + creds = credopts.get_credentials() setup_dir = opts.setupdir @@ -131,8 +135,8 @@ elif opts.partitions_only: samdb_fill = FILL_DRS provision(setup_dir, message, - system_session(), creds, smbconf=smbconf, - samdb_fill=samdb_fill, realm=opts.realm, + system_session(), creds, smbconf=smbconf, targetdir=opts.targetdir, + samdb_fill=samdb_fill, realm=opts.realm, domain=opts.domain, domainguid=opts.domain_guid, domainsid=opts.domain_sid, policyguid=opts.policy_guid, hostname=opts.host_name, hostip=opts.host_ip, hostguid=opts.host_guid, @@ -140,7 +144,7 @@ provision(setup_dir, message, krbtgtpass=opts.krbtgtpass, machinepass=opts.machinepass, dnspass=opts.dnspass, root=opts.root, nobody=opts.nobody, nogroup=opts.nogroup, wheel=opts.wheel, users=opts.users, - aci=opts.aci, serverrole=opts.server_role, + aci=opts.aci, serverrole=server_role, ldap_backend=opts.ldap_backend, ldap_backend_type=opts.ldap_backend_type) diff --git a/source4/setup/provision.smb.conf.dc b/source4/setup/provision.smb.conf.dc index e77e6990284..ad06be43013 100644 --- a/source4/setup/provision.smb.conf.dc +++ b/source4/setup/provision.smb.conf.dc @@ -1,7 +1,7 @@ [globals] netbios name = ${HOSTNAME} - workgroup = ${DOMAIN_CONF} - realm = ${REALM_CONF} + workgroup = ${DOMAIN} + realm = ${REALM} server role = ${SERVERROLE} ${PRIVATEDIR_LINE} ${LOCKDIR_LINE} diff --git a/source4/setup/provision.smb.conf.member b/source4/setup/provision.smb.conf.member index 1d9191d8c2e..0d742fb9034 100644 --- a/source4/setup/provision.smb.conf.member +++ b/source4/setup/provision.smb.conf.member @@ -1,7 +1,7 @@ [globals] netbios name = ${HOSTNAME} - workgroup = ${DOMAIN_CONF} - realm = ${REALM_CONF} + workgroup = ${DOMAIN} + realm = ${REALM} server role = ${SERVERROLE} ${PRIVATEDIR_LINE} ${LOCKDIR_LINE} diff --git a/source4/setup/provision.smb.conf.standalone b/source4/setup/provision.smb.conf.standalone index 1d9191d8c2e..0d742fb9034 100644 --- a/source4/setup/provision.smb.conf.standalone +++ b/source4/setup/provision.smb.conf.standalone @@ -1,7 +1,7 @@ [globals] netbios name = ${HOSTNAME} - workgroup = ${DOMAIN_CONF} - realm = ${REALM_CONF} + workgroup = ${DOMAIN} + realm = ${REALM} server role = ${SERVERROLE} ${PRIVATEDIR_LINE} ${LOCKDIR_LINE} diff --git a/source4/setup/tests/blackbox_provision.sh b/source4/setup/tests/blackbox_provision.sh index 0aed7bb8b79..83c045e40d7 100755 --- a/source4/setup/tests/blackbox_provision.sh +++ b/source4/setup/tests/blackbox_provision.sh @@ -27,7 +27,10 @@ testit() { return $status } -testit "simple" $PYTHON ./setup/provision $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple +testit "simple-default" $PYTHON ./setup/provision $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple-default +testit "simple-dc" $PYTHON ./setup/provision $CONFIGURATION --server-role="dc" --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple-dc +testit "simple-member" $PYTHON ./setup/provision $CONFIGURATION --server-role="member" --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple-member +testit "simple-standalone" $PYTHON ./setup/provision $CONFIGURATION --server-role="standalone" --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple-standalone reprovision() { $PYTHON ./setup/provision $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir="$PREFIX/reprovision" From a7e1fa0bef17ecc46f642b23ef635acfb09fea04 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Mar 2008 19:20:39 +1100 Subject: [PATCH 26/34] Try to fix up part of the upgrade test. There are still problems with the upgrade test, but these are not related to the provision system. Andrew Bartlett (This used to be commit d331bc400fb138bc43be88d0ca8ab3bcd590d2cd) --- source4/scripting/python/samba/provision.py | 13 ++++++++++++- source4/scripting/python/samba/upgrade.py | 20 +++++++++----------- source4/setup/upgrade.py | 12 ++---------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 25c1a995ef5..ebca1f8e40a 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -68,6 +68,12 @@ class ProvisionPaths: self.winsdb = None self.private_dir = None +class ProvisionResult: + def __init__(self): + self.paths = None + self.domaindn = None + self.lp = None + self.samdb = None def check_install(lp, session_info, credentials): """Check whether the current install seems ok. @@ -991,7 +997,12 @@ def provision(setup_dir, message, session_info, message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) - return domaindn + result = ProvisionResult() + result.domaindn = domaindn + result.paths = paths + result.lp = lp + result.samdb = samdb + return result def provision_become_dc(setup_dir=None, smbconf=None, targetdir=None, realm=None, diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py index c5086846d82..f40f2cffe7f 100644 --- a/source4/scripting/python/samba/upgrade.py +++ b/source4/scripting/python/samba/upgrade.py @@ -207,7 +207,7 @@ def import_wins(samba4_winsdb, samba3_winsdb): "objectClass": "winsMaxVersion", "maxVersion": str(version_id)}) -def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, paths): +def upgrade_provision(samba3, setup_dir, message, credentials, session_info, smbconf, targetdir): oldconf = samba3.get_conf() if oldconf.get("domain logons") == "True": @@ -244,15 +244,13 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, else: machinepass = None - domaindn = provision(setup_dir=setup_dir, message=message, - samdb_fill=FILL_DRS, paths=paths, session_info=session_info, - credentials=credentials, realm=realm, - domain=domainname, domainsid=domainsid, domainguid=domainguid, - machinepass=machinepass, serverrole=serverrole) + result = provision(setup_dir=setup_dir, message=message, + samdb_fill=FILL_DRS, smbconf=smbconf, session_info=session_info, + credentials=credentials, realm=realm, + domain=domainname, domainsid=domainsid, domainguid=domainguid, + machinepass=machinepass, serverrole=serverrole, targetdir=targetdir) - samdb = SamDB(paths.samdb, credentials=credentials, lp=lp, session_info=session_info) - - import_wins(Ldb(paths.winsdb), samba3.get_wins_db()) + import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db()) # FIXME: import_registry(registry.Registry(), samba3.get_registry()) @@ -268,12 +266,12 @@ def upgrade_provision(samba3, setup_dir, message, credentials, session_info, lp, passdb = samba3.get_sam_db() for name in passdb: user = passdb[name] - #FIXME: import_sam_account(samdb, user, domaindn, domainsid) + #FIXME: import_sam_account(result.samdb, user, domaindn, domainsid) if hasattr(passdb, 'ldap_url'): message("Enabling Samba3 LDAP mappings for SAM database") - enable_samba3sam(samdb, passdb.ldap_url) + enable_samba3sam(result.samdb, passdb.ldap_url) def enable_samba3sam(samdb, ldapurl): diff --git a/source4/setup/upgrade.py b/source4/setup/upgrade.py index 960cd1b9e22..569b1795442 100755 --- a/source4/setup/upgrade.py +++ b/source4/setup/upgrade.py @@ -50,7 +50,6 @@ else: samba3 = Samba3(libdir, smbconf) from samba.upgrade import upgrade_provision -from samba.provision import provision_paths_from_lp message("Provisioning\n") @@ -59,13 +58,6 @@ if setup_dir is None: setup_dir = "setup" creds = credopts.get_credentials() -lp = sambaopts.get_loadparm() -if opts.targetdir is not None: - if not os.path.exists(opts.targetdir): - os.mkdir(opts.targetdir) - lp.set("private dir", os.path.abspath(opts.targetdir)) - lp.set("lock dir", os.path.abspath(opts.targetdir)) -paths = provision_paths_from_lp(lp, "") -paths.smbconf = sambaopts.get_loadparm_path() + upgrade_provision(samba3, setup_dir, message, credentials=creds, session_info=system_session(), - lp=lp, paths=paths) + smbconf=sambaopts.get_loadparm_path(), targetdir=opts.targetdir) From 17af5a9f42e2ee8c342b4d20928da5b0e7d00045 Mon Sep 17 00:00:00 2001 From: Amin Azez Date: Fri, 7 Mar 2008 10:55:49 +0000 Subject: [PATCH 27/34] Use 32 bit storage for nttrans counts Erroneous 16bit storage for nttrans counts meant that nttrans behaved "strangely" for sizes of over 64K As 32 bit is used in the SMB message and specified in http://us4.samba.org/samba/ftp/specs/draft-leach-cifs-v1-spec-02.txt section 3.13.2 this fix changes storage to match. Signed-off-by: Amin Azez (This used to be commit d66b6c3823f003875e3b7cdf63617a894cceadf9) --- source4/smb_server/smb/nttrans.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source4/smb_server/smb/nttrans.c b/source4/smb_server/smb/nttrans.c index f6edc407d67..a20c41ba4d0 100644 --- a/source4/smb_server/smb/nttrans.c +++ b/source4/smb_server/smb/nttrans.c @@ -460,7 +460,7 @@ static NTSTATUS nttrans_backend(struct smbsrv_request *req, static void reply_nttrans_send(struct ntvfs_request *ntvfs) { struct smbsrv_request *req; - uint16_t params_left, data_left; + uint32_t params_left, data_left; uint8_t *params, *data; struct smb_nttrans *trans; struct nttrans_op *op; @@ -502,7 +502,7 @@ static void reply_nttrans_send(struct ntvfs_request *ntvfs) /* we need to divide up the reply into chunks that fit into the negotiated buffer size */ do { - uint16_t this_data, this_param, max_bytes; + uint32_t this_data, this_param, max_bytes; uint_t align1 = 1, align2 = (params_left ? 2 : 0); struct smbsrv_request *this_req; @@ -573,9 +573,9 @@ void smbsrv_reply_nttrans(struct smbsrv_request *req) { struct nttrans_op *op; struct smb_nttrans *trans; - uint16_t param_ofs, data_ofs; - uint16_t param_count, data_count; - uint16_t param_total, data_total; + uint32_t param_ofs, data_ofs; + uint32_t param_count, data_count; + uint32_t param_total, data_total; /* parse request */ if (req->in.wct < 19) { From 07cb435d40245fc199e67c3cc869cf1f654e9a94 Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Thu, 6 Mar 2008 05:56:49 -0600 Subject: [PATCH 28/34] accountExpires: Windows default is 9223372036854775807, not -1. (This used to be commit be47cc7fdfa3cae0508e564f38b793aa27b6eb92) --- source4/lib/ldb/tests/schema-tests/schema-add-test.ldif | 2 +- source4/setup/provision_templates.ldif | 4 ++-- source4/setup/provision_users.ldif | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source4/lib/ldb/tests/schema-tests/schema-add-test.ldif b/source4/lib/ldb/tests/schema-tests/schema-add-test.ldif index 997b801d840..472ab48fac9 100644 --- a/source4/lib/ldb/tests/schema-tests/schema-add-test.ldif +++ b/source4/lib/ldb/tests/schema-tests/schema-add-test.ldif @@ -46,7 +46,7 @@ pwdLastSet: 0 primaryGroupID: 513 objectSid: S-1-5-21-43662522-77495566-38969261-500 adminCount: 1 -accountExpires: -1 +accountExpires: 9223372036854775807 logonCount: 0 sAMAccountName: Administrator sAMAccountType: 0x30000000 diff --git a/source4/setup/provision_templates.ldif b/source4/setup/provision_templates.ldif index cc0ab212cdc..8f4ed082525 100644 --- a/source4/setup/provision_templates.ldif +++ b/source4/setup/provision_templates.ldif @@ -27,7 +27,7 @@ lastLogoff: 0 lastLogon: 0 pwdLastSet: 0 primaryGroupID: 513 -accountExpires: -1 +accountExpires: 9223372036854775807 logonCount: 0 dn: CN=TemplateTrustingDomain,CN=Templates @@ -39,7 +39,7 @@ badPasswordTime: 0 lastLogoff: 0 lastLogon: 0 primaryGroupID: 513 -accountExpires: -1 +accountExpires: 9223372036854775807 logonCount: 0 dn: CN=TemplateGroup,CN=Templates diff --git a/source4/setup/provision_users.ldif b/source4/setup/provision_users.ldif index 4b053d91663..5a24e074926 100644 --- a/source4/setup/provision_users.ldif +++ b/source4/setup/provision_users.ldif @@ -5,7 +5,7 @@ description: Built-in account for administering the computer/domain userAccountControl: 66048 objectSid: ${DOMAINSID}-500 adminCount: 1 -accountExpires: -1 +accountExpires: 9223372036854775807 sAMAccountName: Administrator isCriticalSystemObject: TRUE sambaPassword:: ${ADMINPASS_B64} From 01b3d89aeccdd7bd6bc2a9636e59f0c928cc22dc Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Thu, 6 Mar 2008 06:02:46 -0600 Subject: [PATCH 29/34] Add samdb_result_account_expires() function. Windows uses 2 different values to indicate an account doesn't expire: 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL). This function looks up the value of the accountExpires attribute and if the value is either value indicating the account doesn't expire, 0x7FFFFFFFFFFFFFFFULL is returned. This simplifies the tests for account expiration. There is no need to check elsewhere in the code for both values, therefore a simple greater-than expression can be used. (This used to be commit 7ce5575a3a40cca4a45ec179a153f7e909065a87) --- source4/dsdb/common/util.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index ace5e0edaf8..07a433780b4 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -433,6 +433,30 @@ NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME def return ldb_msg_find_attr_as_uint64(msg, attr, default_value); } +/* + * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to + * indicate an account doesn't expire. + * + * When Windows initially creates an account, it sets + * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However, + * when changing from an account having a specific expiration date to + * that account never expiring, it sets accountExpires = 0. + * + * Consolidate that logic here to allow clearer logic for account expiry in + * the rest of the code. + */ +NTTIME samdb_result_account_expires(struct ldb_message *msg, + NTTIME default_value) +{ + NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires", + default_value); + + if (ret == (NTTIME)0) + ret = 0x7FFFFFFFFFFFFFFFULL; + + return ret; +} + /* pull a uint64_t from a result set. */ From 20c701400961901e92315b4cd02038fff086e33d Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Thu, 6 Mar 2008 06:07:28 -0600 Subject: [PATCH 30/34] Update account expiration to use new samdb_result_account_expires() function. (This used to be commit 2b6b4e5a1611744eea5dd9ec17c416916d7edab4) --- source4/auth/sam.c | 4 ++-- source4/kdc/hdb-ldb.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source4/auth/sam.c b/source4/auth/sam.c index 9a8045f62d6..882196343c7 100644 --- a/source4/auth/sam.c +++ b/source4/auth/sam.c @@ -157,7 +157,7 @@ _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, domain_dn); - acct_expiry = samdb_result_nttime(msg, "accountExpires", 0); + acct_expiry = samdb_result_account_expires(msg, 0); /* Check for when we must change this password, taking the * userAccountControl flags into account */ @@ -351,7 +351,7 @@ _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_conte server_info->last_logon = samdb_result_nttime(msg, "lastLogon", 0); server_info->last_logoff = samdb_result_nttime(msg, "lastLogoff", 0); - server_info->acct_expiry = samdb_result_nttime(msg, "accountExpires", 0); + server_info->acct_expiry = samdb_result_account_expires(msg, 0); server_info->last_password_change = samdb_result_nttime(msg, "pwdLastSet", 0); ncname = samdb_result_dn(sam_ctx, mem_ctx, msg_domain_ref, "nCName", NULL); diff --git a/source4/kdc/hdb-ldb.c b/source4/kdc/hdb-ldb.c index 9a17e581e3f..bc5a45ae2bb 100644 --- a/source4/kdc/hdb-ldb.c +++ b/source4/kdc/hdb-ldb.c @@ -510,9 +510,8 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db, entry_ex->entry.valid_start = NULL; - acct_expiry = samdb_result_nttime(msg, "accountExpires", (NTTIME)-1); - if ((acct_expiry == (NTTIME)-1) || - (acct_expiry == 0x7FFFFFFFFFFFFFFFULL)) { + acct_expiry = samdb_result_account_expires(msg, 0); + if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) { entry_ex->entry.valid_end = NULL; } else { entry_ex->entry.valid_end = malloc(sizeof(*entry_ex->entry.valid_end)); From e9171397ecd2ab86ea64363f9a0230fc2104ed02 Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Thu, 6 Mar 2008 06:08:32 -0600 Subject: [PATCH 31/34] Enhance mappings of NTSTATUS to KRB5KDC errors. The enhanced mappings allow the Windows client to determine whether a user's password needs to be changed (and allows them to change it), or if they cannot logon at all. Changes still need to be made to allow additional data to be returned. Windows uses that additional data to display more detailed dialogs to the user. The additional information is returned in an e-data struct of type PA-PW-SALT that contains the more-detailed NTSTATUS error code. (This used to be commit 6a98e5a7aa0cdbb61358901df50162b5b914ee5c) --- source4/kdc/pac-glue.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index a99cf6ded85..66f36af870f 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -276,9 +276,28 @@ krb5_error_code samba_kdc_check_client_access(void *priv, /* TODO: Need a more complete mapping of NTSTATUS to krb5kdc errors */ - if (!NT_STATUS_IS_OK(nt_status)) { + /* TODO: Also need to add the appropriate e-data struct of type + * PA-PW-SALT (3) that includes the NT_STATUS code, which gives Windows + * the information it needs to display the appropriate dialog. */ + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) + return KRB5KDC_ERR_KEY_EXPIRED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) + return KRB5KDC_ERR_KEY_EXPIRED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) + return KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) + return KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) + return KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) + return KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) + return KRB5KDC_ERR_POLICY; + else if (!NT_STATUS_IS_OK(nt_status)) { return KRB5KDC_ERR_POLICY; } + return 0; } From a689d65e4ff393ca99051c385f9608b8050b7517 Mon Sep 17 00:00:00 2001 From: Andrew Kroeger Date: Fri, 7 Mar 2008 05:56:04 -0600 Subject: [PATCH 32/34] Treat maxPwdAge == 0 as passwords never expire. (This used to be commit d28f2cb678b334086f601505c88e56b9c1ee559d) --- source4/dsdb/common/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 07a433780b4..88c8afd6cca 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -517,7 +517,7 @@ NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL); if (maxPwdAge == 0) { - return 0; + return 0x7FFFFFFFFFFFFFFFULL; } else { attr_time -= maxPwdAge; } From ce4d94519fd056966e437255a837112f07ccebc2 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 7 Mar 2008 14:59:19 +0100 Subject: [PATCH 33/34] configure: Add major version 4 to AC_INIT call. Michael (This used to be commit 3a9514def21c448d344648d4a28f658fbcfc07eb) --- source4/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/configure.ac b/source4/configure.ac index 5ba441375c5..41f1bcf054b 100644 --- a/source4/configure.ac +++ b/source4/configure.ac @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. dnl disabled 2.53 requirement - we do work with 2.52 on suse 7.3 for example dnl AC_PREREQ(2.53) -AC_INIT([samba],[],[samba-technical@samba.org]) +AC_INIT([samba],[4],[samba-technical@samba.org]) AC_CONFIG_SRCDIR([include/includes.h]) AC_CONFIG_HEADER(include/config_tmp.h) From 97a272a4bf1178c1adcc5761d162b74c338dd230 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 7 Mar 2008 15:00:37 +0100 Subject: [PATCH 34/34] torture: fix escape sequence in test_chkpath(). Michael (This used to be commit d92597d29caf76e1c8d0858f066d7a30143392e9) --- source4/torture/raw/chkpath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/torture/raw/chkpath.c b/source4/torture/raw/chkpath.c index fa69c92caa9..7fd74e3cbee 100644 --- a/source4/torture/raw/chkpath.c +++ b/source4/torture/raw/chkpath.c @@ -150,7 +150,7 @@ static bool test_chkpath(struct smbcli_state *cli, struct torture_context *tctx) ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\f\\o\\o\\..\\..\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); - ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\\\\..\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); + ret &= test_path_ex(cli, tctx, ((char *)BASEDIR"\\foo\\\\..\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, BASEDIR"\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, BASEDIR"\\\\..\\"BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK); ret &= test_path_ex(cli, tctx, BASEDIR"\\\\\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK);