[SCM] Samba Shared Repository - branch master updated
Jo Sutton
jsutton at samba.org
Sun Apr 21 23:18:02 UTC 2024
The branch, master has been updated
via 20ce68f1594 tests/krb5: Test retrieving a denied gMSA password over an unsealed connection
via 7ba61811592 s4:ldap_server: Update gMSA keys when DSDB_CONTROL_GMSA_UPDATE_OID control is specified
via 24f109c59ff s4:dsdb:tests: Make use of ‘ldb’ parameter
via 02d7ab13ee2 lib:crypto: Add more unit tests for GKDI functions
via b2d777a1ed2 s4:dsdb: Make use of DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS search flag
via 118f3ba78fd s4:dsdb: Implement DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS search flag
via 9149d1d338f s4:kdc: Correctly extract older NT hash
via c6fec5156fe tests/krb5: Note that lockout tests use password checks
via ed371ff0fa1 tests/krb5: Fix malapropism
via a916928acaf s4:kdc: Remove unnecessary cast
via 8dca32eba2c pyglue: Remove unnecessary declaration
via 460b1935b96 s4:kdc: Fix grammar
via faba757175f auth:credentials: Remove unnecessary declaration
via b6b8f9539b8 auth:credentials: Fix code spelling
via 56dd910b837 python: Reformat code
via e25c6a21208 s4-gmsa: Do not attempt password set on remote LDAP connections
via 977f5753fc8 s4:dsdb: Add dsdb_update_gmsa_keys()
via 245dc1f0f2b s4:dsdb: Move the responsibility for determining whether an account is a gMSA out of gmsa_recalculate_managed_pwd()
via 2f2d3b7cf28 s4:dsdb: Indicate to the LDAP server physical passwords that need to be refreshed
via 99071bbcf4b s4:dsdb: Store found managed password ID as part of gMSA update structure
via 8bcefaaa5c4 s4:dsdb: Store account DN as part of gMSA update structure
via 6613aeca93a s4:dsdb: Only reuse the current password ID as the previous password ID when appropriate
via dcc5724ed75 s4:dsdb: Add a note that administrators should not set the clock too far in the future
via a397029813f s4:dsdb: No longer pass DSDB_SEARCH_ONE_ONLY flag to dsdb_search_dn()
via cdc63fa68d8 s4:dsdb: Explicitly return success error code
via 1b765edbc95 tests/krb5: Add tests that gMSA keys are updated in the database when appropriate
via 47c519af8e9 tests/krb5: Import MAX_CLOCK_SKEW more directly
via 21d46f3ece3 tests/krb5: Extract method to unpack supplementalCredentials blob
via 502070cd9a5 tests/krb5: Skip loop iteration if attribute has no values
via 5eea17a71bd ldb: Check result of py_ldb_msg_keys()
from 0159c48e897 ctdb-scripts: Do not de-duplicate the interfaces list
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 20ce68f15940b3e8d4d53c10a71729b16cfb3908
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Fri Apr 19 14:16:03 2024 +1200
tests/krb5: Test retrieving a denied gMSA password over an unsealed connection
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Autobuild-User(master): Jo Sutton <jsutton at samba.org>
Autobuild-Date(master): Sun Apr 21 23:17:53 UTC 2024 on atb-devel-224
commit 7ba6181159215e99d8a0f2f3974ee0d46d146f35
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Mon Apr 15 15:13:45 2024 +1200
s4:ldap_server: Update gMSA keys when DSDB_CONTROL_GMSA_UPDATE_OID control is specified
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 24f109c59ff22a8a1f22ba4cdc118795e7b4d512
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Mon Apr 15 13:21:10 2024 +1200
s4:dsdb:tests: Make use of ‘ldb’ parameter
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 02d7ab13ee271448efe5715bdaaf5e6907d32e08
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Mon Apr 15 12:19:12 2024 +1200
lib:crypto: Add more unit tests for GKDI functions
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit b2d777a1ed23dfb968057411f43e92334f55705b
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Mon Apr 15 11:42:50 2024 +1200
s4:dsdb: Make use of DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS search flag
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 118f3ba78fd1135fb7b254d1a2bb152eb5759923
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 9 16:24:43 2024 +1200
s4:dsdb: Implement DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS search flag
View with ‘git show -b’.
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 9149d1d338f109f2220f6408418a6db6f3c43a11
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Thu Apr 11 17:17:54 2024 +1200
s4:kdc: Correctly extract older NT hash
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit c6fec5156fe20da6a424d7239ee234aed0aa96c0
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 16 16:01:44 2024 +1200
tests/krb5: Note that lockout tests use password checks
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit ed371ff0fa1bf3f67ad72ee206b67a693266f4b2
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Thu Apr 11 16:31:51 2024 +1200
tests/krb5: Fix malapropism
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit a916928acaf91a2d238b7940b3f882db7d548564
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Wed Apr 10 12:01:09 2024 +1200
s4:kdc: Remove unnecessary cast
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 8dca32eba2cc3b2947df029839d6962df971acc4
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Wed Apr 10 11:53:43 2024 +1200
pyglue: Remove unnecessary declaration
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 460b1935b966f920cb117da6ca5a6ba9c48e7725
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 9 15:07:23 2024 +1200
s4:kdc: Fix grammar
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit faba757175fdd56c6a489f76becde7e5f71694e3
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 9 14:31:11 2024 +1200
auth:credentials: Remove unnecessary declaration
This declaration is a hold‐over from the Python 2 module initialization
pattern.
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit b6b8f9539b8fd91a1a9fdec6f181479759f04dd3
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Mon Apr 8 17:29:40 2024 +1200
auth:credentials: Fix code spelling
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 56dd910b8372bee82e9cbe26b730dd4c938c9803
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Mar 5 12:33:33 2024 +1300
python: Reformat code
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit e25c6a212085f8c6ee7e99ed5cff68fde957e1db
Author: Andrew Bartlett <abartlet at samba.org>
Date: Tue Mar 5 16:18:34 2024 +1300
s4-gmsa: Do not attempt password set on remote LDAP connections
Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Jo Sutton <josutton at catalyst.net.nz>
commit 977f5753fc866854e652918d5295718b347e7c3d
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Feb 13 16:09:57 2024 +1300
s4:dsdb: Add dsdb_update_gmsa_keys()
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 245dc1f0f2b10912dcba5502489acb0db13b830a
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Wed Apr 17 13:27:19 2024 +1200
s4:dsdb: Move the responsibility for determining whether an account is a gMSA out of gmsa_recalculate_managed_pwd()
and into its callers.
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 2f2d3b7cf284cc9f263060a36c3e4c58ca4a12bc
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Thu Apr 11 20:15:07 2024 +1200
s4:dsdb: Indicate to the LDAP server physical passwords that need to be refreshed
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 99071bbcf4b8fa3718b4c1bc3f17bccb21f4f74c
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 16 14:03:36 2024 +1200
s4:dsdb: Store found managed password ID as part of gMSA update structure
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 8bcefaaa5c4117ae4afc829f08ae239af7ebb00e
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 16 14:03:05 2024 +1200
s4:dsdb: Store account DN as part of gMSA update structure
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 6613aeca93aba3e8edf96be4ceba0f349001b1dd
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 16 14:00:44 2024 +1200
s4:dsdb: Only reuse the current password ID as the previous password ID when appropriate
This should already be the case given the current logic, but let’s make
it explicit.
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit dcc5724ed757ced4c84900ae4589425c5c384b1d
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 16 13:58:15 2024 +1200
s4:dsdb: Add a note that administrators should not set the clock too far in the future
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit a397029813fe32c393c8dabbce8e210a0355811c
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 16 13:49:04 2024 +1200
s4:dsdb: No longer pass DSDB_SEARCH_ONE_ONLY flag to dsdb_search_dn()
As dsdb_search_dn() ignores this flag, passing it in doesn’t achieve
anything.
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit cdc63fa68d81deb0ea1398b32adea5d4be0f6279
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Tue Apr 16 16:28:55 2024 +1200
s4:dsdb: Explicitly return success error code
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 1b765edbc95b5cf9fead82c4e40af747123c6855
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Thu Apr 18 10:13:04 2024 +1200
tests/krb5: Add tests that gMSA keys are updated in the database when appropriate
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 47c519af8e9cf57c3c1abd76c70eabbb8c7ba87c
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Fri Apr 19 12:59:52 2024 +1200
tests/krb5: Import MAX_CLOCK_SKEW more directly
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 21d46f3ece3a48873b9a279b276868417f124fd1
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Fri Apr 19 12:58:36 2024 +1200
tests/krb5: Extract method to unpack supplementalCredentials blob
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 502070cd9a5eb7eef0f98d73b967f1d63b9403f0
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Fri Apr 19 12:57:50 2024 +1200
tests/krb5: Skip loop iteration if attribute has no values
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
commit 5eea17a71bd69f39226a32725a0b09b60dd5308c
Author: Jo Sutton <josutton at catalyst.net.nz>
Date: Thu Apr 18 12:47:28 2024 +1200
ldb: Check result of py_ldb_msg_keys()
Passing NULL into PyObject_GetIter() can cause a segmentation fault.
Signed-off-by: Jo Sutton <josutton at catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
-----------------------------------------------------------------------
Summary of changes:
auth/credentials/pycredentials.c | 2 -
auth/credentials/tests/bind.py | 2 +-
lib/crypto/test_gkdi.c | 183 +++++++++++
lib/ldb/pyldb.c | 3 +
python/pyglue.c | 1 -
python/samba/nt_time.py | 18 +-
python/samba/tests/krb5/gmsa_tests.py | 202 +++++++++++-
python/samba/tests/krb5/kdc_base_test.py | 52 +--
python/samba/tests/krb5/lockout_tests.py | 5 +-
selftest/knownfail_mit_kdc_1_20 | 1 +
source3/passdb/pdb_samba_dsdb.c | 7 +-
source4/auth/sam.c | 11 +-
source4/dsdb/common/util.c | 149 ++++++---
source4/dsdb/gmsa/gkdi.c | 2 +-
source4/dsdb/gmsa/util.c | 378 +++++++++++++++++++++-
source4/dsdb/gmsa/util.h | 25 ++
source4/dsdb/samdb/ldb_modules/managed_pwd.c | 23 ++
source4/dsdb/samdb/ldb_modules/samba_dsdb.c | 1 +
source4/dsdb/tests/python/unicodepwd_encrypted.py | 4 +-
source4/kdc/db-glue.c | 25 +-
source4/kdc/kdc-heimdal.c | 3 +-
source4/kdc/wscript_build | 2 +-
source4/ldap_server/ldap_backend.c | 44 +++
source4/ntp_signd/ntp_signd.c | 28 +-
source4/ntp_signd/wscript_build | 3 +-
source4/rpc_server/netlogon/dcerpc_netlogon.c | 90 ++++--
source4/rpc_server/wscript_build | 1 +
27 files changed, 1087 insertions(+), 178 deletions(-)
Changeset truncated at 500 lines:
diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c
index 5cdbe7796e6..0bcb894f920 100644
--- a/auth/credentials/pycredentials.c
+++ b/auth/credentials/pycredentials.c
@@ -35,8 +35,6 @@
#include "auth/kerberos/kerberos.h"
#include "libcli/smb/smb_constants.h"
-void initcredentials(void);
-
static PyObject *py_creds_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
return pytalloc_steal(type, cli_credentials_init(NULL));
diff --git a/auth/credentials/tests/bind.py b/auth/credentials/tests/bind.py
index ce81b736e86..97370666b3b 100755
--- a/auth/credentials/tests/bind.py
+++ b/auth/credentials/tests/bind.py
@@ -140,7 +140,7 @@ unicodePwd:: """ + base64.b64encode(u"\"P at ssw0rd\"".encode('utf-16-le')).decode(
res = ldb_virtual.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
def test_computer_account_bind(self):
- # create a computer acocount for the test
+ # create a computer account for the test
delete_force(self.ldb, self.computer_dn)
self.ldb.add_ldif("""
dn: """ + self.computer_dn + """
diff --git a/lib/crypto/test_gkdi.c b/lib/crypto/test_gkdi.c
index e6d3b28ae58..083d71eefd3 100644
--- a/lib/crypto/test_gkdi.c
+++ b/lib/crypto/test_gkdi.c
@@ -136,10 +136,193 @@ static void test_password_based_on_key_id(void **state)
talloc_free(mem_ctx);
}
+static void assert_gkid_equal(const struct Gkid g1, const struct Gkid g2)
+{
+ assert_int_equal(g1.l0_idx, g2.l0_idx);
+ assert_int_equal(g1.l1_idx, g2.l1_idx);
+ assert_int_equal(g1.l2_idx, g2.l2_idx);
+}
+
+static void test_gkdi_rollover_interval(void **state)
+{
+ NTTIME interval;
+ bool ok;
+
+ ok = gkdi_rollover_interval(0, &interval);
+ assert_true(ok);
+ assert_int_equal(0, interval);
+
+ ok = gkdi_rollover_interval(1, &interval);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(720000000000), interval);
+
+ ok = gkdi_rollover_interval(2, &interval);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(1440000000000), interval);
+
+ ok = gkdi_rollover_interval(3, &interval);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(2520000000000), interval);
+
+ ok = gkdi_rollover_interval(4, &interval);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(3240000000000), interval);
+
+ ok = gkdi_rollover_interval(5, &interval);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(4320000000000), interval);
+
+ ok = gkdi_rollover_interval(-1, &interval);
+ assert_false(ok);
+
+ ok = gkdi_rollover_interval(-2, &interval);
+ assert_false(ok);
+
+ ok = gkdi_rollover_interval(10675199, &interval);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(9223371720000000000), interval);
+
+ ok = gkdi_rollover_interval(-10675198, &interval);
+ assert_false(ok);
+
+ ok = gkdi_rollover_interval(10675200, &interval);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(9223372800000000000), interval);
+
+ ok = gkdi_rollover_interval(-10675199, &interval);
+ assert_false(ok);
+
+ ok = gkdi_rollover_interval(21350398, &interval);
+ /*
+ * If we accepted this high of an interval, the result would be
+ * 18446743800000000000.
+ */
+ assert_false(ok);
+
+ ok = gkdi_rollover_interval(-21350397, &interval);
+ assert_false(ok);
+
+ ok = gkdi_rollover_interval(21350399, &interval);
+ assert_false(ok); /* too large to be represented */
+
+ ok = gkdi_rollover_interval(-21350398, &interval);
+ assert_false(ok); /* too small to be represented */
+}
+
+static void assert_get_interval_id(const NTTIME time,
+ const struct Gkid expected_gkid)
+{
+ {
+ const bool valid = gkid_is_valid(expected_gkid);
+ assert_true(valid);
+ }
+
+ {
+ const struct Gkid interval_id = gkdi_get_interval_id(time);
+ assert_gkid_equal(expected_gkid, interval_id);
+ }
+}
+
+static void test_get_interval_id(void **state)
+{
+ assert_get_interval_id(0, Gkid(0, 0, 0));
+
+ assert_get_interval_id(gkdi_key_cycle_duration - 1, Gkid(0, 0, 0));
+
+ assert_get_interval_id(gkdi_key_cycle_duration, Gkid(0, 0, 1));
+
+ assert_get_interval_id(27 * gkdi_key_cycle_duration, Gkid(0, 0, 27));
+
+ assert_get_interval_id((gkdi_l2_key_iteration - 1) *
+ gkdi_key_cycle_duration,
+ Gkid(0, 0, gkdi_l2_key_iteration - 1));
+
+ assert_get_interval_id(gkdi_l2_key_iteration * gkdi_key_cycle_duration,
+ Gkid(0, 1, 0));
+
+ assert_get_interval_id(17 * gkdi_l2_key_iteration *
+ gkdi_key_cycle_duration,
+ Gkid(0, 17, 0));
+
+ assert_get_interval_id(((gkdi_l1_key_iteration - 1) *
+ gkdi_l2_key_iteration +
+ 3) * gkdi_key_cycle_duration,
+ Gkid(0, gkdi_l1_key_iteration - 1, 3));
+
+ assert_get_interval_id(gkdi_l1_key_iteration * gkdi_l2_key_iteration *
+ gkdi_key_cycle_duration,
+ Gkid(1, 0, 0));
+
+ assert_get_interval_id(((1234 * gkdi_l1_key_iteration + 8) *
+ gkdi_l2_key_iteration +
+ 13) * gkdi_key_cycle_duration,
+ Gkid(1234, 8, 13));
+
+ assert_get_interval_id(INT64_MAX, Gkid(25019, 31, 29));
+
+ assert_get_interval_id(UINT64_MAX, Gkid(50039, 31, 27));
+}
+
+static void test_get_key_start_time(void **state)
+{
+ NTTIME start_time = 0;
+ bool ok;
+
+ /* Try passing an invalid GKID. */
+ ok = gkdi_get_key_start_time(invalid_gkid, &start_time);
+ assert_false(ok);
+
+ /* Try passing an L1 GKID rather than an L2 GKID. */
+ ok = gkdi_get_key_start_time(Gkid(0, 0, -1), &start_time);
+ assert_false(ok);
+
+ /* Test some L2 GKIDs. */
+
+ ok = gkdi_get_key_start_time(Gkid(0, 0, 0), &start_time);
+ assert_true(ok);
+ assert_int_equal(0, start_time);
+
+ ok = gkdi_get_key_start_time(Gkid(0, 0, 1), &start_time);
+ assert_true(ok);
+ assert_int_equal(gkdi_key_cycle_duration, start_time);
+
+ ok = gkdi_get_key_start_time(Gkid(123, 18, 2), &start_time);
+ assert_true(ok);
+ assert_int_equal(126530 * gkdi_key_cycle_duration, start_time);
+
+ ok = gkdi_get_key_start_time(Gkid(25019, 31, 29), &start_time);
+ assert_true(ok);
+ assert_int_equal(25620477 * gkdi_key_cycle_duration, start_time);
+
+ ok = gkdi_get_key_start_time(Gkid(25019, 31, 30), &start_time);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(25620478) * gkdi_key_cycle_duration,
+ start_time);
+
+ ok = gkdi_get_key_start_time(Gkid(50039, 31, 27), &start_time);
+ assert_true(ok);
+ assert_int_equal(UINT64_C(51240955) * gkdi_key_cycle_duration,
+ start_time);
+
+ /*
+ * Test GKIDs so high that their start times can’t be represented in
+ * NTTIME.
+ */
+
+ ok = gkdi_get_key_start_time(Gkid(50039, 31, 28), &start_time);
+ assert_false(ok);
+
+ ok = gkdi_get_key_start_time(Gkid(INT32_MAX, 31, 31), &start_time);
+ assert_false(ok);
+}
+
int main(int argc, char *argv[])
{
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_password_based_on_key_id),
+ cmocka_unit_test(test_gkdi_rollover_interval),
+ cmocka_unit_test(test_get_interval_id),
+ cmocka_unit_test(test_get_key_start_time),
};
if (argc == 2) {
diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index f416bfe6d5d..d54a952ac01 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -4143,6 +4143,9 @@ static PyObject *py_ldb_msg_iter(PyObject *self)
PyObject *list, *iter;
list = py_ldb_msg_keys(self, NULL);
+ if (list == NULL) {
+ return NULL;
+ }
iter = PyObject_GetIter(list);
Py_DECREF(list);
return iter;
diff --git a/python/pyglue.c b/python/pyglue.c
index c24d1b033a4..27cd41d5b9c 100644
--- a/python/pyglue.c
+++ b/python/pyglue.c
@@ -29,7 +29,6 @@
#include "lib/cmdline/cmdline.h"
#include "lib/crypto/gkdi.h"
-void init_glue(void);
static PyObject *PyExc_NTSTATUSError;
static PyObject *PyExc_WERRORError;
static PyObject *PyExc_HRESULTError;
diff --git a/python/samba/nt_time.py b/python/samba/nt_time.py
index 098748f4f3c..714f9e97ef4 100644
--- a/python/samba/nt_time.py
+++ b/python/samba/nt_time.py
@@ -85,19 +85,21 @@ def nt_time_from_string(s: str) -> NtTime:
UTC).
"""
try:
- if s == 'now':
+ if s == "now":
dt = datetime.datetime.now(datetime.timezone.utc)
- elif re.match(r'^\d{14}\.0Z$', s):
+ elif re.match(r"^\d{14}\.0Z$", s):
# "20230127223641.0Z"
- dt = datetime.datetime.strptime(s, '%Y%m%d%H%M%S.0Z')
+ dt = datetime.datetime.strptime(s, "%Y%m%d%H%M%S.0Z")
else:
dt = datetime.datetime.fromisoformat(s)
except ValueError:
- raise ValueError("Expected a date in either "
- "ISO8601 'YYYY-MM-DD HH:MM:SS' format, "
- "LDAP timestamp 'YYYYmmddHHMMSS.0Z', "
- "or the literal string 'now'. "
- f" Got '{s}'.")
+ raise ValueError(
+ "Expected a date in either "
+ "ISO8601 'YYYY-MM-DD HH:MM:SS' format, "
+ "LDAP timestamp 'YYYYmmddHHMMSS.0Z', "
+ "or the literal string 'now'. "
+ f" Got '{s}'."
+ )
if dt.tzinfo is None:
# This is a cursed timestamp with no timezone info. We have to
diff --git a/python/samba/tests/krb5/gmsa_tests.py b/python/samba/tests/krb5/gmsa_tests.py
index 1d3787af478..80529daf7d0 100755
--- a/python/samba/tests/krb5/gmsa_tests.py
+++ b/python/samba/tests/krb5/gmsa_tests.py
@@ -30,7 +30,7 @@ from itertools import chain
import ldb
-from samba import auth, dsdb, gensec
+from samba import auth, dsdb, gensec, werror
from samba.dcerpc import gkdi, gmsa, misc, netlogon, security
from samba.ndr import ndr_pack, ndr_unpack
from samba.nt_time import (
@@ -46,11 +46,12 @@ from samba.gkdi import (
Gkid,
GroupKey,
KEY_CYCLE_DURATION,
+ MAX_CLOCK_SKEW,
)
from samba.tests import connect_samdb
from samba.tests.krb5 import kcrypto
-from samba.tests.gkdi import GkdiBaseTest, MAX_CLOCK_SKEW
+from samba.tests.gkdi import GkdiBaseTest, ROOT_KEY_START_TIME
from samba.tests.krb5.kdc_base_test import KDCBaseTest
from samba.tests.krb5.raw_testcase import KerberosCredentials
from samba.tests.krb5.rfc4120_constants import (
@@ -632,9 +633,17 @@ class GmsaTests(GkdiBaseTest, KDCBaseTest):
)
def check_managed_password_access(
- self, creds: Credentials, *, expect_access
+ self,
+ creds: Credentials,
+ *,
+ samdb: Optional[SamDB] = None,
+ expect_access: bool = False,
+ expected_werror: int = werror.WERR_SUCCESS,
) -> None:
- samdb = self.get_samdb()
+ if samdb is None:
+ samdb = self.get_samdb()
+ if expected_werror:
+ self.assertFalse(expect_access)
managed_service_accounts_dn = self.get_managed_service_accounts_dn()
username = creds.get_username()
@@ -648,12 +657,24 @@ class GmsaTests(GkdiBaseTest, KDCBaseTest):
for dn, scope in searches:
# Perform a search and see whether we’re allowed to view the managed password.
- res = samdb.search(
- dn,
- scope=scope,
- expression=f"sAMAccountName={username}",
- attrs=["msDS-ManagedPassword"],
- )
+ try:
+ res = samdb.search(
+ dn,
+ scope=scope,
+ expression=f"sAMAccountName={username}",
+ attrs=["msDS-ManagedPassword"],
+ )
+ except ldb.LdbError as err:
+ self.assertTrue(expected_werror, "got an unexpected error")
+
+ num, estr = err.args
+ if num != ldb.ERR_OPERATIONS_ERROR:
+ raise
+
+ self.assertIn(f"{expected_werror:08X}", estr)
+ return
+
+ self.assertFalse(expected_werror, "expected to get an error")
self.assertEqual(1, len(res), "should always find the gMSA")
managed_password = res[0].get("msDS-ManagedPassword", idx=0)
@@ -677,6 +698,36 @@ class GmsaTests(GkdiBaseTest, KDCBaseTest):
self.gmsa_account(msa_membership=deny_world_sddl), expect_access=False
)
+ def test_retrieving_denied_password_over_unsealed_connection(self):
+ # Requires --use-kerberos=required, or it automatically upgrades to an
+ # encrypted connection.
+
+ # Remove FEATURE_SEAL which gets added by insta_creds.
+ creds = self.insta_creds(template=self.get_admin_creds())
+ creds.set_gensec_features(creds.get_gensec_features() & ~gensec.FEATURE_SEAL)
+
+ lp = self.get_lp()
+
+ sasl_wrap = lp.get("client ldap sasl wrapping")
+ self.addCleanup(lp.set, "client ldap sasl wrapping", sasl_wrap)
+ lp.set("client ldap sasl wrapping", "sign")
+
+ # Create a second ldb connection without seal.
+ samdb = SamDB(
+ f"ldap://{self.dc_host}",
+ credentials=creds,
+ session_info=auth.system_session(lp),
+ lp=lp,
+ )
+
+ # Deny anyone from being able to view the password.
+ deny_world_sddl = "O:SYD:(D;;RP;;;WD)"
+ self.check_managed_password_access(
+ self.gmsa_account(msa_membership=deny_world_sddl),
+ samdb=samdb,
+ expected_werror=werror.WERR_DS_CONFIDENTIALITY_REQUIRED,
+ )
+
def future_gkid(self) -> Gkid:
"""Return (6333, 26, 5)—an arbitrary GKID far enough in the future that
it’s situated beyond any reasonable rollover period. But not so far in
@@ -839,6 +890,137 @@ class GmsaTests(GkdiBaseTest, KDCBaseTest):
)
self.check_managed_pwd(samdb, creds, expected_managed_pwd=expected)
+ def test_retrieving_managed_password_triggers_keys_update(self):
+ # Create a root key with a start time early enough to be usable at the
+ # time the gMSA is purported to be created.
+ samdb = self.get_samdb()
+ domain_dn = self.get_server_dn(samdb)
+ self.create_root_key(samdb, domain_dn, use_start_time=ROOT_KEY_START_TIME)
+
+ password_interval = 16
+
+ local_samdb = self.get_local_samdb()
+ series = GmsaSeries(Gkid(100, 0, 0), gkdi_rollover_interval(password_interval))
+ self.set_db_time(local_samdb, series.start_of_interval(0))
+
+ creds = self.gmsa_account(samdb=local_samdb, interval=password_interval)
+ dn = creds.get_dn()
+
+ current_nt_time = self.current_nt_time(local_samdb)
+ self.set_db_time(local_samdb, current_nt_time)
+
+ # Search the local database for the account’s keys.
+ res = local_samdb.search(
+ dn, scope=ldb.SCOPE_BASE, attrs=["unicodePwd", "supplementalCredentials"]
+ )
+ self.assertEqual(1, len(res))
+
+ previous_nt_hash = res[0].get("unicodePwd", idx=0)
+ previous_supplemental_creds = self.unpack_supplemental_credentials(
+ res[0].get("supplementalCredentials", idx=0)
+ )
+
+ # Search for the managed password over LDAP, triggering an update of the
+ # keys in the database.
+ res = samdb.search(dn, scope=ldb.SCOPE_BASE, attrs=["msDS-ManagedPassword"])
+ self.assertEqual(1, len(res))
+
+ # Verify that the password is present in the result.
+ managed_password = res[0].get("msDS-ManagedPassword", idx=0)
+ self.assertIsNotNone(managed_password, "should be allowed to view the password")
+
+ # Search the local database again for the account’s keys, which should
+ # have been updated.
+ res = local_samdb.search(
+ dn, scope=ldb.SCOPE_BASE, attrs=["unicodePwd", "supplementalCredentials"]
+ )
+ self.assertEqual(1, len(res))
+
+ nt_hash = res[0].get("unicodePwd", idx=0)
+ supplemental_creds = self.unpack_supplemental_credentials(
+ res[0].get("supplementalCredentials", idx=0)
+ )
+
+ self.assertNotEqual(
+ previous_nt_hash, nt_hash, "NT hash has not been updated (yet)"
+ )
+ self.assertNotEqual(
+ previous_supplemental_creds,
+ supplemental_creds,
+ "supplementalCredentials has not been updated (yet)",
+ )
+
+ def test_authentication_triggers_keys_update(self):
+ # Create a root key with a start time early enough to be usable at the
+ # time the gMSA is purported to be created. But don’t create it on a
+ # local samdb with a specifically set time, because (if the key isn’t
+ # deleted later) we could end up with multiple keys with identical
+ # creation and start times, and tests failing when the test and the
+ # server don’t agree on which root key to use at a specific time.
+ samdb = self.get_samdb()
+ domain_dn = self.get_server_dn(samdb)
+ self.create_root_key(samdb, domain_dn, use_start_time=ROOT_KEY_START_TIME)
+
+ password_interval = 16
+
+ local_samdb = self.get_local_samdb()
+ series = GmsaSeries(Gkid(100, 0, 0), gkdi_rollover_interval(password_interval))
+ self.set_db_time(local_samdb, series.start_of_interval(0))
+
+ creds = self.gmsa_account(samdb=local_samdb, interval=password_interval)
+ dn = creds.get_dn()
+
+ current_nt_time = self.current_nt_time(local_samdb)
+ self.set_db_time(local_samdb, current_nt_time)
+
+ # Search the local database for the account’s keys.
+ res = local_samdb.search(
+ dn, scope=ldb.SCOPE_BASE, attrs=["unicodePwd", "supplementalCredentials"]
+ )
+ self.assertEqual(1, len(res))
+
+ previous_nt_hash = res[0].get("unicodePwd", idx=0)
+ previous_supplemental_creds = self.unpack_supplemental_credentials(
+ res[0].get("supplementalCredentials", idx=0)
+ )
+
+ # Calculate the password with which to authenticate.
+ managed_pwd = self.expected_current_gmsa_password_blob(
+ samdb, creds, future_key_is_acceptable=False
--
Samba Shared Repository
More information about the samba-cvs
mailing list