]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:kdc: Use samba_kdc_update_pac() in mit_samba_update_pac()
authorAndreas Schneider <asn@samba.org>
Tue, 8 Mar 2022 06:34:16 +0000 (07:34 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 17 Mar 2022 00:41:34 +0000 (00:41 +0000)
This is for MIT Kerberos >= 1.20.

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/mit_samba.c

index e0121585ed4e7ef76c7440b549c19a44d7539406..5405eb3d74786703cb7c71263f21903bcc39b207 100644 (file)
@@ -644,7 +644,7 @@ done:
 #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,
@@ -653,28 +653,12 @@ krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
 {
        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");
@@ -686,17 +670,6 @@ krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
                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) {
@@ -707,6 +680,10 @@ krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
                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
@@ -724,367 +701,40 @@ krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
        }
 
        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;
 }