From: Andreas Schneider Date: Mon, 7 Mar 2022 09:41:41 +0000 (+0100) Subject: s4:kdc: Use samba_kdc_update_pac() in Heimdal DB plugin X-Git-Tag: tevent-0.12.0~424 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c4ecb66715caec7cb900f6bdf6b7ad749c4ef037;p=thirdparty%2Fsamba.git s4:kdc: Use samba_kdc_update_pac() in Heimdal DB plugin Signed-off-by: Andreas Schneider Reviewed-by: Andrew Bartlett Reviewed-by: Joseph Sutton --- diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 05bbb864cdd..d1a9a096709 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -120,57 +120,26 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, krb5_pac *pac, krb5_cksumtype ctype) { + struct samba_kdc_entry *client_skdc_entry = NULL; struct samba_kdc_entry *server_skdc_entry = - talloc_get_type_abort(server->context, - struct samba_kdc_entry); + talloc_get_type_abort(server->context, struct samba_kdc_entry); struct samba_kdc_entry *krbtgt_skdc_entry = - talloc_get_type_abort(krbtgt->context, - struct samba_kdc_entry); - TALLOC_CTX *mem_ctx = talloc_named(server_skdc_entry, - 0, - "samba_kdc_reget_pac2 context"); + talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry); + TALLOC_CTX *mem_ctx = NULL; krb5_pac new_pac = NULL; - DATA_BLOB *pac_blob = NULL; - DATA_BLOB *upn_blob = NULL; - DATA_BLOB *requester_sid_blob = NULL; - DATA_BLOB *deleg_blob = NULL; krb5_error_code ret; - NTSTATUS nt_status; - bool is_in_db, is_untrusted; - bool is_krbtgt; - size_t num_types = 0; - uint32_t *types = NULL; - uint32_t forced_next_type = 0; - size_t i = 0; - ssize_t logon_info_idx = -1; - ssize_t delegation_idx = -1; - ssize_t logon_name_idx = -1; - ssize_t upn_dns_info_idx = -1; - ssize_t srv_checksum_idx = -1; - ssize_t kdc_checksum_idx = -1; - ssize_t tkt_checksum_idx = -1; - ssize_t attrs_info_idx = -1; - ssize_t requester_sid_idx = -1; + bool is_in_db = false; + bool is_untrusted = false; + uint32_t flags = 0; - if (!mem_ctx) { + mem_ctx = talloc_named(NULL, 0, "samba_kdc_reget_pac2 context"); + if (mem_ctx == NULL) { return ENOMEM; } if (client != NULL) { - struct samba_kdc_entry *client_skdc_entry = NULL; - client_skdc_entry = talloc_get_type_abort(client->context, struct samba_kdc_entry); - - /* - * Check the objectSID of the client and pac data are the same. - * Does a parse and SID check, but no crypto. - */ - ret = samba_kdc_validate_pac_blob(context, client_skdc_entry, *pac); - if (ret != 0) { - talloc_free(mem_ctx); - return ret; - } } /* @@ -184,8 +153,7 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, */ ret = samba_krbtgt_is_in_db(krbtgt_skdc_entry, &is_in_db, &is_untrusted); if (ret != 0) { - talloc_free(mem_ctx); - return ret; + goto out; } if (delegated_proxy_principal != NULL) { @@ -200,8 +168,8 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, * server we got the ticket from. We must not proceed as * otherwise the ticket signature is unchecked. */ - talloc_free(mem_ctx); - return HDB_ERR_NOT_FOUND_HERE; + ret = HDB_ERR_NOT_FOUND_HERE; + goto out; } /* Fetch the correct key depending on the checksum type. */ @@ -212,14 +180,12 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, ctype, &etype); if (ret != 0) { - talloc_free(mem_ctx); - return ret; + goto out; } } ret = hdb_enctype2key(context, krbtgt, NULL, etype, &key); if (ret != 0) { - talloc_free(mem_ctx); - return ret; + goto out; } /* Check the KDC and ticket signatures. */ @@ -231,433 +197,52 @@ static krb5_error_code samba_wdc_reget_pac2(krb5_context context, &key->key); if (ret != 0) { DEBUG(1, ("PAC KDC signature failed to verify\n")); - talloc_free(mem_ctx); - return ret; - } - - deleg_blob = talloc_zero(mem_ctx, DATA_BLOB); - if (!deleg_blob) { - talloc_free(mem_ctx); - return ENOMEM; + goto out; } - nt_status = samba_kdc_update_delegation_info_blob(mem_ctx, - context, *pac, - server->principal, - delegated_proxy_principal, - deleg_blob); - if (!NT_STATUS_IS_OK(nt_status)) { - DBG_ERR("samba_kdc_update_delegation_info_blob() failed: %s\n", - nt_errstr(nt_status)); - talloc_free(mem_ctx); - return EINVAL; - } + flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION; } if (is_untrusted) { - struct samba_kdc_entry *client_skdc_entry = NULL; - struct auth_user_info_dc *user_info_dc = NULL; - WERROR werr; - - if (client == NULL) { - return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; - } - - client_skdc_entry = talloc_get_type_abort(client->context, - struct samba_kdc_entry); - - nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry, - &pac_blob, NULL, &upn_blob, - NULL, PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY, - &requester_sid_blob, - &user_info_dc); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(mem_ctx); - DBG_ERR("samba_kdc_get_pac_blobs() failed: %s\n", - nt_errstr(nt_status)); - return KRB5KDC_ERR_TGT_REVOKED; - } - - /* - * Now check if the SID list in the user_info_dc - * intersects correctly with the RODC allow/deny - * lists - */ - - werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids, - user_info_dc->sids, - krbtgt_skdc_entry, - client_skdc_entry); - if (!W_ERROR_IS_OK(werr)) { - talloc_free(mem_ctx); - if (W_ERROR_EQUAL(werr, WERR_DOMAIN_CONTROLLER_NOT_FOUND)) { - return KRB5KDC_ERR_POLICY; - } else { - return KRB5KDC_ERR_TGT_REVOKED; - } - } + flags |= SAMBA_KDC_FLAG_KRBTGT_IS_UNTRUSTED; } - if (!is_untrusted) { - pac_blob = talloc_zero(mem_ctx, DATA_BLOB); - if (!pac_blob) { - talloc_free(mem_ctx); - return ENOMEM; - } - - nt_status = samba_kdc_update_pac_blob(mem_ctx, context, - krbtgt_skdc_entry->kdc_db_ctx->samdb, - *pac, pac_blob, - NULL, NULL); - if (!NT_STATUS_IS_OK(nt_status)) { - DBG_ERR("samba_kdc_update_pac_blob() failed: %s\n", - nt_errstr(nt_status)); - talloc_free(mem_ctx); - return EINVAL; - } - } - - /* Check the types of the given PAC */ - ret = krb5_pac_get_types(context, *pac, &num_types, &types); - if (ret != 0) { - talloc_free(mem_ctx); - return ret; - } - - for (i = 0; i < num_types; i++) { - switch (types[i]) { - case PAC_TYPE_LOGON_INFO: - if (logon_info_idx != -1) { - DEBUG(1, ("logon info type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - logon_info_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - logon_info_idx = i; - break; - case PAC_TYPE_CONSTRAINED_DELEGATION: - if (delegation_idx != -1) { - DEBUG(1, ("constrained delegation type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - delegation_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - delegation_idx = i; - break; - case PAC_TYPE_LOGON_NAME: - if (logon_name_idx != -1) { - DEBUG(1, ("logon name type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - logon_name_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - logon_name_idx = i; - break; - case PAC_TYPE_UPN_DNS_INFO: - if (upn_dns_info_idx != -1) { - DEBUG(1, ("upn dns info type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - upn_dns_info_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - upn_dns_info_idx = i; - break; - case PAC_TYPE_SRV_CHECKSUM: - if (srv_checksum_idx != -1) { - DEBUG(1, ("server checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - srv_checksum_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - srv_checksum_idx = i; - break; - case PAC_TYPE_KDC_CHECKSUM: - if (kdc_checksum_idx != -1) { - DEBUG(1, ("kdc checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - kdc_checksum_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - kdc_checksum_idx = i; - break; - case PAC_TYPE_TICKET_CHECKSUM: - if (tkt_checksum_idx != -1) { - DEBUG(1, ("ticket checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - tkt_checksum_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - tkt_checksum_idx = i; - break; - case PAC_TYPE_ATTRIBUTES_INFO: - if (attrs_info_idx != -1) { - DEBUG(1, ("attributes info type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - attrs_info_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - attrs_info_idx = i; - break; - case PAC_TYPE_REQUESTER_SID: - if (requester_sid_idx != -1) { - DEBUG(1, ("requester sid type[%"PRIu32"] twice [%zd] and [%zu]: \n", - types[i], - requester_sid_idx, - i)); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - requester_sid_idx = i; - break; - default: - continue; - } + if (is_in_db) { + flags |= SAMBA_KDC_FLAG_KRBTGT_IN_DB; } - if (logon_info_idx == -1) { - DEBUG(1, ("PAC_TYPE_LOGON_INFO missing\n")); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - if (logon_name_idx == -1) { - DEBUG(1, ("PAC_TYPE_LOGON_NAME missing\n")); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - if (srv_checksum_idx == -1) { - DEBUG(1, ("PAC_TYPE_SRV_CHECKSUM missing\n")); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - if (kdc_checksum_idx == -1) { - DEBUG(1, ("PAC_TYPE_KDC_CHECKSUM missing\n")); - SAFE_FREE(types); - talloc_free(mem_ctx); - return EINVAL; - } - if (delegated_proxy_principal == NULL && requester_sid_idx == -1) { - DEBUG(1, ("PAC_TYPE_REQUESTER_SID missing\n")); - SAFE_FREE(types); - talloc_free(mem_ctx); - return KRB5KDC_ERR_TGT_REVOKED; - } - - /* - * The server account may be set not to want the PAC. - * - * While this is wasteful if the above cacluations were done - * and now thrown away, this is cleaner as we do any ticket - * signature checking etc always. - * - * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the - * time (eg not accepting a ticket from the RODC) we do not - * need to re-generate anything anyway. - */ - if (!samba_princ_needs_pac(server_skdc_entry)) { - ret = 0; - new_pac = NULL; - goto out; - } - - is_krbtgt = krb5_principal_is_krbtgt(context, server->principal); - - if (!is_untrusted && !is_krbtgt) { - /* - * The client may have requested no PAC when obtaining the - * TGT. - */ - bool requested_pac; - ret = samba_client_requested_pac(context, pac, mem_ctx, - &requested_pac); - if (ret != 0 || !requested_pac) { - new_pac = NULL; - goto out; - } - } - - /* Otherwise build an updated PAC */ ret = krb5_pac_init(context, &new_pac); if (ret != 0) { new_pac = NULL; goto out; } - for (i = 0;;) { - const uint8_t zero_byte = 0; - krb5_data type_data; - DATA_BLOB type_blob = data_blob_null; - uint32_t type; - - if (forced_next_type != 0) { - /* - * We need to inject possible missing types - */ - type = forced_next_type; - forced_next_type = 0; - } else if (i < num_types) { - type = types[i]; - i++; - } else { - break; - } - - switch (type) { - case PAC_TYPE_LOGON_INFO: - type_blob = *pac_blob; - - if (delegation_idx == -1 && deleg_blob != NULL) { - /* inject CONSTRAINED_DELEGATION behind */ - forced_next_type = PAC_TYPE_CONSTRAINED_DELEGATION; - } - break; - case PAC_TYPE_CONSTRAINED_DELEGATION: - if (deleg_blob != NULL) { - type_blob = *deleg_blob; - } - break; - case PAC_TYPE_CREDENTIAL_INFO: - /* - * Note that we copy the credential blob, - * as it's only usable with the PKINIT based - * AS-REP reply key, it's only available on the - * host which did the AS-REQ/AS-REP exchange. - * - * This matches Windows 2008R2... - */ - break; - case PAC_TYPE_LOGON_NAME: - /* - * this is generated in the main KDC code - * we just add a place holder here. - */ - type_blob = data_blob_const(&zero_byte, 1); - - if (upn_dns_info_idx == -1 && upn_blob != NULL) { - /* inject UPN_DNS_INFO behind */ - forced_next_type = PAC_TYPE_UPN_DNS_INFO; - } - break; - case PAC_TYPE_UPN_DNS_INFO: - /* - * Replace in the RODC case, otherwise - * upn_blob is NULL and we just copy. - */ - if (upn_blob != NULL) { - type_blob = *upn_blob; - } - break; - case PAC_TYPE_SRV_CHECKSUM: - /* - * this are generated in the main KDC code - * we just add a place holder here. - */ - type_blob = data_blob_const(&zero_byte, 1); - - if (requester_sid_idx == -1 && requester_sid_blob != NULL) { - /* inject REQUESTER_SID behind */ - forced_next_type = PAC_TYPE_REQUESTER_SID; - } - break; - case PAC_TYPE_KDC_CHECKSUM: - /* - * this are generated in the main KDC code - * we just add a place holders here. - */ - type_blob = data_blob_const(&zero_byte, 1); - break; - case PAC_TYPE_ATTRIBUTES_INFO: - if (!is_untrusted && is_krbtgt) { - /* just copy... */ - break; - } else { - continue; - } - case PAC_TYPE_REQUESTER_SID: - if (is_krbtgt) { - /* - * Replace in the RODC case, otherwise - * requester_sid_blob is NULL and we just copy. - */ - if (requester_sid_blob != NULL) { - type_blob = *requester_sid_blob; - } - break; - } else { - continue; - } - default: - /* just copy... */ - break; - } - - if (type_blob.length != 0) { - ret = smb_krb5_copy_data_contents(&type_data, - type_blob.data, - type_blob.length); - if (ret != 0) { - SAFE_FREE(types); - krb5_pac_free(context, new_pac); - talloc_free(mem_ctx); - return ret; - } - } else { - ret = krb5_pac_get_buffer(context, *pac, - type, &type_data); - if (ret != 0) { - SAFE_FREE(types); - krb5_pac_free(context, new_pac); - talloc_free(mem_ctx); - return ret; - } - } - - ret = krb5_pac_add_buffer(context, new_pac, - type, &type_data); - smb_krb5_free_data_contents(context, &type_data); - if (ret != 0) { - SAFE_FREE(types); - krb5_pac_free(context, new_pac); - talloc_free(mem_ctx); - return ret; + ret = samba_kdc_update_pac(mem_ctx, + context, + krbtgt_skdc_entry->kdc_db_ctx->samdb, + flags, + client_skdc_entry, + server->principal, + server_skdc_entry, + krbtgt_skdc_entry, + delegated_proxy_principal, + *pac, + new_pac); + if (ret != 0) { + krb5_pac_free(context, new_pac); + if (ret == ENODATA) { + krb5_pac_free(context, *pac); + *pac = NULL; + ret = 0; } + goto out; } -out: - - SAFE_FREE(types); - - /* We now replace the pac */ + /* Replace the pac */ krb5_pac_free(context, *pac); *pac = new_pac; +out: talloc_free(mem_ctx); return ret; }