The branch, master has been updated via 589a9ea6767 s4:kdc: Add comment about possible interaction between the krbtgt account and Group Managed Service Accounts via d8302e95326 s4:kdc: Merge current and previous gMSA keys during period when both are valid via a0d639bfb82 tests/krb5: Test that previous keys are counted as current keys following a gMSA key rollover via 5ea07824655 s4:libnet: Allow simulating AS‐REQ flags combination for keytab export via 71899ceb40d s4:libnet: Update export_keytab() docstring via 048de3da01f s4:libnet: Pass SDB_F_ADMIN_DATA flag through to samba_kdc_message2entry() via aa8aeeb655a python:tests: Extract keytab_as_set() function to be usable by other tests via 5682df15a09 python:tests: Manually raise AssertionError via 95e80bf1e05 python:tests: Rename ‘keytab_as_set’ variable to be distinct from keytab_as_set() method via 4597d314029 third_party/heimdal: Import lorikeet-heimdal-202405220400 (commit 8276d6311146b8ab5d57d092bc5d5fa28282a900) via 4de25061120 WHATSNEW: Add 'dns hostname' via f64e728444b auth:ntlmssp: Use lpcfg_dns_hostname() via 78c2427d9b9 auth:ntlmssp: Remove trailing spaces via 26fd78040e5 s4:rpc_server: Use lpcfg_dnsdomain() in dnsdb.c via ad9198bb864 s4:rpc_server: Use lpcfg_dns_hostname() in dnsdb.c via 6bd56a2c19d s4:rpc_server: Use lpcfg_dns_hostname() in dnsutils.c via cb9ff7b4c5b s4:rpc_server: Use lpcfg_dns_hostname() in dns_server.c via 8ae565a14b5 s4:dns_server: Use lpcfg_dns_hostname() in dlz_bind9.c via f353ce5f965 s4:dfs_server: Use lpcfg_dns_hostname() in dfs_server_ad.c via f3f8aa49641 s3:rpc_server: Use lpcfg_dns_hostname() in srv_witness_nt.c via c00571a8b25 python:tests: Ignore case for group_name comparison via c2d4fe11b4d s3:utils: Use lp_dnsdomain() in net_ads.c via 382c300acda s3:libnet: Convert myalias to lower case via 0e96092c189 s3:libnet: Use lp_dns_hostname() in libnet_join.c via 84989f2bf4a s3:lib: Remove obsolete name_to_fqdn() via f6efc74670d s3:librpc: Use lp_dns_hostname() for creating the fqdn via b93fef8e90d s3:utils: Use lp_dns_hostname() for 'net' dns updates via 758bb9aacd5 docs-xml: Add smb.conf option 'dns hostname' from e0d9e285921 selftest/Samba4: make use of get_cmd_env_vars() to setup all relevant env variables
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 589a9ea6767a8112baf664dd18c4aa1667e57d76 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Thu May 9 13:16:50 2024 +1200 s4:kdc: Add comment about possible interaction between the krbtgt account and Group Managed Service Accounts Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> Autobuild-User(master): Andrew Bartlett <abart...@samba.org> Autobuild-Date(master): Wed May 22 21:33:14 UTC 2024 on atb-devel-224 commit d8302e95326639c159fa46788cf645c11d56420c Author: Jo Sutton <josut...@catalyst.net.nz> Date: Mon Apr 15 14:46:47 2024 +1200 s4:kdc: Merge current and previous gMSA keys during period when both are valid Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit a0d639bfb825c2ec0840c048b9b1b3d1474c1146 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Fri Apr 26 13:43:57 2024 +1200 tests/krb5: Test that previous keys are counted as current keys following a gMSA key rollover Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 5ea07824655170fb20bb0c6862d7697ca96b8697 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Fri Apr 26 13:54:42 2024 +1200 s4:libnet: Allow simulating AS‐REQ flags combination for keytab export Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 71899ceb40dcea6a70102c7318c55cf9b3687379 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Wed Apr 24 17:11:03 2024 +1200 s4:libnet: Update export_keytab() docstring Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 048de3da01f2f7c7210085a624e38d671b38aeda Author: Jo Sutton <josut...@catalyst.net.nz> Date: Wed Apr 24 13:45:08 2024 +1200 s4:libnet: Pass SDB_F_ADMIN_DATA flag through to samba_kdc_message2entry() This will allow us to specify whether to specify this flag for a keytab export. Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit aa8aeeb655a5605b2ecbca89762f6a2402152116 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Wed Apr 24 12:48:53 2024 +1200 python:tests: Extract keytab_as_set() function to be usable by other tests Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 5682df15a098dcad7398d8dafdcbccac37371c1a Author: Jo Sutton <josut...@catalyst.net.nz> Date: Wed Apr 24 13:38:53 2024 +1200 python:tests: Manually raise AssertionError This removes the last dependency on ‘self’ in this method. Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 95e80bf1e0533716a4a15dc2848b76bed2e28a2b Author: Jo Sutton <josut...@catalyst.net.nz> Date: Wed Apr 24 12:45:27 2024 +1200 python:tests: Rename ‘keytab_as_set’ variable to be distinct from keytab_as_set() method Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 4597d3140299a2befe17c5b6627bd80a69aa204c Author: Jo Sutton <josut...@catalyst.net.nz> Date: Wed May 22 16:07:17 2024 +1200 third_party/heimdal: Import lorikeet-heimdal-202405220400 (commit 8276d6311146b8ab5d57d092bc5d5fa28282a900) Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 4de250611201834b228ce253cd7a282835b9b3f3 Author: Andreas Schneider <a...@samba.org> Date: Wed Mar 6 16:02:02 2024 +0100 WHATSNEW: Add 'dns hostname' Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit f64e728444bef04a7593184fef21f6560e807cab Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 07:41:06 2024 +0200 auth:ntlmssp: Use lpcfg_dns_hostname() Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 78c2427d9b9afe07d5ae3ff78bae5cb306225327 Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 08:17:04 2024 +0200 auth:ntlmssp: Remove trailing spaces Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 26fd78040e55ea957df5874d0b29f6eb4175f150 Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 08:16:33 2024 +0200 s4:rpc_server: Use lpcfg_dnsdomain() in dnsdb.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit ad9198bb8644b2e62524bbd8f445684ae61c292c Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 08:13:04 2024 +0200 s4:rpc_server: Use lpcfg_dns_hostname() in dnsdb.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 6bd56a2c19dbe6b7fcfde069cbf868b261b673ce Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 07:37:09 2024 +0200 s4:rpc_server: Use lpcfg_dns_hostname() in dnsutils.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit cb9ff7b4c5bcb896de49e4d3949a3ad539a77b0e Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 07:34:54 2024 +0200 s4:rpc_server: Use lpcfg_dns_hostname() in dns_server.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 8ae565a14b59dbd7c67a0bc19e89b8ea1393e41a Author: Andreas Schneider <a...@samba.org> Date: Thu Apr 4 11:28:39 2024 +0200 s4:dns_server: Use lpcfg_dns_hostname() in dlz_bind9.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit f353ce5f96582477733b244e6eca9fc8b92caa2f Author: Andreas Schneider <a...@samba.org> Date: Thu Apr 4 11:31:06 2024 +0200 s4:dfs_server: Use lpcfg_dns_hostname() in dfs_server_ad.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit f3f8aa49641a2ca6ddd57a45b8109862d2629059 Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 08:19:25 2024 +0200 s3:rpc_server: Use lpcfg_dns_hostname() in srv_witness_nt.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit c00571a8b250b17aae436dc9d154b79db473399f Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 19:15:36 2024 +0200 python:tests: Ignore case for group_name comparison Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit c2d4fe11b4da5ddbd94e0b2c15215dcada9b7b47 Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 08:23:23 2024 +0200 s3:utils: Use lp_dnsdomain() in net_ads.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 382c300acda1e4878cae86967430a4f24e5b85cc Author: Andreas Schneider <a...@samba.org> Date: Fri Apr 12 08:33:06 2024 +0200 s3:libnet: Convert myalias to lower case This will be more consistent as it is a dnsname. Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 0e96092c1895ecb41d4064111566b4ada71fe457 Author: Andreas Schneider <a...@samba.org> Date: Thu Apr 4 11:24:13 2024 +0200 s3:libnet: Use lp_dns_hostname() in libnet_join.c Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 84989f2bf4a7265b35625f575db2e14744cc8c63 Author: Andreas Schneider <a...@samba.org> Date: Wed Mar 6 16:00:47 2024 +0100 s3:lib: Remove obsolete name_to_fqdn() Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit f6efc74670d7a7daa1ebf50bf14dde5b75bc2d88 Author: Andreas Schneider <a...@samba.org> Date: Wed Mar 6 15:59:14 2024 +0100 s3:librpc: Use lp_dns_hostname() for creating the fqdn Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit b93fef8e90d3797dad5ce120831fcdfccd6cd30c Author: Andreas Schneider <a...@samba.org> Date: Wed Mar 6 15:53:17 2024 +0100 s3:utils: Use lp_dns_hostname() for 'net' dns updates name_to_fqdn() requires /etc/hosts to be set up in a special way to find out the fqdn for dns updates. They are not set up by default and the DNS update fails. Normally the fqdn is just <lp_netbios_name>.<realm> and we should just use that. However if it is different, you can set it to the special value in the smb.conf now. Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 758bb9aacd587daef31a4320b845e92cb09427ac Author: Andreas Schneider <a...@samba.org> Date: Tue Jan 9 15:47:48 2024 +0100 docs-xml: Add smb.conf option 'dns hostname' Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> ----------------------------------------------------------------------- Summary of changes: WHATSNEW.txt | 14 +++ auth/ntlmssp/gensec_ntlmssp_server.c | 19 +--- dfs_server/dfs_server_ad.c | 8 +- docs-xml/smbdotconf/misc/dnsclientname.xml | 17 ++++ lib/param/loadparm.c | 37 ++++++++ .../tests/blackbox/rpcd_witness_samba_only.py | 3 +- python/samba/tests/dckeytab.py | 100 +++++++++++---------- python/samba/tests/docs.py | 1 + python/samba/tests/krb5/gmsa_tests.py | 95 +++++++++++++++++++- python/samba/tests/krb5/raw_testcase.py | 3 + selftest/knownfail_heimdal_kdc | 1 - source3/include/proto.h | 1 - source3/lib/util.c | 59 ------------ source3/libnet/libnet_join.c | 26 ++++++ source3/librpc/crypto/gse_krb5.c | 10 ++- source3/param/loadparm.c | 35 ++++++++ source3/param/loadparm.h | 1 + source3/rpc_server/witness/srv_witness_nt.c | 30 +------ source3/utils/net_ads.c | 2 +- source3/utils/net_ads_join_dns.c | 6 +- source4/dns_server/dlz_bind9.c | 9 +- source4/dns_server/dns_server.c | 15 ++-- source4/dsdb/gmsa/util.c | 25 ++++++ source4/dsdb/gmsa/util.h | 3 + source4/kdc/db-glue.c | 97 +++++++++++++++++++- source4/kdc/db-glue.h | 2 + source4/kdc/hdb-samba4.c | 4 +- source4/kdc/mit_samba.c | 4 +- source4/libnet/libnet_export_keytab.c | 10 ++- source4/libnet/libnet_export_keytab.h | 1 + source4/libnet/py_net_dckeytab.c | 19 +++- source4/rpc_server/dnsserver/dnsdb.c | 31 +++---- source4/rpc_server/dnsserver/dnsutils.c | 10 ++- third_party/heimdal/kdc/Makefile.am | 4 +- third_party/heimdal/kdc/kerberos5.c | 2 +- 35 files changed, 491 insertions(+), 213 deletions(-) create mode 100644 docs-xml/smbdotconf/misc/dnsclientname.xml Changeset truncated at 500 lines: diff --git a/WHATSNEW.txt b/WHATSNEW.txt index e08070a0ed3..67bdb963cca 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -104,6 +104,19 @@ correct certificate trusts with at least one of the following options: While 'tls verify peer' and 'tls crlfile' are also relevant, see 'man smb.conf' for further details. +New DNS hostname config option +------------------------------ + +To get `net ads dns register` working correctly running manually or during a +domain join a special entry in /etc/hosts was required. This not really +documented and thus the DNS registration mostly didn't work. With the new option +the default is [netbios name].[realm] which should be correct in the majority of +use cases. + +We will also use the value to create service principal names during a Kerberos +authentication and DNS functions. + +This is not supported in samba-tool yet. REMOVED FEATURES ================ @@ -119,6 +132,7 @@ smb.conf changes ldap server require strong auth new values tls trust system cas new tls ca directories new + dns hostname client dns name [netbios name].[realm] KNOWN ISSUES diff --git a/auth/ntlmssp/gensec_ntlmssp_server.c b/auth/ntlmssp/gensec_ntlmssp_server.c index ab92f4d0c09..6da13a1a6fe 100644 --- a/auth/ntlmssp/gensec_ntlmssp_server.c +++ b/auth/ntlmssp/gensec_ntlmssp_server.c @@ -68,7 +68,7 @@ NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security, session_info_flags |= AUTH_SESSION_INFO_NTLM; if (gensec_security->auth_context && gensec_security->auth_context->generate_session_info) { - nt_status = gensec_security->auth_context->generate_session_info(gensec_security->auth_context, mem_ctx, + nt_status = gensec_security->auth_context->generate_session_info(gensec_security->auth_context, mem_ctx, gensec_ntlmssp->server_returned_info, gensec_ntlmssp->ntlmssp_state->user, session_info_flags, @@ -201,22 +201,7 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) if (gensec_security->settings->server_dns_name) { dns_name = gensec_security->settings->server_dns_name; } else { - const char *dnsdomain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx); - char *lower_netbiosname; - - lower_netbiosname = strlower_talloc(ntlmssp_state, netbios_name); - NT_STATUS_HAVE_NO_MEMORY(lower_netbiosname); - - /* Find out the DNS host name */ - if (dnsdomain && dnsdomain[0] != '\0') { - dns_name = talloc_asprintf(ntlmssp_state, "%s.%s", - lower_netbiosname, - dnsdomain); - talloc_free(lower_netbiosname); - NT_STATUS_HAVE_NO_MEMORY(dns_name); - } else { - dns_name = lower_netbiosname; - } + dns_name = lpcfg_dns_hostname(gensec_security->settings->lp_ctx); } if (gensec_security->settings->server_dns_domain) { diff --git a/dfs_server/dfs_server_ad.c b/dfs_server/dfs_server_ad.c index f992042966e..0e601992e4a 100644 --- a/dfs_server/dfs_server_ad.c +++ b/dfs_server/dfs_server_ad.c @@ -804,7 +804,7 @@ NTSTATUS dfs_server_ad_get_referrals(struct loadparm_context *lp_ctx, const char *netbios_domain; const char *dns_domain; const char *netbios_name; - const char *dns_name; + const char *dns_hostname = NULL; const char **netbios_aliases; char path_separator; @@ -863,13 +863,13 @@ NTSTATUS dfs_server_ad_get_referrals(struct loadparm_context *lp_ctx, netbios_domain = lpcfg_workgroup(lp_ctx); dns_domain = lpcfg_dnsdomain(lp_ctx); netbios_name = lpcfg_netbios_name(lp_ctx); - dns_name = talloc_asprintf(r, "%s.%s", netbios_name, dns_domain); - if (dns_name == NULL) { + dns_hostname = lpcfg_dns_hostname(lp_ctx); + if (dns_hostname == NULL) { return NT_STATUS_NO_MEMORY; } if ((strcasecmp_m(server_name, netbios_name) == 0) || - (strcasecmp_m(server_name, dns_name) == 0)) { + (strcasecmp_m(server_name, dns_hostname) == 0)) { /* * If it is not domain related do not * handle it here. diff --git a/docs-xml/smbdotconf/misc/dnsclientname.xml b/docs-xml/smbdotconf/misc/dnsclientname.xml new file mode 100644 index 00000000000..9de2bde918a --- /dev/null +++ b/docs-xml/smbdotconf/misc/dnsclientname.xml @@ -0,0 +1,17 @@ +<samba:parameter name="dns hostname" + context="G" + type="string" + function="_dns_hostname" + xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> +<description> + This value is used either register with AD during a join or by calling + <programlisting> + net ads dns register + </programlisting> + or during Kerberos authentication to create service principal names. This + is not supported in samba-tool yet. +</description> + +<value type="default">[netbios name].[realm]</value> +<value type="example">client-hostname.example.com</value> +</samba:parameter> diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index f779affe54a..00971309042 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -3763,3 +3763,40 @@ int32_t lpcfg_parse_enum_vals(const char *param_name, return ret; } + +const char *lpcfg_dns_hostname(struct loadparm_context *lp_ctx) +{ + const char *dns_hostname = lpcfg__dns_hostname(lp_ctx); + const char *dns_domain = lpcfg_dnsdomain(lp_ctx); + char *netbios_name = NULL; + char *hostname = NULL; + + if (dns_hostname != NULL && dns_hostname[0] != '\0') { + return dns_hostname; + } + + netbios_name = strlower_talloc(lp_ctx, lpcfg_netbios_name(lp_ctx)); + if (netbios_name == NULL) { + return NULL; + } + + /* If it isn't set, try to initialize with [netbios name].[realm] */ + if (dns_domain != NULL && dns_domain[0] != '\0') { + hostname = talloc_asprintf(lp_ctx, + "%s.%s", + netbios_name, + dns_domain); + } else { + hostname = talloc_strdup(lp_ctx, netbios_name); + } + TALLOC_FREE(netbios_name); + if (hostname == NULL) { + return NULL; + } + + lpcfg_string_set(lp_ctx->globals->ctx, + &lp_ctx->globals->_dns_hostname, + hostname); + + return hostname; +} diff --git a/python/samba/tests/blackbox/rpcd_witness_samba_only.py b/python/samba/tests/blackbox/rpcd_witness_samba_only.py index aa81c347f99..38bc7e078c3 100755 --- a/python/samba/tests/blackbox/rpcd_witness_samba_only.py +++ b/python/samba/tests/blackbox/rpcd_witness_samba_only.py @@ -286,7 +286,8 @@ class RpcdWitnessSambaTests(BlackboxTestCase): expected_state = witness.WITNESS_STATE_AVAILABLE self.assertIsNotNone(iface.group_name) - self.assertEqual(iface.group_name, self.interface_group_name) + self.assertEqual(iface.group_name.lower(), + self.interface_group_name.lower()) self.assertEqual(iface.version, witness.WITNESS_V2) self.assertEqual(iface.state, expected_state) diff --git a/python/samba/tests/dckeytab.py b/python/samba/tests/dckeytab.py index 9424c8e50ff..6c8a1795e0f 100644 --- a/python/samba/tests/dckeytab.py +++ b/python/samba/tests/dckeytab.py @@ -34,6 +34,36 @@ from ldb import SCOPE_BASE enable_net_export_keytab() +def keytab_as_set(keytab_bytes): + def entry_to_tuple(entry): + principal = '/'.join(entry.principal.components) + f"@{entry.principal.realm}" + enctype = entry.enctype + kvno = entry.key_version + key = bytes(entry.key.data) + return (principal, enctype, kvno, key) + + keytab = ndr_unpack(krb5ccache.KEYTAB, keytab_bytes) + entry = keytab.entry + + keytab_set = set() + + entry_as_tuple = entry_to_tuple(entry) + keytab_set.add(entry_as_tuple) + + keytab_bytes = keytab.further_entry + while keytab_bytes: + multiple_entry = ndr_unpack(krb5ccache.MULTIPLE_KEYTAB_ENTRIES, keytab_bytes) + entry = multiple_entry.entry + entry_as_tuple = entry_to_tuple(entry) + if entry_as_tuple in keytab_set: + raise AssertionError('entry found multiple times in keytab') + keytab_set.add(entry_as_tuple) + + keytab_bytes = multiple_entry.further_entry + + return keytab_set + + class DCKeytabTests(TestCaseInTempDir): def setUp(self): super().setUp() @@ -50,34 +80,6 @@ class DCKeytabTests(TestCaseInTempDir): def tearDown(self): super().tearDown() - def keytab_as_set(self, keytab_bytes): - def entry_to_tuple(entry): - principal = '/'.join(entry.principal.components) + f"@{entry.principal.realm}" - enctype = entry.enctype - kvno = entry.key_version - key = bytes(entry.key.data) - return (principal, enctype, kvno, key) - - keytab = ndr_unpack(krb5ccache.KEYTAB, keytab_bytes) - entry = keytab.entry - - keytab_as_set = set() - - entry_as_tuple = entry_to_tuple(entry) - keytab_as_set.add(entry_as_tuple) - - keytab_bytes = keytab.further_entry - while keytab_bytes: - multiple_entry = ndr_unpack(krb5ccache.MULTIPLE_KEYTAB_ENTRIES, keytab_bytes) - entry = multiple_entry.entry - entry_as_tuple = entry_to_tuple(entry) - self.assertNotIn(entry_as_tuple, keytab_as_set) - keytab_as_set.add(entry_as_tuple) - - keytab_bytes = multiple_entry.further_entry - - return keytab_as_set - def test_export_keytab(self): net = Net(None, self.lp) self.addCleanup(self.rm_files, self.ktfile) @@ -89,7 +91,7 @@ class DCKeytabTests(TestCaseInTempDir): keytab_bytes = bytes_kt.read() # confirm only this principal was exported - for entry in self.keytab_as_set(keytab_bytes): + for entry in keytab_as_set(keytab_bytes): (principal, enctype, kvno, key) = entry self.assertEqual(principal, self.principal) @@ -103,10 +105,10 @@ class DCKeytabTests(TestCaseInTempDir): keytab_bytes = bytes_kt.read() # Parse the keytab - keytab_as_set = self.keytab_as_set(keytab_bytes) + keytab_set = keytab_as_set(keytab_bytes) # confirm many principals were exported - self.assertGreater(len(keytab_as_set), 10) + self.assertGreater(len(keytab_set), 10) def test_export_keytab_all_keep_stale(self): net = Net(None, self.lp) @@ -125,15 +127,15 @@ class DCKeytabTests(TestCaseInTempDir): keytab_bytes = bytes_kt.read() # confirm many principals were exported - # self.keytab_as_set() will also check we only got it + # keytab_as_set() will also check we only got it # each entry once - keytab_as_set = self.keytab_as_set(keytab_bytes) + keytab_set = keytab_as_set(keytab_bytes) - self.assertGreater(len(keytab_as_set), 10) + self.assertGreater(len(keytab_set), 10) # Look for the new principal, showing this was updated found = False - for entry in keytab_as_set: + for entry in keytab_set: (principal, enctype, kvno, key) = entry if principal == new_principal: found = True @@ -180,9 +182,9 @@ class DCKeytabTests(TestCaseInTempDir): self.assertEqual(keytab_orig_bytes, keytab_bytes) # confirm only this principal was exported. - # self.keytab_as_set() will also check we only got it + # keytab_as_set() will also check we only got it # once - for entry in self.keytab_as_set(keytab_bytes): + for entry in keytab_as_set(keytab_bytes): (principal, enctype, kvno, key) = entry self.assertEqual(principal, new_principal) @@ -268,13 +270,13 @@ class DCKeytabTests(TestCaseInTempDir): self.assertNotEqual(keytab_orig_bytes, keytab_change_bytes) - # self.keytab_as_set() will also check we got each entry + # keytab_as_set() will also check we got each entry # exactly once - keytab_as_set = self.keytab_as_set(keytab_change_bytes) + keytab_set = keytab_as_set(keytab_change_bytes) # Look for the new principal, showing this was updated but the old kept found = 0 - for entry in keytab_as_set: + for entry in keytab_set: (principal, enctype, kvno, key) = entry if principal == new_principal and enctype == credentials.ENCTYPE_AES128_CTS_HMAC_SHA1_96: found += 1 @@ -284,7 +286,7 @@ class DCKeytabTests(TestCaseInTempDir): # confirm at least 12 keys (4 changes, 1 in orig export and 3 # history in 2nd export, 3 enctypes) were exported - self.assertGreaterEqual(len(keytab_as_set), 12) + self.assertGreaterEqual(len(keytab_set), 12) def test_export_keytab_change3_update_only_current_keep(self): new_principal=f"keytab_testuser@{self.creds.get_realm()}" @@ -317,13 +319,13 @@ class DCKeytabTests(TestCaseInTempDir): self.assertNotEqual(keytab_orig_bytes, keytab_change_bytes) - # self.keytab_as_set() will also check we got each entry + # keytab_as_set() will also check we got each entry # exactly once - keytab_as_set = self.keytab_as_set(keytab_change_bytes) + keytab_set = keytab_as_set(keytab_change_bytes) # Look for the new principal, showing this was updated but the old kept found = 0 - for entry in keytab_as_set: + for entry in keytab_set: (principal, enctype, kvno, key) = entry if principal == new_principal and enctype == credentials.ENCTYPE_AES128_CTS_HMAC_SHA1_96: found += 1 @@ -333,7 +335,7 @@ class DCKeytabTests(TestCaseInTempDir): # confirm at least 6 keys (1 change, 1 in orig export # both with 3 enctypes) were exported - self.assertGreaterEqual(len(keytab_as_set), 6) + self.assertGreaterEqual(len(keytab_set), 6) def test_export_keytab_change2_export2_update_keep(self): new_principal=f"keytab_testuser@{self.creds.get_realm()}" @@ -361,13 +363,13 @@ class DCKeytabTests(TestCaseInTempDir): self.assertNotEqual(keytab_orig_bytes, keytab_change_bytes) - # self.keytab_as_set() will also check we got each entry + # keytab_as_set() will also check we got each entry # exactly once - keytab_as_set = self.keytab_as_set(keytab_change_bytes) + keytab_set = keytab_as_set(keytab_change_bytes) # Look for the new principal, showing this was updated but the old kept found = 0 - for entry in keytab_as_set: + for entry in keytab_set: (principal, enctype, kvno, key) = entry if principal == new_principal and enctype == credentials.ENCTYPE_AES128_CTS_HMAC_SHA1_96: found += 1 @@ -376,7 +378,7 @@ class DCKeytabTests(TestCaseInTempDir): self.assertEqual(found, 3) # confirm at least 9 keys (3 exports, 3 enctypes) were exported - self.assertGreaterEqual(len(keytab_as_set), 9) + self.assertGreaterEqual(len(keytab_set), 9) def test_export_keytab_not_a_dir(self): net = Net(None, self.lp) diff --git a/python/samba/tests/docs.py b/python/samba/tests/docs.py index df20b04bc7e..66189277260 100644 --- a/python/samba/tests/docs.py +++ b/python/samba/tests/docs.py @@ -217,6 +217,7 @@ class SmbDotConfTests(TestCase): 'max open files', 'include system krb5 conf', 'smbd max async dosmode', + 'dns hostname', ]) def setUp(self): diff --git a/python/samba/tests/krb5/gmsa_tests.py b/python/samba/tests/krb5/gmsa_tests.py index 7077c0c95a5..031e27bb8fe 100755 --- a/python/samba/tests/krb5/gmsa_tests.py +++ b/python/samba/tests/krb5/gmsa_tests.py @@ -23,7 +23,7 @@ import os sys.path.insert(0, "bin/python") os.environ["PYTHONUNBUFFERED"] = "1" -from typing import Callable, Iterable, NewType, Optional, Tuple, TypeVar +from typing import Callable, Iterable, NewType, Optional, Set, Tuple, TypeVar import datetime from itertools import chain @@ -41,6 +41,7 @@ from samba import ( ) from samba.dcerpc import gkdi, gmsa, misc, netlogon, security, srvsvc from samba.ndr import ndr_pack, ndr_unpack +from samba.net import Net from samba.nt_time import ( nt_time_delta_from_timedelta, nt_time_from_datetime, @@ -58,6 +59,7 @@ from samba.gkdi import ( ) from samba.tests import connect_samdb +from samba.tests.dckeytab import keytab_as_set from samba.tests.krb5 import kcrypto from samba.tests.gkdi import GkdiBaseTest, ROOT_KEY_START_TIME from samba.tests.krb5.kdc_base_test import KDCBaseTest @@ -1554,6 +1556,97 @@ class GmsaTests(GkdiBaseTest, KDCBaseTest): # Expect the gensec logon to fail. self.gensec_ntlmssp_logon(creds, samdb, expect_success=False) + def test_gmsa_keys_when_previous_password_is_not_acceptable(self): + self._check_gmsa_keys(within_valid_window=False, expect_previous_keys=False) + + def test_gmsa_keys_when_previous_password_is_acceptable(self): + self._check_gmsa_keys(within_valid_window=True, expect_previous_keys=True) + + def _check_gmsa_keys( + self, *, within_valid_window: bool, expect_previous_keys: bool + ): + password_interval = 77 + + samdb = self.get_local_samdb() + series = self.gmsa_series(password_interval) + self.set_db_time(samdb, series.start_of_interval(0)) + + creds = self.gmsa_account(samdb=samdb, interval=password_interval) + + if within_valid_window: + db_time = series.within_previous_password_valid_window(1) + else: + db_time = series.outside_previous_password_valid_window(1) + self.set_db_time(samdb, db_time) + + gmsa_principal = f"{creds.get_username()}@{creds.get_realm()}" + + ktfile = os.path.join(self.tempdir, "test.keytab") + self.addCleanup(self.rm_files, ktfile) + + net = Net(None, self.get_lp()) + net.export_keytab( + keytab=ktfile, + samdb=samdb, + principal=gmsa_principal, + only_current_keys=True, + as_for_AS_REQ=True, + ) + self.assertTrue(os.path.exists(ktfile), "keytab was not created") + + with open(ktfile, "rb") as bytes_kt: + keytab_bytes = bytes_kt.read() + + keytab_set = keytab_as_set(keytab_bytes) + exported_etypes = {entry[1] for entry in keytab_set} + + # Ensure that the AES keys were exported. + self.assertLessEqual( + {kcrypto.Enctype.AES256, kcrypto.Enctype.AES128}, exported_etypes + ) + + def fill_keytab( + creds: KerberosCredentials, + keytab: Set[Tuple[str, kcrypto.Enctype, int, bytes]], + etypes: Iterable[kcrypto.Enctype], + ) -> None: + for etype in etypes: + key = self.TicketDecryptionKey_from_creds(creds, etype=etype) + kvno = 2 + entry = gmsa_principal, etype, kvno, key.key.contents + + self.assertNotIn(entry, keytab, "key already present in keytab") + keytab.add(entry) + + expected_keytab = set() + + if expect_previous_keys: + # Fill the expected keytab with the previous keys. -- Samba Shared Repository