The branch, master has been updated via cd813f7 s3:gse_krb5: make use of precalculated krb5 keys in fill_mem_keytab_from_secrets() via 37e49a2 s3:secrets: allow secrets_fetch_or_upgrade_domain_info() on an AD DC via 0bb4d28 getncchanges.py: Add test for GET_ANC and linked attributes via 9f0ae6e getncchanges.py: Add GET_ANC replication test case via 4cfc296 getncchanges.py: Add a new test for replication via fae5df8 replmd: Try to add forward-link for unknown cross-partition links via 89cf5c3 replmd: Don't fail cycle if we get link for deleted object with GET_TGT via ab12aed replmd: Avoid dropping links if link target is deleted via 18ea167 replmd: Move where we store linked attributes via f812c29 drs_utils: Add GET_TGT support to 'samba-tool drs replicate --local' via f87332e replmd: Set GET_ANC if Windows sends a link with unknown source object via cc201c2 drepl: Support GET_TGT on periodic replication client via 67617d4 drs: Check target object is known after applying objects via f69596c drs: Fail replication transaction instead of dropping links via 04ce638 replmd: Split checking link attr target into new function via d13e7b9 werror: Add WERR_DS_DRA_RECYCLED_TARGET from 9fb2562 libcli/smb: debug an error if smb1cli_req_writev_submit() is called for SMB2/3
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit cd813f7fd9ee8e9d82a6bf6c98621c437f6974b2 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Aug 17 17:45:21 2017 +0200 s3:gse_krb5: make use of precalculated krb5 keys in fill_mem_keytab_from_secrets() This avoids a lot of cpu cycles, which were wasted for each single smb connection, even if the client didn't use kerberos. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12973 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> Autobuild-User(master): Andrew Bartlett <abart...@samba.org> Autobuild-Date(master): Fri Aug 18 10:04:57 CEST 2017 on sn-devel-144 commit 37e49a2af5bb1c40c17eab18ff9412f2ce79ef71 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Aug 17 21:42:34 2017 +0200 s3:secrets: allow secrets_fetch_or_upgrade_domain_info() on an AD DC The reason for the check is for write access as secrets.ldb is the master database. But secrets_fetch_or_upgrade_domain_info() just syncs the values we got from if they got overwritten by secrets_store_machine_pw_sync(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=12973 Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 0bb4d28272914736a46dc5cdb0bef766ba7a4ab8 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Wed Jul 12 10:16:00 2017 +1200 getncchanges.py: Add test for GET_ANC and linked attributes Add a basic test that when we use GET_ANC and the parents have linked attributes, then we receive all the expected links and all the expected objects by the end of the test. This extends the test code to track what linked attributes get received and check whether they match what's present on the DC. Also made some minor cleanups to store the received objects/links each time we successfully receive a GETNCChanges response (this saves the test case having to repeat this code every time). Note that although this test involves linked attributes, it shouldn't exercise the GET_TGT case at all. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit 9f0ae6e44d0f6def6be7c44067c7fcfdf0d42db2 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Tue Jun 6 18:21:40 2017 +1200 getncchanges.py: Add GET_ANC replication test case This test: - creates blocks of parent/child objects - modifies the parents, so the child gets received first in the replication (which means the client has to use GET_ANC) - checks that we always receive the parent before the child (if not, it either retries with GET_ANC, or asserts if GET_ANC is already set) - modifies the parent objects to change their USN while the replication is in progress - checks that all expected objects are received by the end of the test I've added a repl_get_next() function to help simulate a client's behaviour - if it encounters an object it doesn't know the parent of, then it retries with GET_ANC. Also added some debug to drs_base.py that developers can turn on to make it easier to see what objects we're actually receiving in the responses. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit 4cfc29688584ca69c43abb770d1e721d1eab1480 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Tue Jun 6 18:06:22 2017 +1200 getncchanges.py: Add a new test for replication This adds a new test to check that if objects are modified during a replication, then those objects don't wind up missing from the replication data. Note that when this scenario occurs, samba returns the objects in a different order to Windows. This test doesn't care what order the replicated objects get returned in, so long as they all have been received by the end of the test. As part of this, I've refactored _check_replication() in drs_base.py so it can be reused in new tests. In these cases, the objects are split up over multiple different chunks. So asserting that the objects are returned in a specific order makes it difficult to run the same test on both Samba and Windows. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit fae5df891c11f642cbede9e4e3d845c49c5f86b8 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Mon Jul 24 16:20:58 2017 +1200 replmd: Try to add forward-link for unknown cross-partition links Previously Samba would just drop cross-partition links where the link target object is unknown. Instead, what we want to do is try to add the forward link for the GUID specified. We can't add the backlink because we don't know the target, however, dbcheck should be able to fix any missing backlinks. The new behaviour should now mean dbcheck will detect the problem and be able to fix it. It's still not ideal, but it's better than dropping the link completely. I've updated the log so that it has higher severity and tells the user what they need to do to fix it. These changes now mean that the selftests now detect an error - instead of completely dropping the serverReference, we now have a missing backlink. I've updated the selftests to fix up any missing serverReference backlinks before running dbcheck. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit 89cf5c3f76e214fbd06ce461470eb64b338c5144 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Thu Jul 20 11:14:27 2017 +1200 replmd: Don't fail cycle if we get link for deleted object with GET_TGT We are going to end up supporting 2 different server schemes: A. the old/default behaviour of sending all the linked attributes last, at the end of the replication cycle. B. the new/Microsoft way of sending the linked attributes interleaved with the source/target objects. Normally if we're talking to a server using the old scheme-A, we won't ever use the GET_TGT flag. However, there are a couple of cases where it can happen: - A link to a new object was added during the replication cycle. - An object was deleted while the replication was in progress (and the linked attribute got queued before the object was deleted). Talking to an Samba DC running the old scheme will just cause it to start the replication cycle from scratch again, which is fairly harmless. However, there is a chance that the same thing can happen again, in which case the replication cycle will fail (because GET_TGT was already set). Even if we're using the new scheme (B), we could still potentially hit this case, as we can still queue up linked attributes between requests (group memberships can be larger than what can fit into a single replication chunk). If GET_TGT is set in the GetNcChanges request, then the local copy of the target object should always be up-to-date when we process the linked attribute. So if we still think the target object is deleted/recycled at this point, then it's safe to ignore the linked attribute (because we know our local copy is up-to-date). This logic matches the MS spec logic in ProcessLinkValue(). Not failing the replication cycle may be beneficial if we're trying to do a full-sync of a large database. Otherwise it might be time-consuming and frustrating to repeat the sync unnecessarily. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit ab12aed7e13a9c9663ba04b6dd4f02acb7bff380 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Wed Jul 19 16:18:20 2017 +1200 replmd: Avoid dropping links if link target is deleted The server-side can potentially send the linked attribute before the target-object. This happens on Microsoft, and will happen on Samba once server-side GET_TGT support is added. In these cases there is a hole where the Samba client can silently drop the linked attribute. If the old copy of the target object was deleted/recycled, then the client can receive the new linked attribute before it realizes the target has now been reincarnated. It silently ignores the linked attribute, thinking its receiving out of date information, when really it's the client's copy of the target object that's out of date. In this case we want to retry with the GET_TGT flag set, which will force the updated version of the target object to be sent along with the linked attribute. This deleted/recycled target case is the main reason that Windows added the GET_TGT flag. If the server sends all the links at the end, instead of along with the source object, then this case can still be hit. If so, it will cause the server to restart the replication from the beginning again. This is probably preferential to silently dropping links. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit 18ea167adef59b80982f13135947e58cb56a4f16 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Thu Jun 22 10:43:31 2017 +1200 replmd: Move where we store linked attributes There was a bug in my previous patch where the code would verify *all* links in the list, rather than just the ones that are new. And it would do this for every replication chunk it received, regardless of whether there were actually any links in that chunk. The problem is by the time we want to verify the attributes, we don't actually know which attributes are new. We can fix this by moving where we store the linked attributes from the start of processing the replication chunk to the end of processing the chunk. We can then verify the new linked attributes at the same time we store them. Longer-term we may want to try to apply the linked attribute at this point. This would save looking up the source/target objects twice, but it makes things a bit more complicated (attributes will usually apply at this point *most* of the time, but not *all* the time). Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit f812c29d4000ef35fa5d7f6007606ca53c5ed37a Author: Tim Beale <timbe...@catalyst.net.nz> Date: Fri Jun 16 12:54:32 2017 +1200 drs_utils: Add GET_TGT support to 'samba-tool drs replicate --local' Update drs_Replicate.replicate() so it handles being passed the GET_TGT flag (more_flags). To do this, we need to always use a v10 GetNCChanges request (v8 and v10 are essentially the same except for the more_flags). If the replicate_chunk() call into the C bindings throws an error, check to see whether the error could be fixed by setting the GET_TGT flag, and re-send the request if so. Unfortunately because WERR_DS_DRA_RECYCLED_TARGET isn't documented with the other AD error codes, I've left it hardcoded for now (Microsoft should be fixing up their Docs). Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit f87332eb35638cc38f83c580d4623ab978088601 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Fri Jun 16 09:49:16 2017 +1200 replmd: Set GET_ANC if Windows sends a link with unknown source object Windows replication can send the linked attribute before it sends the source object. The MS-DRSR spec says that in this case the client should resend the GetNCChanges request with the GET_ANC flag set. In my testing this resolves the problem - Windows will include the source object for the linked attribute in the same replication chunk. This problem doesn't happen with Samba-to-Samba replication, because the source object for the linked attribute is guaranteed to have already been sent. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit cc201c2c4f5d2dfd18f68143d001c5ba02c00b32 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Thu Jun 15 16:52:33 2017 +1200 drepl: Support GET_TGT on periodic replication client - Update IDL comments to include Microsoft reference doc - Add support for sending v10 GetNCChanges request (needed for the GET_TGT flag, which is in the new 'more_flags' field) - Update to also set the GET_TGT flag in the same place we were setting GET_ANC (I split this logic out into a separate function). - The state struct now needs to hold a 'more_flags' field as well (this flag is different to the GET_ANC replica flag) Note that using the GET_TGT when replicating from a Windows DC could be highly inefficient. Because Samba keeps the GET_TGT flag set throughout the replication cycle, it will basically receive a repeated object from Windows for every single linked attribute that it receives. I believe Windows behaviour only expects the client to set the GET_TGT flag when it actually needs to (i.e. when it receives a target object it doesn't know about), rather than throughout the replication cycle. However, this approach won't work with Samba-to-Samba replication, because when the server receives the GET_TGT flag it restarts the replication cycle from scratch. So if we only set the GET_TGT flag when the client encountered an unknown target then Samba-to-Samba could potentially get into an endless replication loop. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit 67617d470028b45c722c598944a17591cab1e6ba Author: Tim Beale <timbe...@catalyst.net.nz> Date: Thu Jun 15 14:09:27 2017 +1200 drs: Check target object is known after applying objects Currently we only check that the target object is known at the end of the transaction (i.e. the .prepare_commit hook). It's too late at this point to resend the request with GET_TGT. Move this processing earlier on, after we've applied all the objects (i.e. off the .extended hook). In reality, we need to perform the checks at both points. I've split the common code that gets the source/target details out of the la_entry into a helper function. It's not the greatest function ever, but seemed to make more sense than duplicating the code. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit f69596cd21d8106afdf494f39d1fcebea2b0f5dd Author: Tim Beale <timbe...@catalyst.net.nz> Date: Wed Jun 14 11:35:36 2017 +1200 drs: Fail replication transaction instead of dropping links If the DRS client received a linked attribute that it couldn't resolve the target for, then it would just ignore that link and keep going. That link would then be lost forever (although a full-sync would resolve this). Instead of silently ignoring the link, fail the transaction. This *can* happen on Samba, but it is unusual. The target object and linked-attribute would need to be added while a replication is still in progress. It can also happen fairly easily when talking to a Windows DC. There are two import exceptions to this: 1). Linked attributes that span partitions. We can never guarantee that we will have received the target object, because it may be in a partition we haven't replicated yet. Samba doesn't have a great way of handling this currently, but we shouldn't fail the replication (because that breaks basic join tests). Just skip that linked attribute and hope that a subsequent full-sync will fix it. (I queried Microsoft and they said resolving cross-partition linked attributes is a implementation-specific problem to solve. GET_TGT won't resolve it) 2). When the replication involves a subset of objects, e.g. critical-only. In these cases, we don't increase the highwater-mark, so it is probably not such a dire problem if we don't add the link. In the case of critical-only, we will do a subsequent full sync which will then add the links. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit 04ce638a1f7166b3fe75b52efd0a522248196fd4 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Wed Jun 14 10:51:59 2017 +1200 replmd: Split checking link attr target into new function We want to re-use this code to check that the linked attribute's target object exists *before* we try to commit the transaction. This will allow us to re-request the block with the GET_TGT flag set. This splits checking the target object exists into a separate function. Minor changes of note: - the 'parent' argument was passed to replmd_process_linked_attribute() as NULL, so I've just replaced where it was used in the refactored code with NULL. - I've tweaked the "Failed to find GUID" error message slightly to display the attribute ID rather than the attribute name (saves repeating lookups and/or passing extra arguments). - Tweaked the replmd_deletion_state() logic - it only made sense to call it in the code block where we actually found the target Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 commit d13e7b92f85e5623c5cf1309f13d59141dc7d888 Author: Tim Beale <timbe...@catalyst.net.nz> Date: Tue May 30 15:08:44 2017 +1200 werror: Add WERR_DS_DRA_RECYCLED_TARGET When the DRS client encounters a linked attribute with an unknown target object, it should return a RECYCLED_TARGET error, which should result in the client resending the GETNCChanges request with the GET_TGT flag set. This error code is currently documented by Microsoft under System Error Codes (8200-8999). I contacted them and they will also add it to the MS-ERREF doc in future. Signed-off-by: Tim Beale <timbe...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12972 ----------------------------------------------------------------------- Summary of changes: libcli/util/werror.h | 1 + librpc/idl/drsuapi.idl | 4 +- python/samba/drs_utils.py | 101 +++-- source3/librpc/crypto/gse_krb5.c | 180 ++++---- source3/passdb/machine_account_secrets.c | 15 +- source4/dsdb/repl/drepl_out_helpers.c | 105 ++++- source4/dsdb/repl/drepl_out_pull.c | 1 + source4/dsdb/repl/drepl_service.h | 2 + source4/dsdb/repl/replicated_objects.c | 11 +- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 558 +++++++++++++++++------- source4/dsdb/samdb/samdb.h | 3 +- source4/libnet/libnet_vampire.c | 5 + source4/selftest/tests.py | 10 + source4/torture/drs/python/drs_base.py | 141 ++++-- source4/torture/drs/python/getncchanges.py | 428 ++++++++++++++++++ testprogs/blackbox/dbcheck.sh | 8 + 16 files changed, 1233 insertions(+), 340 deletions(-) create mode 100644 source4/torture/drs/python/getncchanges.py Changeset truncated at 500 lines: diff --git a/libcli/util/werror.h b/libcli/util/werror.h index d3d3327..0370a06 100644 --- a/libcli/util/werror.h +++ b/libcli/util/werror.h @@ -100,6 +100,7 @@ typedef uint32_t WERROR; #define WERR_INVALID_PRIMARY_GROUP W_ERROR(0x0000051C) #define WERR_DS_DRA_SECRETS_DENIED W_ERROR(0x000021B6) +#define WERR_DS_DRA_RECYCLED_TARGET W_ERROR(0x000021BF) #define WERR_DNS_ERROR_KEYMASTER_REQUIRED W_ERROR(0x0000238D) #define WERR_DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE W_ERROR(0x0000238E) diff --git a/librpc/idl/drsuapi.idl b/librpc/idl/drsuapi.idl index 2eb1d65..51ef567 100644 --- a/librpc/idl/drsuapi.idl +++ b/librpc/idl/drsuapi.idl @@ -70,7 +70,9 @@ interface drsuapi } drsuapi_DrsUpdate; /*****************/ - /* Function 0x00 */ + /* Function 0x00 drsuapi_DsBind() */ + + /* MS-DRSR 5.39 DRS_EXTENSIONS_INT */ typedef [bitmap32bit] bitmap { DRSUAPI_SUPPORTED_EXTENSION_BASE = 0x00000001, DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION = 0x00000002, diff --git a/python/samba/drs_utils.py b/python/samba/drs_utils.py index b9ed059..bed8817 100644 --- a/python/samba/drs_utils.py +++ b/python/samba/drs_utils.py @@ -21,6 +21,8 @@ from samba.dcerpc import drsuapi, misc, drsblobs from samba.net import Net from samba.ndr import ndr_unpack from samba import dsdb +from samba import werror +from samba import WERRORError import samba, ldb @@ -198,18 +200,37 @@ class drs_Replicate(object): raise RuntimeError("Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id") self.replication_state = self.net.replicate_init(self.samdb, lp, self.drs, invocation_id) + def _should_retry_with_get_tgt(self, error_code, req): + + # If the error indicates we fail to resolve a target object for a + # linked attribute, then we should retry the request with GET_TGT + # (if we support it and haven't already tried that) + + # TODO fix up the below line when we next update werror_err_table.txt + # and pull in the new error-code + # return (error_code == werror.WERR_DS_DRA_RECYCLED_TARGET and + return (error_code == 0x21bf and + (req.more_flags & drsuapi.DRSUAPI_DRS_GET_TGT) == 0 and + self.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10) + def replicate(self, dn, source_dsa_invocation_id, destination_dsa_guid, schema=False, exop=drsuapi.DRSUAPI_EXOP_NONE, rodc=False, - replica_flags=None, full_sync=True, sync_forced=False): + replica_flags=None, full_sync=True, sync_forced=False, more_flags=0): '''replicate a single DN''' # setup for a GetNCChanges call - req8 = drsuapi.DsGetNCChangesRequest8() + if self.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10: + req = drsuapi.DsGetNCChangesRequest10() + req.more_flags = more_flags + req_level = 10 + else: + req_level = 8 + req = drsuapi.DsGetNCChangesRequest8() - req8.destination_dsa_guid = destination_dsa_guid - req8.source_dsa_invocation_id = source_dsa_invocation_id - req8.naming_context = drsuapi.DsReplicaObjectIdentifier() - req8.naming_context.dn = dn + req.destination_dsa_guid = destination_dsa_guid + req.source_dsa_invocation_id = source_dsa_invocation_id + req.naming_context = drsuapi.DsReplicaObjectIdentifier() + req.naming_context.dn = dn # Default to a full replication if we don't find an upToDatenessVector udv = None @@ -244,49 +265,46 @@ class drs_Replicate(object): udv.cursors = cursors_v1 udv.count = len(cursors_v1) - req8.highwatermark = hwm - req8.uptodateness_vector = udv + req.highwatermark = hwm + req.uptodateness_vector = udv if replica_flags is not None: - req8.replica_flags = replica_flags + req.replica_flags = replica_flags elif exop == drsuapi.DRSUAPI_EXOP_REPL_SECRET: - req8.replica_flags = 0 + req.replica_flags = 0 else: - req8.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC | - drsuapi.DRSUAPI_DRS_PER_SYNC | - drsuapi.DRSUAPI_DRS_GET_ANC | - drsuapi.DRSUAPI_DRS_NEVER_SYNCED | - drsuapi.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP) + req.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC | + drsuapi.DRSUAPI_DRS_PER_SYNC | + drsuapi.DRSUAPI_DRS_GET_ANC | + drsuapi.DRSUAPI_DRS_NEVER_SYNCED | + drsuapi.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP) if rodc: - req8.replica_flags |= ( - drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) + req.replica_flags |= ( + drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) else: - req8.replica_flags |= drsuapi.DRSUAPI_DRS_WRIT_REP + req.replica_flags |= drsuapi.DRSUAPI_DRS_WRIT_REP if sync_forced: - req8.replica_flags |= drsuapi.DRSUAPI_DRS_SYNC_FORCED + req.replica_flags |= drsuapi.DRSUAPI_DRS_SYNC_FORCED - req8.max_object_count = 402 - req8.max_ndr_size = 402116 - req8.extended_op = exop - req8.fsmo_info = 0 - req8.partial_attribute_set = None - req8.partial_attribute_set_ex = None - req8.mapping_ctr.num_mappings = 0 - req8.mapping_ctr.mappings = None + req.max_object_count = 402 + req.max_ndr_size = 402116 + req.extended_op = exop + req.fsmo_info = 0 + req.partial_attribute_set = None + req.partial_attribute_set_ex = None + req.mapping_ctr.num_mappings = 0 + req.mapping_ctr.mappings = None if not schema and rodc: - req8.partial_attribute_set = drs_get_rodc_partial_attribute_set(self.samdb) + req.partial_attribute_set = drs_get_rodc_partial_attribute_set(self.samdb) - if self.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8: - req_level = 8 - req = req8 - else: + if not self.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8: req_level = 5 req5 = drsuapi.DsGetNCChangesRequest5() for a in dir(req5): if a[0] != '_': - setattr(req5, a, getattr(req8, a)) + setattr(req5, a, getattr(req, a)) req = req5 num_objects = 0 @@ -295,8 +313,21 @@ class drs_Replicate(object): (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, req_level, req) if ctr.first_object is None and ctr.object_count != 0: raise RuntimeError("DsGetNCChanges: NULL first_object with object_count=%u" % (ctr.object_count)) - self.net.replicate_chunk(self.replication_state, level, ctr, - schema=schema, req_level=req_level, req=req) + + try: + self.net.replicate_chunk(self.replication_state, level, ctr, + schema=schema, req_level=req_level, req=req) + except WERRORError as e: + # Check if retrying with the GET_TGT flag set might resolve this error + if self._should_retry_with_get_tgt(e[0], req): + + print("Missing target object - retrying with DRS_GET_TGT") + req.more_flags |= drsuapi.DRSUAPI_DRS_GET_TGT + + # try sending the request again + continue + else: + raise e num_objects += ctr.object_count diff --git a/source3/librpc/crypto/gse_krb5.c b/source3/librpc/crypto/gse_krb5.c index 2c9fc03..cc8cb90 100644 --- a/source3/librpc/crypto/gse_krb5.c +++ b/source3/librpc/crypto/gse_krb5.c @@ -20,6 +20,7 @@ #include "includes.h" #include "smb_krb5.h" #include "secrets.h" +#include "librpc/gen_ndr/secrets.h" #include "gse_krb5.h" #include "lib/param/loadparm.h" #include "libads/kerberos_proto.h" @@ -85,45 +86,15 @@ out: return ret; } -static krb5_error_code get_host_principal(krb5_context krbctx, - krb5_principal *host_princ) -{ - krb5_error_code ret; - char *host_princ_s = NULL; - int err; - - err = asprintf(&host_princ_s, "%s$@%s", lp_netbios_name(), lp_realm()); - if (err == -1) { - return -1; - } - - if (!strlower_m(host_princ_s)) { - SAFE_FREE(host_princ_s); - return -1; - } - ret = smb_krb5_parse_name(krbctx, host_princ_s, host_princ); - if (ret) { - DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) " - "failed (%s)\n", - host_princ_s, error_message(ret))); - } - - SAFE_FREE(host_princ_s); - return ret; -} - static krb5_error_code fill_keytab_from_password(krb5_context krbctx, krb5_keytab keytab, krb5_principal princ, krb5_kvno vno, - krb5_data *password) + struct secrets_domain_info1_password *pw) { krb5_error_code ret; krb5_enctype *enctypes; - krb5_keytab_entry kt_entry; - unsigned int i; - krb5_principal salt_princ = NULL; - char *salt_princ_s = NULL; + uint16_t i; ret = smb_krb5_get_allowed_etypes(krbctx, &enctypes); if (ret) { @@ -132,61 +103,47 @@ static krb5_error_code fill_keytab_from_password(krb5_context krbctx, return ret; } - salt_princ_s = kerberos_secrets_fetch_salt_princ(); - if (salt_princ_s == NULL) { - ret = ENOMEM; - goto out; - } - ret = krb5_parse_name(krbctx, salt_princ_s, &salt_princ); - SAFE_FREE(salt_princ_s); - if (ret != 0) { - goto out; - } - - for (i = 0; enctypes[i]; i++) { + for (i = 0; i < pw->num_keys; i++) { + krb5_keytab_entry kt_entry; krb5_keyblock *key = NULL; - int rc; + unsigned int ei; + bool found_etype = false; - if (!(key = SMB_MALLOC_P(krb5_keyblock))) { - ret = ENOMEM; - goto out; + for (ei=0; enctypes[ei] != 0; ei++) { + if ((uint32_t)enctypes[ei] != pw->keys[i].keytype) { + continue; + } + + found_etype = true; + break; } - rc = create_kerberos_key_from_string(krbctx, - princ, - salt_princ, - password, - key, - enctypes[i], - false); - if (rc != 0) { - DEBUG(10, ("Failed to create key for enctype %d " - "(error: %s)\n", - enctypes[i], error_message(ret))); - SAFE_FREE(key); + if (!found_etype) { continue; } + ZERO_STRUCT(kt_entry); kt_entry.principal = princ; kt_entry.vno = vno; - *(KRB5_KT_KEY(&kt_entry)) = *key; + + key = KRB5_KT_KEY(&kt_entry); + KRB5_KEY_TYPE(key) = pw->keys[i].keytype; + KRB5_KEY_DATA(key) = pw->keys[i].value.data; + KRB5_KEY_LENGTH(key) = pw->keys[i].value.length; ret = krb5_kt_add_entry(krbctx, keytab, &kt_entry); if (ret) { DEBUG(1, (__location__ ": Failed to add entry to " "keytab for enctype %d (error: %s)\n", - enctypes[i], error_message(ret))); - krb5_free_keyblock(krbctx, key); + (unsigned)pw->keys[i].keytype, + error_message(ret))); goto out; } - - krb5_free_keyblock(krbctx, key); } ret = 0; out: - krb5_free_principal(krbctx, salt_princ); SAFE_FREE(enctypes); return ret; } @@ -197,27 +154,43 @@ out: static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx, krb5_keytab *keytab) { + TALLOC_CTX *frame = talloc_stackframe(); krb5_error_code ret; - char *pwd = NULL; - size_t pwd_len; + const char *domain = lp_workgroup(); + struct secrets_domain_info1 *info = NULL; + const char *realm = NULL; + const DATA_BLOB *ct = NULL; krb5_kt_cursor kt_cursor; krb5_keytab_entry kt_entry; - krb5_data password; krb5_principal princ = NULL; krb5_kvno kvno = 0; /* FIXME: fetch current vno from KDC ? */ - char *pwd_old = NULL; + NTSTATUS status; if (!secrets_init()) { DEBUG(1, (__location__ ": secrets_init failed\n")); + TALLOC_FREE(frame); return KRB5_CONFIG_CANTOPEN; } - pwd = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); - if (!pwd) { - DEBUG(2, (__location__ ": failed to fetch machine password\n")); + status = secrets_fetch_or_upgrade_domain_info(domain, + frame, + &info); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("secrets_fetch_or_upgrade_domain_info(%s) - %s\n", + domain, nt_errstr(status)); + TALLOC_FREE(frame); return KRB5_LIBOS_CANTREADPWD; } - pwd_len = strlen(pwd); + ct = &info->password->cleartext_blob; + + if (info->domain_info.dns_domain.string != NULL) { + realm = strupper_talloc(frame, + info->domain_info.dns_domain.string); + if (realm == NULL) { + TALLOC_FREE(frame); + return ENOMEM; + } + } ZERO_STRUCT(kt_entry); ZERO_STRUCT(kt_cursor); @@ -249,9 +222,9 @@ static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx, /* found private entry, * check if keytab is up to date */ - if ((pwd_len == KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry))) && + if ((ct->length == KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry))) && (memcmp(KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)), - pwd, pwd_len) == 0)) { + ct->data, ct->length) == 0)) { /* keytab is already up to date, return */ smb_krb5_kt_free_entry(krbctx, &kt_entry); goto out; @@ -277,32 +250,51 @@ static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx, /* keytab is not up to date, fill it up */ - ret = get_host_principal(krbctx, &princ); + ret = smb_krb5_make_principal(krbctx, &princ, realm, + info->account_name, NULL); if (ret) { DEBUG(1, (__location__ ": Failed to get host principal!\n")); goto out; } - password.data = pwd; - password.length = pwd_len; ret = fill_keytab_from_password(krbctx, *keytab, - princ, kvno, &password); + princ, kvno, + info->password); if (ret) { - DEBUG(1, (__location__ ": Failed to fill memory keytab!\n")); + DBG_WARNING("fill_keytab_from_password() failed for " + "info->password.\n."); goto out; } - pwd_old = secrets_fetch_prev_machine_password(lp_workgroup()); - if (!pwd_old) { - DEBUG(10, (__location__ ": no prev machine password\n")); - } else { - password.data = pwd_old; - password.length = strlen(pwd_old); + if (info->old_password != NULL) { + ret = fill_keytab_from_password(krbctx, *keytab, + princ, kvno - 1, + info->old_password); + if (ret) { + DBG_WARNING("fill_keytab_from_password() failed for " + "info->old_password.\n."); + goto out; + } + } + + if (info->older_password != NULL) { ret = fill_keytab_from_password(krbctx, *keytab, - princ, kvno -1, &password); + princ, kvno - 2, + info->older_password); if (ret) { - DEBUG(1, (__location__ - ": Failed to fill memory keytab!\n")); + DBG_WARNING("fill_keytab_from_password() failed for " + "info->older_password.\n."); + goto out; + } + } + + if (info->next_change != NULL) { + ret = fill_keytab_from_password(krbctx, *keytab, + princ, kvno - 3, + info->next_change->password); + if (ret) { + DBG_WARNING("fill_keytab_from_password() failed for " + "info->next_change->password.\n."); goto out; } } @@ -314,8 +306,8 @@ static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx, kt_entry.vno = 0; KRB5_KEY_TYPE(KRB5_KT_KEY(&kt_entry)) = CLEARTEXT_PRIV_ENCTYPE; - KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry)) = pwd_len; - KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)) = (uint8_t *)pwd; + KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry)) = ct->length; + KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)) = ct->data; ret = krb5_kt_add_entry(krbctx, *keytab, &kt_entry); if (ret) { @@ -328,9 +320,6 @@ static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx, ret = 0; out: - SAFE_FREE(pwd); - SAFE_FREE(pwd_old); - if (!all_zero((uint8_t *)&kt_cursor, sizeof(kt_cursor)) && *keytab) { krb5_kt_end_seq_get(krbctx, *keytab, &kt_cursor); } @@ -339,6 +328,7 @@ out: krb5_free_principal(krbctx, princ); } + TALLOC_FREE(frame); return ret; } diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c index 3d1cb5b..5a0f7a8 100644 --- a/source3/passdb/machine_account_secrets.c +++ b/source3/passdb/machine_account_secrets.c @@ -832,7 +832,8 @@ static NTSTATUS secrets_store_domain_info1_by_key(const char *key, return NT_STATUS_OK; } -static NTSTATUS secrets_store_domain_info(const struct secrets_domain_info1 *info) +static NTSTATUS secrets_store_domain_info(const struct secrets_domain_info1 *info, + bool upgrade) { TALLOC_CTX *frame = talloc_stackframe(); const char *domain = info->domain_info.name.string; @@ -853,7 +854,7 @@ static NTSTATUS secrets_store_domain_info(const struct secrets_domain_info1 *inf switch (info->secure_channel_type) { case SEC_CHAN_WKSTA: -- Samba Shared Repository