The branch, master has been updated via bdfbf25255e test_kinit_export_keytab: reset pw of the test account and test --only-current-keys via b4be5718d3d samba-tool: let 'samba-tool domain exportkeytab' take an --only-current-keys option via 2793ef3e163 samba.tests.dckeytab: add test_export_keytab_change3_update_only_current_keep() via e2a5fbf5cf2 s4:libnet_export_keytab: add only_current_keys option via 7f1e89488a7 s4:kdc: also provide cross-realm keys via samba_kdc_seq() via 37292f8a60f s4:kdc: let samba_kdc_trust_message2entry() return all keys with SDB_F_ADMIN_DATA via 6ecc607edee s4:kdc: split out samba_kdc_fill_trust_keys() helper via f5c8c212dcb s4:kdc: add available_enctypes to supported_session_etypes in samba_kdc_trust_message2entry() via f48699641cf s4:kdc: add a returned_kvno helper variable in samba_kdc_trust_message2entry() via d1efc396de4 s4:kdc: let samba_kdc_trust_message2entry() ignore KRB5_PROG_ETYPE_NOSUPP via 8cfebc36edc s4:kdc: split out samba_kdc_fill_trust_keys() helper via 83f03513fd5 s3:libnet: add a debug message to libnet_keytab_add_to_keytab_entries() via 888a785f476 s3:libnet: add support for trusted domains in libnet_dssync_keytab.c via 2b2cc544725 s3:libnet: split out store_or_fetch_attribute() from parse_user() in libnet_dssync_keytab.c via feff15fc88b s3:libnet: split out parse_user() in libnet_dssync_keytab.c via 52df4063871 s3:libnet: let parse_user() in libnet_dssync_keytab.c work without nt hash from 01849ab1bca s4:kdc: Implement KDC plugin hardware authentication policy
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit bdfbf25255e457c3e5d5d75ee09fca3af461c5a7 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Apr 17 16:15:17 2024 +0200 test_kinit_export_keytab: reset pw of the test account and test --only-current-keys 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): Wed May 22 04:07:02 UTC 2024 on atb-devel-224 commit b4be5718d3de3bc90d142cb53f79fe067d0a3e0a Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 16:14:18 2024 +0100 samba-tool: let 'samba-tool domain exportkeytab' take an --only-current-keys option Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 2793ef3e1632c735f9caac015503aab06f53d543 Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 16:31:22 2024 +0100 samba.tests.dckeytab: add test_export_keytab_change3_update_only_current_keep() This tests that only_current_keys=True works. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit e2a5fbf5cf2b65db77e7c5a859c896acca69f432 Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 16:11:10 2024 +0100 s4:libnet_export_keytab: add only_current_keys option By default we also export on the old and older passwords... In order to do a kinit with a keytab it might we useful to include only the current keys. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 7f1e89488a7212832819380a93fe137a6fa28c37 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Feb 3 14:14:06 2022 +0100 s4:kdc: also provide cross-realm keys via samba_kdc_seq() This means that 'samba-tool domain exportkeytab' is able to export them. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 37292f8a60f8fa82faa7bde4314919dcae6fb7ab Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 19:23:46 2024 +0100 s4:kdc: let samba_kdc_trust_message2entry() return all keys with SDB_F_ADMIN_DATA Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 6ecc607edeeeb1877b5ecf02ba60d6c8799f583a Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 19:19:20 2024 +0100 s4:kdc: split out samba_kdc_fill_trust_keys() helper This simplifies the logic in samba_kdc_trust_message2entry(), is very similar to our samba_kdc_fill_user_keys() helper and will make it trivial to provide the previous keys in entry->old_keys in the next commit. Review with: git show -p --patience Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit f5c8c212dcba48167d8ae8c555a5c4750cb763fd Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 19:19:20 2024 +0100 s4:kdc: add available_enctypes to supported_session_etypes in samba_kdc_trust_message2entry() This aligns the logic of samba_kdc_trust_message2entry() with samba_kdc_message2entry_keys(). Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit f48699641cf95f1e2d197e0f8ea1ed4ce2c4fb41 Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 19:19:20 2024 +0100 s4:kdc: add a returned_kvno helper variable in samba_kdc_trust_message2entry() This will simplifiy further changes. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit d1efc396de4855a90c7dfd3d935028a21d780272 Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 19:19:20 2024 +0100 s4:kdc: let samba_kdc_trust_message2entry() ignore KRB5_PROG_ETYPE_NOSUPP We already handle it in samba_kdc_fill_user_keys() mostly for DES keys, but other encryption types might be from kerberos libraries in future. And things like FIPS mode may also alter the runtime behaviour. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 8cfebc36edcf5a4ba259d11c6e319aba303ea8ff Author: Stefan Metzmacher <me...@samba.org> Date: Fri Mar 15 19:19:20 2024 +0100 s4:kdc: split out samba_kdc_fill_trust_keys() helper Let samba_kdc_trust_message2entry() also fill in the salt used by the key. This is not strictly needed, but it's better to be consistent. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 83f03513fd5221cb3bf914bd996c86f0840f34dd Author: Stefan Metzmacher <me...@samba.org> Date: Thu Feb 3 18:27:19 2022 +0100 s3:libnet: add a debug message to libnet_keytab_add_to_keytab_entries() Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 888a785f476c64cd34a67149f69bd20f9b7749d8 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Feb 3 18:27:19 2022 +0100 s3:libnet: add support for trusted domains in libnet_dssync_keytab.c It means that keytabs generated via 'net rpc vampire keytab' are able to decrypt cross-realm tickets in wireshark. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 2b2cc544725368e1922c3c71541c2b478a47586b Author: Stefan Metzmacher <me...@samba.org> Date: Thu Feb 3 14:48:03 2022 +0100 s3:libnet: split out store_or_fetch_attribute() from parse_user() in libnet_dssync_keytab.c This way we can easily re-use the logic in the next commits... Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit feff15fc88b548f9b59aef1427dd1fb5d72ef2a1 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Feb 3 14:48:03 2022 +0100 s3:libnet: split out parse_user() in libnet_dssync_keytab.c Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 52df4063871bb6b18e84e559a94fd05ebf33b012 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Feb 3 14:48:03 2022 +0100 s3:libnet: let parse_user() in libnet_dssync_keytab.c work without nt hash It happens in setups with 'nt hash store = never'. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andrew Bartlett <abart...@samba.org> ----------------------------------------------------------------------- Summary of changes: python/samba/netcmd/domain/keytab.py | 9 +- python/samba/tests/dckeytab.py | 53 ++- selftest/knownfail.d/export-keytab | 1 - source3/libnet/libnet_dssync_keytab.c | 595 ++++++++++++++++++++++--- source3/libnet/libnet_keytab.c | 2 + source4/auth/kerberos/srv_keytab.c | 3 +- source4/kdc/db-glue.c | 556 +++++++++++++++++------ source4/libnet/libnet_export_keytab.c | 87 ++++ source4/libnet/libnet_export_keytab.h | 1 + source4/libnet/py_net_dckeytab.c | 12 +- testprogs/blackbox/test_kinit_export_keytab.sh | 22 +- 11 files changed, 1110 insertions(+), 231 deletions(-) delete mode 100644 selftest/knownfail.d/export-keytab Changeset truncated at 500 lines: diff --git a/python/samba/netcmd/domain/keytab.py b/python/samba/netcmd/domain/keytab.py index 0136a11436f..a6d5291ae1a 100644 --- a/python/samba/netcmd/domain/keytab.py +++ b/python/samba/netcmd/domain/keytab.py @@ -47,6 +47,9 @@ else: takes_options = [ Option("--principal", help="extract only this principal", type=str), Option("--keep-stale-entries", help="keep stale keys in keytab (useful for collecting keys for Wireshark)", action="store_true"), + Option("--only-current-keys", + help="This avoids exporting old and older keys (useful for keytabs used by kinit)", + action="store_true"), ] takes_args = ["keytab"] @@ -58,7 +61,8 @@ else: versionopts=None, hostopts=None, principal=None, - keep_stale_entries=None): + keep_stale_entries=None, + only_current_keys=None): lp = sambaopts.get_loadparm() net = Net(None, lp) samdb = self.ldb_connect(hostopts, sambaopts, credopts) @@ -66,6 +70,7 @@ else: net.export_keytab(samdb=samdb, keytab=keytab, principal=principal, - keep_stale_entries=keep_stale_entries) + keep_stale_entries=keep_stale_entries, + only_current_keys=only_current_keys) except NTSTATUSError as error: raise CommandError(f"Failed to export domain keys into keytab {keytab}: {error.args[1]}") diff --git a/python/samba/tests/dckeytab.py b/python/samba/tests/dckeytab.py index 31139c0360f..9424c8e50ff 100644 --- a/python/samba/tests/dckeytab.py +++ b/python/samba/tests/dckeytab.py @@ -259,7 +259,7 @@ class DCKeytabTests(TestCaseInTempDir): # keytab self.samdb.setpassword(f"(userPrincipalName={new_principal})", "5rfvBGT%") self.samdb.setpassword(f"(userPrincipalName={new_principal})", "6rfvBGT%") - self.samdb.setpassword(f"(userPrincipalName={new_principal})", "6rfvBGT%") + self.samdb.setpassword(f"(userPrincipalName={new_principal})", "7rfvBGT%") net.export_keytab(keytab=self.ktfile, principal=new_principal, keep_stale_entries=True) @@ -279,13 +279,62 @@ class DCKeytabTests(TestCaseInTempDir): if principal == new_principal and enctype == credentials.ENCTYPE_AES128_CTS_HMAC_SHA1_96: found += 1 - # Samba currently does not export the previous keys into the keytab, but could. + # We exported the previous keys into the keytab... self.assertEqual(found, 4) # 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) + def test_export_keytab_change3_update_only_current_keep(self): + new_principal=f"keytab_testuser@{self.creds.get_realm()}" + self.samdb.newuser("keytab_testuser", "4rfvBGT%") + self.addCleanup(self.samdb.deleteuser, "keytab_testuser") + net = Net(None, self.lp) + self.addCleanup(self.rm_files, self.ktfile) + net.export_keytab(keytab=self.ktfile, principal=new_principal) + self.assertTrue(os.path.exists(self.ktfile), 'keytab was not created') + + # Parse the first entry in the keytab + with open(self.ktfile, 'rb') as bytes_kt: + keytab_orig_bytes = bytes_kt.read() + + # By changing the password three times, we allow Samba to fill + # out current, old, older from supplementalCredentials and + # still have one password that must still be from the original + # keytab + self.samdb.setpassword(f"(userPrincipalName={new_principal})", "5rfvBGT%") + self.samdb.setpassword(f"(userPrincipalName={new_principal})", "6rfvBGT%") + self.samdb.setpassword(f"(userPrincipalName={new_principal})", "7rfvBGT%") + + net.export_keytab(keytab=self.ktfile, + principal=new_principal, + keep_stale_entries=True, + only_current_keys=True) + + with open(self.ktfile, 'rb') as bytes_kt: + keytab_change_bytes = bytes_kt.read() + + self.assertNotEqual(keytab_orig_bytes, keytab_change_bytes) + + # self.keytab_as_set() will also check we got each entry + # exactly once + keytab_as_set = self.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: + (principal, enctype, kvno, key) = entry + if principal == new_principal and enctype == credentials.ENCTYPE_AES128_CTS_HMAC_SHA1_96: + found += 1 + + # By default previous keys are not exported into the keytab. + self.assertEqual(found, 2) + + # confirm at least 6 keys (1 change, 1 in orig export + # both with 3 enctypes) were exported + self.assertGreaterEqual(len(keytab_as_set), 6) + def test_export_keytab_change2_export2_update_keep(self): new_principal=f"keytab_testuser@{self.creds.get_realm()}" self.samdb.newuser("keytab_testuser", "4rfvBGT%") diff --git a/selftest/knownfail.d/export-keytab b/selftest/knownfail.d/export-keytab deleted file mode 100644 index 34c16072f5a..00000000000 --- a/selftest/knownfail.d/export-keytab +++ /dev/null @@ -1 +0,0 @@ -^samba.tests.dckeytab.samba.tests.dckeytab.DCKeytabTests.test_export_keytab_change3_update_keep diff --git a/source3/libnet/libnet_dssync_keytab.c b/source3/libnet/libnet_dssync_keytab.c index 41893b4f7fd..a4fc4e98b0c 100644 --- a/source3/libnet/libnet_dssync_keytab.c +++ b/source3/libnet/libnet_dssync_keytab.c @@ -23,6 +23,7 @@ #include "libnet/libnet_dssync.h" #include "libnet/libnet_keytab.h" #include "librpc/gen_ndr/ndr_drsblobs.h" +#include "lib/crypto/md4.h" #if defined(HAVE_ADS) @@ -233,9 +234,76 @@ done: return status; } -static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, - struct libnet_keytab_context *ctx, - struct drsuapi_DsReplicaObjectListItemEx *cur) +static NTSTATUS store_or_fetch_attribute(TALLOC_CTX *mem_ctx, + struct libnet_keytab_context *ctx, + const char *object_dn, + const char *attr, + char **value) +{ + DATA_BLOB blob = { .length = 0, }; + NTSTATUS status; + + if (*value == NULL) { + /* look into keytab ... */ + struct libnet_keytab_entry *entry = NULL; + char *principal = NULL; + + D_DEBUG("looking for %s/%s@%s in keytayb...\n", + attr, object_dn, ctx->dns_domain_name); + + principal = talloc_asprintf(mem_ctx, + "%s/%s@%s", + attr, + object_dn, + ctx->dns_domain_name); + if (principal == NULL) { + return NT_STATUS_NO_MEMORY; + } + entry = libnet_keytab_search(ctx, + principal, + 0, + ENCTYPE_NULL, + mem_ctx); + if (entry != NULL) { + *value = talloc_strndup(mem_ctx, + (char *)entry->password.data, + entry->password.length); + if (*value == NULL) { + return NT_STATUS_NO_MEMORY; + } + D_DEBUG("found %s: %s\n", attr, *value); + TALLOC_FREE(entry); + } else { + *value = NULL; + D_DEBUG("entry not found\n"); + } + TALLOC_FREE(principal); + return NT_STATUS_OK; + } + + blob = data_blob_string_const_null(*value); + blob = data_blob_dup_talloc(mem_ctx, blob); + if (blob.data == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = libnet_keytab_add_to_keytab_entries(mem_ctx, + ctx, + 0, + object_dn, + attr, + ENCTYPE_NULL, + blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +static NTSTATUS parse_user(TALLOC_CTX *mem_ctx, + struct libnet_keytab_context *ctx, + struct drsuapi_DsReplicaObjectListItemEx *cur) { NTSTATUS status = NT_STATUS_OK; uchar nt_passwd[16]; @@ -266,7 +334,7 @@ static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } - DEBUG(3, ("parsing object '%s'\n", object_dn)); + DEBUG(3, ("parsing user '%s'\n", object_dn)); for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) { @@ -278,6 +346,9 @@ static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, spn = talloc_array(mem_ctx, char *, num_spns); for (count = 0; count < num_spns; count++) { blob = attr->value_ctr.values[count].blob; + if (blob == NULL) { + continue; + } pull_string_talloc(spn, NULL, 0, &spn[count], blob->data, blob->length, @@ -285,6 +356,18 @@ static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, } } + if (attr->attid == DRSUAPI_ATTID_unicodePwd && + cur->meta_data_ctr != NULL && + cur->meta_data_ctr->count == + cur->object.attribute_ctr.num_attributes) + { + /* + * pick the kvno from the unicodePwd + * meta data, even without a unicodePwd blob + */ + kvno = cur->meta_data_ctr->meta_data[i].version; + } + if (attr->value_ctr.num_values != 1) { continue; } @@ -304,18 +387,6 @@ static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, memcpy(&nt_passwd, blob->data, 16); got_pwd = true; - - /* pick the kvno from the meta_data version, - * thanks, metze, for explaining this */ - - if (!cur->meta_data_ctr) { - break; - } - if (cur->meta_data_ctr->count != - cur->object.attribute_ctr.num_attributes) { - break; - } - kvno = cur->meta_data_ctr->meta_data[i].version; break; case DRSUAPI_ATTID_ntPwdHistory: pwd_history_len = blob->length / 16; @@ -353,53 +424,16 @@ static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, } } - if (!got_pwd) { - DEBUG(10, ("no password (unicodePwd) found - skipping.\n")); - return NT_STATUS_OK; - } - - if (name) { - status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, 0, object_dn, - "SAMACCOUNTNAME", - ENCTYPE_NULL, - data_blob_talloc(mem_ctx, name, - strlen(name) + 1)); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - } else { - /* look into keytab ... */ - struct libnet_keytab_entry *entry = NULL; - char *principal = NULL; - - DEBUG(10, ("looking for SAMACCOUNTNAME/%s@%s in keytayb...\n", - object_dn, ctx->dns_domain_name)); - - principal = talloc_asprintf(mem_ctx, "%s/%s@%s", - "SAMACCOUNTNAME", - object_dn, - ctx->dns_domain_name); - if (!principal) { - DEBUG(1, ("talloc failed\n")); - return NT_STATUS_NO_MEMORY; - } - entry = libnet_keytab_search(ctx, principal, 0, ENCTYPE_NULL, - mem_ctx); - if (entry) { - name = (char *)talloc_memdup(mem_ctx, - entry->password.data, - entry->password.length); - if (!name) { - DEBUG(1, ("talloc failed!\n")); - return NT_STATUS_NO_MEMORY; - } else { - DEBUG(10, ("found name %s\n", name)); - } - TALLOC_FREE(entry); - } else { - DEBUG(10, ("entry not found\n")); - } - TALLOC_FREE(principal); + status = store_or_fetch_attribute(mem_ctx, + ctx, + object_dn, + "SAMACCOUNTNAME", + &name); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("store_or_fetch_attribute(%s, %s, %s): %s\n", + object_dn, "SAMACCOUNTNAME", name, + nt_errstr(status)); + return status; } if (!name) { @@ -422,12 +456,14 @@ static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, } DEBUGADD(1,("\n")); - status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno, name, NULL, - ENCTYPE_ARCFOUR_HMAC, - data_blob_talloc(mem_ctx, nt_passwd, 16)); + if (got_pwd) { + status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno, name, NULL, + ENCTYPE_ARCFOUR_HMAC, + data_blob_talloc(mem_ctx, nt_passwd, 16)); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (!NT_STATUS_IS_OK(status)) { + return status; + } } /* add kerberos keys (if any) */ @@ -528,6 +564,429 @@ static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, return status; } +static NTSTATUS parse_AuthenticationInformation(TALLOC_CTX *mem_ctx, + struct libnet_keytab_context *ctx, + const char *dn, + const char *trust_name, + const char *attr_name, + const char *salt_principal, + const char *type, + uint32_t *kvno, + const struct AuthenticationInformationArray *ia) +{ + uint32_t i; + struct samr_Password _nthash = {{ 0, }}; + const struct samr_Password *nthash = NULL; + const struct AuthInfoClear *clear = NULL; + DATA_BLOB password_utf8 = data_blob_null; + + for (i = 0; i < ia->count; i++) { + const struct AuthenticationInformation *a = &ia->array[i]; + + switch (a->AuthType) { + case TRUST_AUTH_TYPE_VERSION: + *kvno = a->AuthInfo.version.version; + break; + case TRUST_AUTH_TYPE_NT4OWF: + nthash = &a->AuthInfo.nt4owf.password; + break; + case TRUST_AUTH_TYPE_CLEAR: + clear = &a->AuthInfo.clear; + break; + default: + break; + } + } + + if (clear != NULL && clear->size != 0) { + DATA_BLOB password_utf16 = data_blob_null; + bool ok; + + password_utf16 = data_blob_const(clear->password, + clear->size); + + if (nthash == NULL) { + mdfour(_nthash.hash, + password_utf16.data, + password_utf16.length); + nthash = &_nthash; + } + + ok = convert_string_talloc(mem_ctx, + CH_UTF16MUNGED, CH_UTF8, + password_utf16.data, + password_utf16.length, + (void *)&password_utf8.data, + &password_utf8.length); + if (!ok) { + return NT_STATUS_NO_MEMORY; + } + } + + if (password_utf8.length != 0) { + krb5_principal salt_princ = NULL; + krb5_data salt = { 0, }; + krb5_data cleartext_data = { 0, }; + krb5_enctype enctypes[] = { + ENCTYPE_AES256_CTS_HMAC_SHA1_96, + ENCTYPE_AES128_CTS_HMAC_SHA1_96, + }; + size_t ei; + krb5_error_code kret; + NTSTATUS status; + + kret = smb_krb5_parse_name(ctx->context, + salt_principal, + &salt_princ); + if (kret != 0) { + return NT_STATUS_NO_MEMORY; + } + + cleartext_data.data = discard_const_p(char, password_utf8.data); + cleartext_data.length = password_utf8.length; + + kret = smb_krb5_get_pw_salt(ctx->context, + salt_princ, + &salt); + if (kret != 0) { + krb5_free_principal(ctx->context, salt_princ); + return NT_STATUS_NO_MEMORY; + } + + for (ei = 0; ei < ARRAY_SIZE(enctypes); ei++) { + krb5_keyblock keyb = { 0, }; + DATA_BLOB blob = data_blob_null; + + kret = smb_krb5_create_key_from_string(ctx->context, + salt_princ, + &salt, + &cleartext_data, + enctypes[ei], + &keyb); + if (kret != 0) { + smb_krb5_free_data_contents(ctx->context, &salt); + krb5_free_principal(ctx->context, salt_princ); + return NT_STATUS_NO_MEMORY; + } + + blob = data_blob_talloc(mem_ctx, + KRB5_KEY_DATA(&keyb), + KRB5_KEY_LENGTH(&keyb)); + krb5_free_keyblock_contents(ctx->context, &keyb); + + status = libnet_keytab_add_to_keytab_entries(mem_ctx, + ctx, + *kvno, + trust_name, + attr_name, + enctypes[ei], + blob); + if (!NT_STATUS_IS_OK(status)) { + smb_krb5_free_data_contents(ctx->context, &salt); + krb5_free_principal(ctx->context, salt_princ); + return status; + } + } + + smb_krb5_free_data_contents(ctx->context, &salt); + krb5_free_principal(ctx->context, salt_princ); + } + + if (nthash != NULL) { + DATA_BLOB blob = data_blob_null; + NTSTATUS status; + + blob = data_blob_talloc(mem_ctx, nthash->hash, sizeof(nthash->hash)); + + status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, + *kvno, + trust_name, + attr_name, + ENCTYPE_ARCFOUR_HMAC, + blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + return NT_STATUS_OK; -- Samba Shared Repository