]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:kdc: Use samba_kdc_update_pac() in Heimdal DB plugin
authorAndreas Schneider <asn@samba.org>
Mon, 7 Mar 2022 09:41:41 +0000 (10:41 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 17 Mar 2022 00:41:34 +0000 (00:41 +0000)
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
source4/kdc/wdc-samba4.c

index 05bbb864cdd61b24bdf17190022c31955246841e..d1a9a0967090d28d028853e5d29c4fc12964ebe5 100644 (file)
@@ -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;
 }