#else
krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
krb5_context context,
- int flags,
+ int kdc_flags,
krb5_db_entry *client,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
{
TALLOC_CTX *tmp_ctx = NULL;
krb5_error_code code;
- NTSTATUS nt_status;
- DATA_BLOB *pac_blob = NULL;
- DATA_BLOB *upn_blob = NULL;
- DATA_BLOB *requester_sid_blob = NULL;
struct samba_kdc_entry *client_skdc_entry = NULL;
struct samba_kdc_entry *server_skdc_entry = NULL;
struct samba_kdc_entry *krbtgt_skdc_entry = NULL;
bool is_in_db = false;
bool is_untrusted = false;
- bool is_krbtgt = false;
- size_t num_types = 0;
- uint32_t *types = NULL;
- 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;
+ uint32_t flags = SAMBA_KDC_FLAG_SKIP_PAC_BUFFER;
/* Create a memory context early so code can use talloc_stackframe() */
tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac context");
client_skdc_entry =
talloc_get_type_abort(client->e_data,
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.
- */
- code = samba_kdc_validate_pac_blob(context,
- client_skdc_entry,
- old_pac);
- if (code != 0) {
- goto done;
- }
}
if (krbtgt == NULL) {
talloc_get_type_abort(krbtgt->e_data,
struct samba_kdc_entry);
+ server_skdc_entry =
+ talloc_get_type_abort(server->e_data,
+ struct samba_kdc_entry);
+
/*
* If the krbtgt was generated by an RODC, and we are not that
* RODC, then we need to regenerate the PAC - we can't trust
}
if (is_untrusted) {
- struct auth_user_info_dc *user_info_dc = NULL;
- WERROR werr;
-
- if (client == NULL) {
- code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
- goto done;
- }
-
- nt_status = samba_kdc_get_pac_blobs(tmp_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)) {
- code = KRB5KDC_ERR_TGT_REVOKED;
- goto done;
- }
-
- /*
- * 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)) {
- code = KRB5KDC_ERR_TGT_REVOKED;
- if (W_ERROR_EQUAL(werr,
- WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
- code = KRB5KDC_ERR_POLICY;
- }
- goto done;
- }
- } else {
- pac_blob = talloc_zero(tmp_ctx, DATA_BLOB);
- if (pac_blob == NULL) {
- code = ENOMEM;
- goto done;
- }
-
- nt_status = samba_kdc_update_pac_blob(tmp_ctx,
- context,
- krbtgt_skdc_entry->kdc_db_ctx->samdb,
- old_pac,
- pac_blob,
- NULL,
- NULL);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(0, ("Update PAC blob failed: %s\n",
- nt_errstr(nt_status)));
- code = EINVAL;
- goto done;
- }
- }
-
- /* Check the types of the given PAC */
- code = krb5_pac_get_types(context, old_pac, &num_types, &types);
- if (code != 0) {
- goto done;
- }
-
- for (i = 0; i < num_types; i++) {
- switch (types[i]) {
- case PAC_TYPE_LOGON_INFO:
- if (logon_info_idx != -1) {
- DBG_WARNING("logon info type[%u] twice [%zd] and "
- "[%zu]: \n",
- types[i],
- logon_info_idx,
- i);
- code = EINVAL;
- goto done;
- }
- logon_info_idx = i;
- break;
- case PAC_TYPE_CONSTRAINED_DELEGATION:
- if (delegation_idx != -1) {
- DBG_WARNING("constrained delegation type[%u] "
- "twice [%zd] and [%zu]: \n",
- types[i],
- delegation_idx,
- i);
- code = EINVAL;
- goto done;
- }
- delegation_idx = i;
- break;
- case PAC_TYPE_LOGON_NAME:
- if (logon_name_idx != -1) {
- DBG_WARNING("logon name type[%u] twice [%zd] "
- "and [%zu]: \n",
- types[i],
- logon_name_idx,
- i);
- code = EINVAL;
- goto done;
- }
- logon_name_idx = i;
- break;
- case PAC_TYPE_UPN_DNS_INFO:
- if (upn_dns_info_idx != -1) {
- DBG_WARNING("upn dns info type[%u] twice [%zd] "
- "and [%zu]: \n",
- types[i],
- upn_dns_info_idx,
- i);
- code = EINVAL;
- goto done;
- }
- upn_dns_info_idx = i;
- break;
- case PAC_TYPE_SRV_CHECKSUM:
- if (srv_checksum_idx != -1) {
- DBG_WARNING("srv checksum type[%u] twice [%zd] "
- "and [%zu]: \n",
- types[i],
- srv_checksum_idx,
- i);
- code = EINVAL;
- goto done;
- }
- srv_checksum_idx = i;
- break;
- case PAC_TYPE_KDC_CHECKSUM:
- if (kdc_checksum_idx != -1) {
- DBG_WARNING("kdc checksum type[%u] twice [%zd] "
- "and [%zu]: \n",
- types[i],
- kdc_checksum_idx,
- i);
- code = EINVAL;
- goto done;
- }
- kdc_checksum_idx = i;
- break;
- case PAC_TYPE_TICKET_CHECKSUM:
- if (tkt_checksum_idx != -1) {
- DBG_WARNING("ticket checksum type[%u] twice "
- "[%zd] and [%zu]: \n",
- types[i],
- tkt_checksum_idx,
- i);
- code = EINVAL;
- goto done;
- }
- tkt_checksum_idx = i;
- break;
- case PAC_TYPE_ATTRIBUTES_INFO:
- if (attrs_info_idx != -1) {
- DBG_WARNING("attributes info type[%u] twice "
- "[%zd] and [%zu]: \n",
- types[i],
- attrs_info_idx,
- i);
- code = EINVAL;
- goto done;
- }
- attrs_info_idx = i;
- break;
- case PAC_TYPE_REQUESTER_SID:
- if (requester_sid_idx != -1) {
- DBG_WARNING("requester sid type[%u] twice"
- "[%zd] and [%zu]: \n",
- types[i],
- requester_sid_idx,
- i);
- code = EINVAL;
- goto done;
- }
- requester_sid_idx = i;
- break;
- default:
- continue;
- }
- }
-
- if (logon_info_idx == -1) {
- DBG_WARNING("PAC_TYPE_LOGON_INFO missing\n");
- code = EINVAL;
- goto done;
- }
- if (logon_name_idx == -1) {
- DBG_WARNING("PAC_TYPE_LOGON_NAME missing\n");
- code = EINVAL;
- goto done;
- }
- if (srv_checksum_idx == -1) {
- DBG_WARNING("PAC_TYPE_SRV_CHECKSUM missing\n");
- code = EINVAL;
- goto done;
- }
- if (kdc_checksum_idx == -1) {
- DBG_WARNING("PAC_TYPE_KDC_CHECKSUM missing\n");
- code = EINVAL;
- goto done;
- }
- if (!(flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) &&
- requester_sid_idx == -1) {
- DBG_WARNING("PAC_TYPE_REQUESTER_SID missing\n");
- code = KRB5KDC_ERR_TGT_REVOKED;
- goto done;
+ flags |= SAMBA_KDC_FLAG_KRBTGT_IS_UNTRUSTED;
}
- server_skdc_entry = talloc_get_type_abort(server->e_data,
- struct samba_kdc_entry);
+ if (is_in_db) {
+ flags |= SAMBA_KDC_FLAG_KRBTGT_IN_DB;
- /*
- * 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)) {
- code = 0;
- goto done;
}
- is_krbtgt = ks_is_tgs_principal(ctx, server->princ);
-
- if (!is_untrusted && !is_krbtgt) {
- /*
- * The client may have requested no PAC when obtaining the
- * TGT.
- */
- bool requested_pac = false;
-
- code = samba_client_requested_pac(context,
- &old_pac,
- tmp_ctx,
- &requested_pac);
- if (code != 0 || !requested_pac) {
- goto done;
- }
+ if (kdc_flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
+ flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
}
-#define MAX_PAC_BUFFERS 64 /* Avoid infinite loops */
-
- for (i = 0; i < MAX_PAC_BUFFERS;) {
- krb5_data type_data;
- DATA_BLOB type_blob = data_blob_null;
- uint32_t type;
-
- if (i < num_types) {
- type = types[i];
- i++;
- } else {
- break;
- }
-
- switch (type) {
- case PAC_TYPE_LOGON_INFO:
- type_blob = *pac_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
- */
- continue;
- 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 is generated in the main KDC code
- */
- continue;
- case PAC_TYPE_KDC_CHECKSUM:
- /*
- * This is generated in the main KDC code
- */
- continue;
- case PAC_TYPE_TICKET_CHECKSUM:
- /*
- * This is generated in the main KDC code
- */
- continue;
- case PAC_TYPE_CONSTRAINED_DELEGATION:
+ code = samba_kdc_update_pac(tmp_ctx,
+ context,
+ krbtgt_skdc_entry->kdc_db_ctx->samdb,
+ flags,
+ client_skdc_entry,
+ server->princ,
+ server_skdc_entry,
+ krbtgt_skdc_entry,
+ NULL,
+ old_pac,
+ new_pac);
+ if (code != 0) {
+ if (code == ENODATA) {
/*
- * This is generated in the main KDC code
+ * We can't tell the KDC to not issue a PAC. It will
+ * just return the newly allocated empty PAC.
*/
- continue;
- 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) {
- code = smb_krb5_copy_data_contents(&type_data,
- type_blob.data,
- type_blob.length);
- if (code != 0) {
- goto done;
- }
- } else {
- code = krb5_pac_get_buffer(context,
- old_pac,
- type,
- &type_data);
- if (code != 0) {
- goto done;
- }
- }
-
- code = krb5_pac_add_buffer(context,
- new_pac,
- type,
- &type_data);
- smb_krb5_free_data_contents(context, &type_data);
- if (code != 0) {
- goto done;
+ code = 0;
}
}
done:
- SAFE_FREE(types);
talloc_free(tmp_ctx);
return code;
}