#include "librpc/gen_ndr/ndr_irpc_c.h"
#include "lib/messaging/irpc.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_KERBEROS
+
#undef strcasecmp
#undef strncasecmp
/*
* Make sure we'll never reveal DES keys
*/
- uint32_t supported_enctypes = p->supported_enctypes & ENC_ALL_TYPES;
+ uint32_t supported_enctypes = p->supported_enctypes &= ~(ENC_CRC32 | ENC_RSA_MD5);
uint32_t _available_enctypes = 0;
uint32_t *available_enctypes = p->available_enctypes;
uint32_t _returned_kvno = 0;
supported_enctypes,
&entry->keys);
- *supported_enctypes_out = supported_enctypes;
+ *supported_enctypes_out = supported_enctypes & ENC_ALL_TYPES;
goto out;
}
*supported_enctypes_out |= available_enctypes;
- /* Set FAST support bits */
- *supported_enctypes_out |= supported_enctypes & (ENC_FAST_SUPPORTED |
- ENC_COMPOUND_IDENTITY_SUPPORTED |
- ENC_CLAIMS_SUPPORTED);
-
if (is_krbtgt) {
/*
* Even for the main krbtgt account
bool do_strcasecmp)
{
const char *p;
- size_t len;
#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
p = krb5_principal_get_comp_string(context, principal, component);
if (p == NULL) {
return -1;
}
- len = strlen(p);
+ if (do_strcasecmp) {
+ return strcasecmp(p, string);
+ } else {
+ return strcmp(p, string);
+ }
#else
+ size_t len;
krb5_data *d;
if (component >= krb5_princ_size(context, principal)) {
return -1;
}
p = d->data;
- len = d->length;
-#endif
+
+ len = strlen(string);
+
+ /*
+ * We explicitly return -1 or 1. Subtracting of the two lengths might
+ * give the wrong result if the result overflows or loses data when
+ * narrowed to int.
+ */
+ if (d->length < len) {
+ return -1;
+ } else if (d->length > len) {
+ return 1;
+ }
+
if (do_strcasecmp) {
return strncasecmp(p, string, len);
} else {
- return strncmp(p, string, len);
+ return memcmp(p, string, len);
}
+#endif
}
static int principal_comp_strcasecmp(krb5_context context,
component, string, false);
}
+static bool is_kadmin_changepw(krb5_context context,
+ krb5_const_principal principal)
+{
+ return krb5_princ_size(context, principal) == 2 &&
+ (principal_comp_strcmp(context, principal, 0, "kadmin") == 0) &&
+ (principal_comp_strcmp(context, principal, 1, "changepw") == 0);
+}
+
+static krb5_error_code samba_kdc_get_entry_principal(
+ krb5_context context,
+ struct samba_kdc_db_context *kdc_db_ctx,
+ const char *samAccountName,
+ enum samba_kdc_ent_type ent_type,
+ unsigned flags,
+ bool is_kadmin_changepw,
+ krb5_const_principal in_princ,
+ krb5_principal *out_princ)
+{
+ struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
+ krb5_error_code code = 0;
+ bool canon = flags & (SDB_F_CANON|SDB_F_FORCE_CANON);
+
+ /*
+ * If we are set to canonicalize, we get back the fixed UPPER
+ * case realm, and the real username (ie matching LDAP
+ * samAccountName)
+ *
+ * Otherwise, if we are set to enterprise, we
+ * get back the whole principal as-sent
+ *
+ * Finally, if we are not set to canonicalize, we get back the
+ * fixed UPPER case realm, but the as-sent username
+ */
+
+ /*
+ * We need to ensure that the kadmin/changepw principal isn't able to
+ * issue krbtgt tickets, even if canonicalization is turned on.
+ */
+ if (!is_kadmin_changepw) {
+ if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT && canon) {
+ /*
+ * When requested to do so, ensure that the
+ * both realm values in the principal are set
+ * to the upper case, canonical realm
+ */
+ code = smb_krb5_make_principal(context,
+ out_princ,
+ lpcfg_realm(lp_ctx),
+ "krbtgt",
+ lpcfg_realm(lp_ctx),
+ NULL);
+ if (code != 0) {
+ return code;
+ }
+ smb_krb5_principal_set_type(context,
+ *out_princ,
+ KRB5_NT_SRV_INST);
+
+ return 0;
+ }
+
+ if ((canon && flags & (SDB_F_FORCE_CANON|SDB_F_FOR_AS_REQ)) ||
+ (ent_type == SAMBA_KDC_ENT_TYPE_ANY && in_princ == NULL)) {
+ /*
+ * SDB_F_CANON maps from the canonicalize flag in the
+ * packet, and has a different meaning between AS-REQ
+ * and TGS-REQ. We only change the principal in the
+ * AS-REQ case.
+ *
+ * The SDB_F_FORCE_CANON if for new MIT KDC code that
+ * wants the canonical name in all lookups, and takes
+ * care to canonicalize only when appropriate.
+ */
+ code = smb_krb5_make_principal(context,
+ out_princ,
+ lpcfg_realm(lp_ctx),
+ samAccountName,
+ NULL);
+ return code;
+ }
+ }
+
+ /*
+ * For a krbtgt entry, this appears to be required regardless of the
+ * canonicalize flag from the client.
+ */
+ code = krb5_copy_principal(context, in_princ, out_princ);
+ if (code != 0) {
+ return code;
+ }
+
+ /*
+ * While we have copied the client principal, tests show that Win2k3
+ * returns the 'corrected' realm, not the client-specified realm. This
+ * code attempts to replace the client principal's realm with the one
+ * we determine from our records
+ */
+ code = smb_krb5_principal_set_realm(context,
+ *out_princ,
+ lpcfg_realm(lp_ctx));
+
+ return code;
+}
+
/*
* Construct an hdb_entry from a directory entry.
*/
uint32_t rid;
bool is_krbtgt = false;
bool is_rodc = false;
+ bool force_rc4 = lpcfg_kdc_force_enable_rc4_weak_session_keys(lp_ctx);
struct ldb_message_element *objectclasses;
struct ldb_val computer_val = data_blob_string_const("computer");
+ uint32_t config_default_supported_enctypes = lpcfg_kdc_default_domain_supported_enctypes(lp_ctx);
+ uint32_t default_supported_enctypes =
+ config_default_supported_enctypes != 0 ?
+ config_default_supported_enctypes :
+ ENC_RC4_HMAC_MD5 | ENC_HMAC_SHA1_96_AES256_SK;
uint32_t supported_enctypes
= ldb_msg_find_attr_as_uint(msg,
"msDS-SupportedEncryptionTypes",
- 0);
+ default_supported_enctypes);
+ uint32_t pa_supported_enctypes;
+ uint32_t supported_session_etypes;
+ uint32_t available_enctypes = 0;
+ /*
+ * also lagacy enctypes are announced,
+ * but effectively restricted by kdc_enctypes
+ */
+ uint32_t domain_enctypes = ENC_RC4_HMAC_MD5 | ENC_RSA_MD5 | ENC_CRC32;
+ uint32_t config_kdc_enctypes = lpcfg_kdc_supported_enctypes(lp_ctx);
+ uint32_t kdc_enctypes =
+ config_kdc_enctypes != 0 ?
+ config_kdc_enctypes :
+ ENC_ALL_TYPES;
const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
ZERO_STRUCTP(entry);
+ if (supported_enctypes == 0) {
+ supported_enctypes = default_supported_enctypes;
+ }
+
+ if (dsdb_functional_level(kdc_db_ctx->samdb) >= DS_DOMAIN_FUNCTION_2008) {
+ domain_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
+ }
+
if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
is_rodc = true;
}
userAccountControl |= msDS_User_Account_Control_Computed;
}
- /*
- * If we are set to canonicalize, we get back the fixed UPPER
- * case realm, and the real username (ie matching LDAP
- * samAccountName)
- *
- * Otherwise, if we are set to enterprise, we
- * get back the whole principal as-sent
- *
- * Finally, if we are not set to canonicalize, we get back the
- * fixed UPPER case realm, but the as-sent username
- */
-
if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
p->is_krbtgt = true;
-
- if (flags & (SDB_F_CANON|SDB_F_FORCE_CANON)) {
- /*
- * When requested to do so, ensure that the
- * both realm values in the principal are set
- * to the upper case, canonical realm
- */
- ret = smb_krb5_make_principal(context, &entry->principal,
- lpcfg_realm(lp_ctx), "krbtgt",
- lpcfg_realm(lp_ctx), NULL);
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
- smb_krb5_principal_set_type(context, entry->principal, KRB5_NT_SRV_INST);
- } else {
- ret = krb5_copy_principal(context, principal, &entry->principal);
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
- /*
- * this appears to be required regardless of
- * the canonicalize flag from the client
- */
- ret = smb_krb5_principal_set_realm(context, entry->principal, lpcfg_realm(lp_ctx));
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
- }
-
- } else if (ent_type == SAMBA_KDC_ENT_TYPE_ANY && principal == NULL) {
- ret = smb_krb5_make_principal(context, &entry->principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
- } else if ((flags & SDB_F_FORCE_CANON) ||
- ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ))) {
- /*
- * SDB_F_CANON maps from the canonicalize flag in the
- * packet, and has a different meaning between AS-REQ
- * and TGS-REQ. We only change the principal in the AS-REQ case
- *
- * The SDB_F_FORCE_CANON if for new MIT KDC code that wants
- * the canonical name in all lookups, and takes care to
- * canonicalize only when appropriate.
- */
- ret = smb_krb5_make_principal(context, &entry->principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
- } else {
- ret = krb5_copy_principal(context, principal, &entry->principal);
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
-
- /* While we have copied the client principal, tests
- * show that Win2k3 returns the 'corrected' realm, not
- * the client-specified realm. This code attempts to
- * replace the client principal's realm with the one
- * we determine from our records */
-
- /* this has to be with malloc() */
- ret = smb_krb5_principal_set_realm(context, entry->principal, lpcfg_realm(lp_ctx));
- if (ret) {
- krb5_clear_error_message(context);
- goto out;
- }
}
/* First try and figure out the flags based on the userAccountControl */
* 'change password', as otherwise we could get into
* trouble, and not enforce the password expirty.
* Instead, only do it when request is for the kpasswd service */
- if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER
- && krb5_princ_size(context, principal) == 2
- && (principal_comp_strcmp(context, principal, 0, "kadmin") == 0)
- && (principal_comp_strcmp(context, principal, 1, "changepw") == 0)
- && lpcfg_is_my_domain_or_realm(lp_ctx, realm)) {
+ if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER &&
+ is_kadmin_changepw(context, principal) &&
+ lpcfg_is_my_domain_or_realm(lp_ctx, realm)) {
entry->flags.change_pw = 1;
}
}
}
+ ret = samba_kdc_get_entry_principal(context,
+ kdc_db_ctx,
+ samAccountName,
+ ent_type,
+ flags,
+ entry->flags.change_pw,
+ principal,
+ &entry->principal);
+ if (ret != 0) {
+ krb5_clear_error_message(context);
+ goto out;
+ }
+
entry->valid_start = NULL;
entry->max_life = malloc(sizeof(*entry->max_life));
kdc_db_ctx->policy.usr_tkt_lifetime);
}
+ if (entry->flags.change_pw) {
+ /* Limit lifetime of kpasswd tickets to two minutes or less. */
+ *entry->max_life = MIN(*entry->max_life, CHANGEPW_LIFETIME);
+ }
+
entry->max_renew = malloc(sizeof(*entry->max_renew));
if (entry->max_renew == NULL) {
ret = ENOMEM;
is_krbtgt = true;
- /* KDCs (and KDCs on RODCs) use AES */
- supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
+ /*
+ * KDCs (and KDCs on RODCs)
+ * ignore msDS-SupportedEncryptionTypes completely
+ * but support all supported enctypes by the domain.
+ */
+ supported_enctypes = domain_enctypes;
enable_fast = lpcfg_kdc_enable_fast(kdc_db_ctx->lp_ctx);
if (enable_fast) {
supported_enctypes |= ENC_FAST_SUPPORTED;
}
+
+ /*
+ * Resource SID compression is enabled implicitly, unless
+ * disabled in msDS-SupportedEncryptionTypes.
+ */
+
} else if (userAccountControl & (UF_PARTIAL_SECRETS_ACCOUNT|UF_SERVER_TRUST_ACCOUNT)) {
- /* DCs and RODCs comptuer accounts use AES */
- supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
+ /*
+ * DCs and RODCs computer accounts take
+ * msDS-SupportedEncryptionTypes unmodified, but
+ * force all enctypes supported by the domain.
+ */
+ supported_enctypes |= domain_enctypes;
+
} else if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT ||
(ent_type == SAMBA_KDC_ENT_TYPE_ANY)) {
- /* for AS-REQ the client chooses the enc types it
+ /*
+ * for AS-REQ the client chooses the enc types it
* supports, and this will vary between computers a
- * user logs in from.
+ * user logs in from. Therefore, so that we accept any
+ * of the client's keys for decrypting padata,
+ * supported_enctypes should not restrict etype usage.
*
* likewise for 'any' return as much as is supported,
- * to export into a keytab */
- supported_enctypes = ENC_ALL_TYPES;
+ * to export into a keytab.
+ */
+ supported_enctypes |= ENC_ALL_TYPES;
}
/* If UF_USE_DES_KEY_ONLY has been set, then don't allow use of the newer enc types */
if (userAccountControl & UF_USE_DES_KEY_ONLY) {
- supported_enctypes = 0;
- } else {
- /* Otherwise, add in the default enc types */
- supported_enctypes |= ENC_RC4_HMAC_MD5;
+ supported_enctypes &= ~ENC_ALL_TYPES;
}
if (protected_user) {
supported_enctypes &= ~ENC_RC4_HMAC_MD5;
}
+ pa_supported_enctypes = supported_enctypes;
+ supported_session_etypes = supported_enctypes;
+ if (supported_session_etypes & ENC_HMAC_SHA1_96_AES256_SK) {
+ supported_session_etypes |= ENC_HMAC_SHA1_96_AES256;
+ supported_session_etypes |= ENC_HMAC_SHA1_96_AES128;
+ }
+ if (force_rc4) {
+ supported_session_etypes |= ENC_RC4_HMAC_MD5;
+ }
+ /*
+ * now that we remembered what to announce in pa_supported_enctypes
+ * and normalized ENC_HMAC_SHA1_96_AES256_SK, we restrict the
+ * rest to the enc types the local kdc supports.
+ */
+ supported_enctypes &= kdc_enctypes;
+ supported_session_etypes &= kdc_enctypes;
+
/* Get keys from the db */
ret = samba_kdc_message2entry_keys(context, p, msg,
is_krbtgt, is_rodc,
userAccountControl,
ent_type, flags, kvno, entry,
supported_enctypes,
- &supported_enctypes);
+ &available_enctypes);
if (ret) {
/* Could be bogus data in the entry, or out of memory */
goto out;
}
- if (entry->keys.len == 0) {
- if (kdc_db_ctx->rodc) {
+ /*
+ * If we only have a nthash stored,
+ * but a better session key would be
+ * available, we fallback to fetching the
+ * RC4_HMAC_MD5, which implicitly also
+ * would allow an RC4_HMAC_MD5 session key.
+ * But only if the kdc actually supports
+ * RC4_HMAC_MD5.
+ */
+ if (available_enctypes == 0 &&
+ (supported_enctypes & ENC_RC4_HMAC_MD5) == 0 &&
+ (supported_enctypes & ~ENC_RC4_HMAC_MD5) != 0 &&
+ (kdc_enctypes & ENC_RC4_HMAC_MD5) != 0)
+ {
+ supported_enctypes = ENC_RC4_HMAC_MD5;
+ ret = samba_kdc_message2entry_keys(context, p, msg,
+ is_krbtgt, is_rodc,
+ userAccountControl,
+ ent_type, flags, kvno, entry,
+ supported_enctypes,
+ &available_enctypes);
+ if (ret) {
+ /* Could be bogus data in the entry, or out of memory */
+ goto out;
+ }
+ }
+
+ /*
+ * We need to support all session keys enctypes for
+ * all keys we provide
+ */
+ supported_session_etypes |= available_enctypes;
+
+ ret = sdb_entry_set_etypes(entry);
+ if (ret) {
+ goto out;
+ }
+
+ if (entry->flags.server) {
+ bool add_aes256 =
+ supported_session_etypes & KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ bool add_aes128 =
+ supported_session_etypes & KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ bool add_rc4 =
+ supported_session_etypes & ENC_RC4_HMAC_MD5;
+ ret = sdb_entry_set_session_etypes(entry,
+ add_aes256,
+ add_aes128,
+ add_rc4);
+ if (ret) {
+ goto out;
+ }
+ }
+
+ if (entry->keys.len != 0) {
+ /*
+ * FIXME: Currently limited to Heimdal so as not to
+ * break MIT KDCs, for which no fix is available.
+ */
+#ifdef SAMBA4_USES_HEIMDAL
+ if (is_krbtgt) {
/*
- * We are on an RODC, but don't have keys for this
- * account. Signal this to the caller
+ * The krbtgt account, having no reason to
+ * issue tickets encrypted in weaker keys,
+ * shall only make available its strongest
+ * key. All weaker keys are stripped out. This
+ * makes it impossible for an RC4-encrypted
+ * TGT to be accepted when AES KDC keys exist.
+ *
+ * This controls the ticket key and so the PAC
+ * signature algorithms indirectly, preventing
+ * a weak KDC checksum from being accepted
+ * when we verify the signatures for an
+ * S4U2Proxy evidence ticket. As such, this is
+ * indispensable for addressing
+ * CVE-2022-37966.
+ *
+ * Being strict here also provides protection
+ * against possible future attacks on weak
+ * keys.
*/
- auth_sam_trigger_repl_secret(kdc_db_ctx,
- kdc_db_ctx->msg_ctx,
- kdc_db_ctx->ev_ctx,
- msg->dn);
- return SDB_ERR_NOT_FOUND_HERE;
+ entry->keys.len = 1;
+ if (entry->etypes != NULL) {
+ entry->etypes->len = 1;
+ }
+ entry->old_keys.len = MIN(entry->old_keys.len, 1);
+ entry->older_keys.len = MIN(entry->older_keys.len, 1);
}
-
+#endif
+ } else if (kdc_db_ctx->rodc) {
+ /*
+ * We are on an RODC, but don't have keys for this
+ * account. Signal this to the caller
+ */
+ auth_sam_trigger_repl_secret(kdc_db_ctx,
+ kdc_db_ctx->msg_ctx,
+ kdc_db_ctx->ev_ctx,
+ msg->dn);
+ return SDB_ERR_NOT_FOUND_HERE;
+ } else {
/*
* oh, no password. Apparently (comment in
* hdb-ldap.c) this violates the ASN.1, but this
}
p->msg = talloc_steal(p, msg);
- p->supported_enctypes = supported_enctypes;
+ p->supported_enctypes = pa_supported_enctypes;
out:
if (ret != 0) {
NTTIME an_hour_ago;
uint32_t *auth_kvno;
bool preferr_current = false;
+ bool force_rc4 = lpcfg_kdc_force_enable_rc4_weak_session_keys(lp_ctx);
uint32_t supported_enctypes = ENC_RC4_HMAC_MD5;
+ uint32_t pa_supported_enctypes;
+ uint32_t supported_session_etypes;
+ uint32_t config_kdc_enctypes = lpcfg_kdc_supported_enctypes(lp_ctx);
+ uint32_t kdc_enctypes =
+ config_kdc_enctypes != 0 ?
+ config_kdc_enctypes :
+ ENC_ALL_TYPES;
struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
NTSTATUS status;
ZERO_STRUCTP(entry);
if (dsdb_functional_level(kdc_db_ctx->samdb) >= DS_DOMAIN_FUNCTION_2008) {
+ /* If not told otherwise, Windows now assumes that trusts support AES. */
supported_enctypes = ldb_msg_find_attr_as_uint(msg,
"msDS-SupportedEncryptionTypes",
- supported_enctypes);
+ ENC_HMAC_SHA1_96_AES256);
}
+ pa_supported_enctypes = supported_enctypes;
+ supported_session_etypes = supported_enctypes;
+ if (supported_session_etypes & ENC_HMAC_SHA1_96_AES256_SK) {
+ supported_session_etypes |= ENC_HMAC_SHA1_96_AES256;
+ supported_session_etypes |= ENC_HMAC_SHA1_96_AES128;
+ }
+ if (force_rc4) {
+ supported_session_etypes |= ENC_RC4_HMAC_MD5;
+ }
+ /*
+ * now that we remembered what to announce in pa_supported_enctypes
+ * and normalized ENC_HMAC_SHA1_96_AES256_SK, we restrict the
+ * rest to the enc types the local kdc supports.
+ */
+ supported_enctypes &= kdc_enctypes;
+ supported_session_etypes &= kdc_enctypes;
+
status = dsdb_trust_parse_tdo_info(mem_ctx, msg, &tdo);
if (!NT_STATUS_IS_OK(status)) {
krb5_clear_error_message(context);
p->is_trust = true;
p->kdc_db_ctx = kdc_db_ctx;
p->realm_dn = realm_dn;
- p->supported_enctypes = supported_enctypes;
+ p->supported_enctypes = pa_supported_enctypes;
talloc_set_destructor(p, samba_kdc_entry_destructor);
samba_kdc_sort_keys(&entry->keys);
+ ret = sdb_entry_set_etypes(entry);
+ if (ret) {
+ goto out;
+ }
+
+ {
+ bool add_aes256 =
+ supported_session_etypes & KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ bool add_aes128 =
+ supported_session_etypes & KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ bool add_rc4 =
+ supported_session_etypes & ENC_RC4_HMAC_MD5;
+ ret = sdb_entry_set_session_etypes(entry,
+ add_aes256,
+ add_aes128,
+ add_rc4);
+ if (ret) {
+ goto out;
+ }
+ }
+
p->msg = talloc_steal(p, msg);
out:
flags, kvno,
realm_dn, msg, entry);
if (ret != 0) {
- krb5_warnx(context, "samba_kdc_fetch: message2entry failed");
+ char *client_name = NULL;
+ krb5_error_code code;
+
+ code = krb5_unparse_name(context, principal, &client_name);
+ if (code == 0) {
+ krb5_warnx(context,
+ "samba_kdc_fetch: message2entry failed for "
+ "%s",
+ client_name);
+ } else {
+ krb5_warnx(context,
+ "samba_kdc_fetch: message2entry and "
+ "krb5_unparse_name failed");
+ }
+ SAFE_FREE(client_name);
}
return ret;
struct samba_kdc_db_context *kdc_db_ctx,
krb5_const_principal client_principal,
krb5_const_principal server_principal,
- krb5_pac header_pac,
+ krb5_const_pac header_pac,
struct samba_kdc_entry *proxy_skdc_entry)
{
krb5_error_code code;
struct auth_user_info_dc *user_info_dc = NULL;
struct auth_session_info *session_info = NULL;
uint32_t session_info_flags = AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
- uint32_t access_desired = SEC_ADS_GENERIC_ALL; /* => 0x000f01ff */
+ /*
+ * Testing shows that although Windows grants SEC_ADS_GENERIC_ALL access
+ * in security descriptors it creates for RBCD, its KDC only requires
+ * SEC_ADS_CONTROL_ACCESS for the access check to succeed.
+ */
+ uint32_t access_desired = SEC_ADS_CONTROL_ACCESS;
uint32_t access_granted = 0;
NTSTATUS nt_status;
TALLOC_CTX *mem_ctx = NULL;
header_pac,
context,
&user_info_dc,
+ AUTH_INCLUDE_RESOURCE_GROUPS,
+ NULL,
NULL,
NULL);
if (code != 0) {
goto out;
}
- if (user_info_dc->info->authenticated) {
+ if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
}
data = ldb_msg_find_ldb_val(proxy_skdc_entry->msg,
"msDS-AllowedToActOnBehalfOfOtherIdentity");
if (data == NULL) {
- DBG_ERR("Could not find security descriptor"
+ DBG_ERR("Could not find security descriptor "
"msDS-AllowedToActOnBehalfOfOtherIdentity in "
"proxy[%s]\n",
proxy_dn);
*kdc_db_ctx_out = kdc_db_ctx;
return NT_STATUS_OK;
}
+
+krb5_error_code dsdb_extract_aes_256_key(krb5_context context,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg,
+ uint32_t user_account_control,
+ const uint32_t *kvno,
+ uint32_t *kvno_out,
+ DATA_BLOB *aes_256_key,
+ DATA_BLOB *salt)
+{
+ krb5_error_code krb5_ret;
+ uint32_t supported_enctypes;
+ unsigned flags = SDB_F_GET_CLIENT;
+ struct sdb_entry sentry = {};
+
+ if (kvno != NULL) {
+ flags |= SDB_F_KVNO_SPECIFIED;
+ }
+
+ krb5_ret = samba_kdc_message2entry_keys(context,
+ mem_ctx,
+ msg,
+ false, /* is_krbtgt */
+ false, /* is_rodc */
+ user_account_control,
+ SAMBA_KDC_ENT_TYPE_CLIENT,
+ flags,
+ (kvno != NULL) ? *kvno : 0,
+ &sentry,
+ ENC_HMAC_SHA1_96_AES256,
+ &supported_enctypes);
+ if (krb5_ret != 0) {
+ DBG_ERR("Failed to parse supplementalCredentials "
+ "of %s with %s kvno using "
+ "ENCTYPE_HMAC_SHA1_96_AES256 "
+ "Kerberos Key: %s\n",
+ ldb_dn_get_linearized(msg->dn),
+ (kvno != NULL) ? "previous" : "current",
+ krb5_get_error_message(context,
+ krb5_ret));
+ return krb5_ret;
+ }
+
+ if ((supported_enctypes & ENC_HMAC_SHA1_96_AES256) == 0 ||
+ sentry.keys.len != 1) {
+ DBG_INFO("Failed to find a ENCTYPE_HMAC_SHA1_96_AES256 "
+ "key in supplementalCredentials "
+ "of %s at KVNO %u (got %u keys, expected 1)\n",
+ ldb_dn_get_linearized(msg->dn),
+ sentry.kvno,
+ sentry.keys.len);
+ sdb_entry_free(&sentry);
+ return ENOENT;
+ }
+
+ if (sentry.keys.val[0].salt == NULL) {
+ DBG_INFO("Failed to find a salt in "
+ "supplementalCredentials "
+ "of %s at KVNO %u\n",
+ ldb_dn_get_linearized(msg->dn),
+ sentry.kvno);
+ sdb_entry_free(&sentry);
+ return ENOENT;
+ }
+
+ if (aes_256_key != NULL) {
+ *aes_256_key = data_blob_talloc(mem_ctx,
+ KRB5_KEY_DATA(&sentry.keys.val[0].key),
+ KRB5_KEY_LENGTH(&sentry.keys.val[0].key));
+ if (aes_256_key->data == NULL) {
+ sdb_entry_free(&sentry);
+ return ENOMEM;
+ }
+ talloc_keep_secret(aes_256_key->data);
+ }
+
+ if (salt != NULL) {
+ *salt = data_blob_talloc(mem_ctx,
+ sentry.keys.val[0].salt->salt.data,
+ sentry.keys.val[0].salt->salt.length);
+ if (salt->data == NULL) {
+ sdb_entry_free(&sentry);
+ return ENOMEM;
+ }
+ }
+
+ if (kvno_out != NULL) {
+ *kvno_out = sentry.kvno;
+ }
+
+ sdb_entry_free(&sentry);
+
+ return 0;
+}