LCOV - code coverage report
Current view: top level - source4/kdc - pac-glue.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 1003 1473 68.1 %
Date: 2024-05-31 13:13:24 Functions: 45 46 97.8 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    PAC Glue between Samba and the KDC
       5             : 
       6             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
       7             :    Copyright (C) Simo Sorce <idra@samba.org> 2010
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "lib/replace/replace.h"
      25             : #include "lib/replace/system/kerberos.h"
      26             : #include "lib/replace/system/filesys.h"
      27             : #include "lib/util/debug.h"
      28             : #include "lib/util/samba_util.h"
      29             : #include "lib/util/talloc_stack.h"
      30             : 
      31             : #include "auth/auth_sam_reply.h"
      32             : #include "auth/kerberos/kerberos.h"
      33             : #include "auth/kerberos/pac_utils.h"
      34             : #include "auth/authn_policy.h"
      35             : #include "libcli/security/security.h"
      36             : #include "libds/common/flags.h"
      37             : #include "librpc/gen_ndr/ndr_krb5pac.h"
      38             : #include "param/param.h"
      39             : #include "source4/auth/auth.h"
      40             : #include "source4/dsdb/common/util.h"
      41             : #include "source4/dsdb/samdb/samdb.h"
      42             : #include "source4/kdc/authn_policy_util.h"
      43             : #include "source4/kdc/samba_kdc.h"
      44             : #include "source4/kdc/pac-glue.h"
      45             : #include "source4/kdc/ad_claims.h"
      46             : #include "source4/kdc/pac-blobs.h"
      47             : 
      48             : #include <ldb.h>
      49             : 
      50             : #undef DBGC_CLASS
      51             : #define DBGC_CLASS DBGC_KERBEROS
      52             : 
      53             : static
      54       78964 : NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
      55             :                                        const struct auth_user_info_dc *info,
      56             :                                        const struct PAC_DOMAIN_GROUP_MEMBERSHIP *override_resource_groups,
      57             :                                        const enum auth_group_inclusion group_inclusion,
      58             :                                        DATA_BLOB *pac_data)
      59             : {
      60       78964 :         TALLOC_CTX *tmp_ctx = NULL;
      61       78964 :         struct netr_SamInfo3 *info3 = NULL;
      62       78964 :         struct PAC_DOMAIN_GROUP_MEMBERSHIP *_resource_groups = NULL;
      63       78964 :         struct PAC_DOMAIN_GROUP_MEMBERSHIP **resource_groups = NULL;
      64       78964 :         union PAC_INFO pac_info = {};
      65        2856 :         enum ndr_err_code ndr_err;
      66       78964 :         NTSTATUS nt_status = NT_STATUS_OK;
      67             : 
      68       78964 :         *pac_data = data_blob_null;
      69             : 
      70       78964 :         tmp_ctx = talloc_new(mem_ctx);
      71       78964 :         if (tmp_ctx == NULL) {
      72           0 :                 return NT_STATUS_NO_MEMORY;
      73             :         }
      74             : 
      75       78964 :         if (override_resource_groups == NULL) {
      76       76103 :                 resource_groups = &_resource_groups;
      77           5 :         } else if (group_inclusion != AUTH_EXCLUDE_RESOURCE_GROUPS) {
      78             :                 /*
      79             :                  * It doesn't make sense to override resource groups if we claim
      80             :                  * to want resource groups from user_info_dc.
      81             :                  */
      82           0 :                 DBG_ERR("supplied resource groups with invalid group inclusion parameter: %u\n",
      83             :                         group_inclusion);
      84           0 :                 nt_status = NT_STATUS_INVALID_PARAMETER;
      85           0 :                 goto out;
      86             :         }
      87             : 
      88       78964 :         nt_status = auth_convert_user_info_dc_saminfo3(tmp_ctx, info,
      89             :                                                        group_inclusion,
      90             :                                                        &info3,
      91             :                                                        resource_groups);
      92       78964 :         if (!NT_STATUS_IS_OK(nt_status)) {
      93           0 :                 DBG_WARNING("Getting Samba info failed: %s\n",
      94             :                             nt_errstr(nt_status));
      95           0 :                 goto out;
      96             :         }
      97             : 
      98       78964 :         pac_info.logon_info.info = talloc_zero(tmp_ctx, struct PAC_LOGON_INFO);
      99       78964 :         if (!pac_info.logon_info.info) {
     100           0 :                 nt_status = NT_STATUS_NO_MEMORY;
     101           0 :                 goto out;
     102             :         }
     103             : 
     104       78964 :         pac_info.logon_info.info->info3 = *info3;
     105       78964 :         if (_resource_groups != NULL) {
     106       16461 :                 pac_info.logon_info.info->resource_groups = *_resource_groups;
     107             :         }
     108             : 
     109       78964 :         if (override_resource_groups != NULL) {
     110           5 :                 pac_info.logon_info.info->resource_groups = *override_resource_groups;
     111             :         }
     112             : 
     113       78964 :         if (group_inclusion != AUTH_EXCLUDE_RESOURCE_GROUPS) {
     114             :                 /*
     115             :                  * Set the resource groups flag based on whether any groups are
     116             :                  * present. Otherwise, the flag is propagated from the
     117             :                  * originating PAC.
     118             :                  */
     119       23786 :                 if (pac_info.logon_info.info->resource_groups.groups.count > 0) {
     120       16461 :                         pac_info.logon_info.info->info3.base.user_flags |= NETLOGON_RESOURCE_GROUPS;
     121             :                 } else {
     122        7325 :                         pac_info.logon_info.info->info3.base.user_flags &= ~NETLOGON_RESOURCE_GROUPS;
     123             :                 }
     124             :         }
     125             : 
     126       78964 :         ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info,
     127             :                                       PAC_TYPE_LOGON_INFO,
     128             :                                       (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
     129       78964 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     130           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
     131           0 :                 DBG_WARNING("PAC_LOGON_INFO (presig) push failed: %s\n",
     132             :                             nt_errstr(nt_status));
     133           0 :                 goto out;
     134             :         }
     135             : 
     136       78964 : out:
     137       78964 :         talloc_free(tmp_ctx);
     138       78964 :         return nt_status;
     139             : }
     140             : 
     141             : static
     142       30423 : NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
     143             :                                      const struct auth_user_info_dc *info,
     144             :                                      DATA_BLOB *upn_data)
     145             : {
     146       30423 :         TALLOC_CTX *tmp_ctx = NULL;
     147       30423 :         union PAC_INFO pac_upn = {};
     148        1184 :         enum ndr_err_code ndr_err;
     149       30423 :         NTSTATUS nt_status = NT_STATUS_OK;
     150        1184 :         bool ok;
     151             : 
     152       30423 :         *upn_data = data_blob_null;
     153             : 
     154       30423 :         tmp_ctx = talloc_new(mem_ctx);
     155       30423 :         if (tmp_ctx == NULL) {
     156           0 :                 return NT_STATUS_NO_MEMORY;
     157             :         }
     158             : 
     159       30423 :         pac_upn.upn_dns_info.upn_name = info->info->user_principal_name;
     160       59662 :         pac_upn.upn_dns_info.dns_domain_name = strupper_talloc(tmp_ctx,
     161       29239 :                                                 info->info->dns_domain_name);
     162       30423 :         if (pac_upn.upn_dns_info.dns_domain_name == NULL) {
     163           0 :                 nt_status = NT_STATUS_NO_MEMORY;
     164           0 :                 goto out;
     165             :         }
     166       30423 :         if (info->info->user_principal_constructed) {
     167       29175 :                 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
     168             :         }
     169             : 
     170       30423 :         pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID;
     171             : 
     172        1184 :         pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname
     173       30423 :                 = info->info->account_name;
     174             : 
     175        1184 :         pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid
     176       30423 :                 = &info->sids[PRIMARY_USER_SID_INDEX].sid;
     177             : 
     178       30423 :         ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
     179             :                                       PAC_TYPE_UPN_DNS_INFO,
     180             :                                       (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
     181       30423 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     182           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
     183           0 :                 DBG_WARNING("PAC UPN_DNS_INFO (presig) push failed: %s\n",
     184             :                             nt_errstr(nt_status));
     185           0 :                 goto out;
     186             :         }
     187             : 
     188       30423 :         ok = data_blob_pad(mem_ctx, upn_data, 8);
     189       30423 :         if (!ok) {
     190           0 :                 talloc_free(upn_data);
     191           0 :                 nt_status = NT_STATUS_NO_MEMORY;
     192           0 :                 goto out;
     193             :         }
     194             : 
     195       30423 : out:
     196       30423 :         talloc_free(tmp_ctx);
     197       30423 :         return nt_status;
     198             : }
     199             : 
     200             : static
     201          45 : NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
     202             :                                       const struct ldb_message *msg,
     203             :                                       DATA_BLOB *cred_blob)
     204             : {
     205           0 :         enum ndr_err_code ndr_err;
     206           0 :         NTSTATUS nt_status;
     207          45 :         struct samr_Password *lm_hash = NULL;
     208          45 :         struct samr_Password *nt_hash = NULL;
     209          45 :         struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg = {
     210             :                 .version = 0,
     211             :         };
     212          45 :         DATA_BLOB ntlm_blob = data_blob_null;
     213          45 :         struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs[1] = {{
     214             :                 .credential_size = 0,
     215             :         }};
     216          45 :         struct PAC_CREDENTIAL_DATA cred_data = {
     217             :                 .credential_count = 0,
     218             :         };
     219          45 :         struct PAC_CREDENTIAL_DATA_NDR cred_ndr = {};
     220             : 
     221          45 :         *cred_blob = data_blob_null;
     222             : 
     223          45 :         lm_hash = samdb_result_hash(mem_ctx, msg, "dBCSPwd");
     224          45 :         if (lm_hash != NULL) {
     225           0 :                 bool zero = all_zero(lm_hash->hash, 16);
     226           0 :                 if (zero) {
     227           0 :                         lm_hash = NULL;
     228             :                 }
     229             :         }
     230          45 :         if (lm_hash != NULL) {
     231           0 :                 DBG_INFO("Passing LM password hash through credentials set\n");
     232           0 :                 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_LM_HASH;
     233           0 :                 ntlm_secpkg.lm_password = *lm_hash;
     234           0 :                 ZERO_STRUCTP(lm_hash);
     235           0 :                 TALLOC_FREE(lm_hash);
     236             :         }
     237             : 
     238          45 :         nt_hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
     239          45 :         if (nt_hash != NULL) {
     240          45 :                 bool zero = all_zero(nt_hash->hash, 16);
     241          45 :                 if (zero) {
     242           0 :                         nt_hash = NULL;
     243             :                 }
     244             :         }
     245          45 :         if (nt_hash != NULL) {
     246          45 :                 DBG_INFO("Passing NT password hash through credentials set\n");
     247          45 :                 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_NT_HASH;
     248          45 :                 ntlm_secpkg.nt_password = *nt_hash;
     249          45 :                 ZERO_STRUCTP(nt_hash);
     250          45 :                 TALLOC_FREE(nt_hash);
     251             :         }
     252             : 
     253          45 :         if (ntlm_secpkg.flags == 0) {
     254           0 :                 return NT_STATUS_OK;
     255             :         }
     256             : 
     257             : #ifdef DEBUG_PASSWORD
     258          45 :         if (DEBUGLVL(11)) {
     259           0 :                 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG, &ntlm_secpkg);
     260             :         }
     261             : #endif
     262             : 
     263          45 :         ndr_err = ndr_push_struct_blob(&ntlm_blob, mem_ctx, &ntlm_secpkg,
     264             :                         (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG);
     265          45 :         ZERO_STRUCT(ntlm_secpkg);
     266          45 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     267           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
     268           0 :                 DBG_WARNING("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
     269             :                             nt_errstr(nt_status));
     270           0 :                 return nt_status;
     271             :         }
     272             : 
     273          45 :         DBG_DEBUG("NTLM credential BLOB (len %zu) for user\n",
     274             :                   ntlm_blob.length);
     275          45 :         dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
     276          45 :                      ntlm_blob.data, ntlm_blob.length);
     277             : 
     278          45 :         secpkgs[0].package_name.string = discard_const_p(char, "NTLM");
     279          45 :         secpkgs[0].credential_size = ntlm_blob.length;
     280          45 :         secpkgs[0].credential = ntlm_blob.data;
     281             : 
     282          45 :         cred_data.credential_count = ARRAY_SIZE(secpkgs);
     283          45 :         cred_data.credentials = secpkgs;
     284             : 
     285             : #ifdef DEBUG_PASSWORD
     286          45 :         if (DEBUGLVL(11)) {
     287           0 :                 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA, &cred_data);
     288             :         }
     289             : #endif
     290             : 
     291          45 :         cred_ndr.ctr.data = &cred_data;
     292             : 
     293             : #ifdef DEBUG_PASSWORD
     294          45 :         if (DEBUGLVL(11)) {
     295           0 :                 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR, &cred_ndr);
     296             :         }
     297             : #endif
     298             : 
     299          45 :         ndr_err = ndr_push_struct_blob(cred_blob, mem_ctx, &cred_ndr,
     300             :                         (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_DATA_NDR);
     301          45 :         data_blob_clear(&ntlm_blob);
     302          45 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     303           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
     304           0 :                 DBG_WARNING("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
     305             :                             nt_errstr(nt_status));
     306           0 :                 return nt_status;
     307             :         }
     308             : 
     309          45 :         DBG_DEBUG("Created credential BLOB (len %zu) for user\n",
     310             :                   cred_blob->length);
     311          45 :         dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
     312          45 :                      cred_blob->data, cred_blob->length);
     313             : 
     314          45 :         return NT_STATUS_OK;
     315             : }
     316             : 
     317          45 : krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
     318             :                                                   const krb5_keyblock *pkreplykey,
     319             :                                                   const DATA_BLOB *cred_ndr_blob,
     320             :                                                   TALLOC_CTX *mem_ctx,
     321             :                                                   DATA_BLOB *cred_info_blob)
     322             : {
     323             : #ifdef SAMBA4_USES_HEIMDAL
     324           0 :         krb5_crypto cred_crypto;
     325           0 :         krb5_enctype cred_enctype;
     326           0 :         krb5_data cred_ndr_crypt;
     327          45 :         struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
     328           0 :         krb5_error_code ret;
     329           0 :         const char *krb5err;
     330           0 :         enum ndr_err_code ndr_err;
     331           0 :         NTSTATUS nt_status;
     332             : 
     333          45 :         *cred_info_blob = data_blob_null;
     334             : 
     335          45 :         ret = krb5_crypto_init(context, pkreplykey, ETYPE_NULL,
     336             :                                &cred_crypto);
     337          45 :         if (ret != 0) {
     338           0 :                 krb5err = krb5_get_error_message(context, ret);
     339           0 :                 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err);
     340           0 :                 krb5_free_error_message(context, krb5err);
     341           0 :                 return ret;
     342             :         }
     343             : 
     344          45 :         ret = krb5_crypto_getenctype(context, cred_crypto, &cred_enctype);
     345          45 :         if (ret != 0) {
     346           0 :                 DBG_WARNING("Failed getting crypto type for key\n");
     347           0 :                 krb5_crypto_destroy(context, cred_crypto);
     348           0 :                 return ret;
     349             :         }
     350             : 
     351          45 :         DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
     352             :                   cred_ndr_blob->length);
     353          45 :         dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
     354          45 :                      cred_ndr_blob->data, cred_ndr_blob->length);
     355             : 
     356          45 :         ret = krb5_encrypt(context, cred_crypto,
     357             :                            KRB5_KU_OTHER_ENCRYPTED,
     358          45 :                            cred_ndr_blob->data, cred_ndr_blob->length,
     359             :                            &cred_ndr_crypt);
     360          45 :         krb5_crypto_destroy(context, cred_crypto);
     361          45 :         if (ret != 0) {
     362           0 :                 krb5err = krb5_get_error_message(context, ret);
     363           0 :                 DBG_WARNING("Failed crypt of cred data: %s\n", krb5err);
     364           0 :                 krb5_free_error_message(context, krb5err);
     365           0 :                 return ret;
     366             :         }
     367             : 
     368          45 :         pac_cred_info.encryption_type = cred_enctype;
     369          45 :         pac_cred_info.encrypted_data.length = cred_ndr_crypt.length;
     370          45 :         pac_cred_info.encrypted_data.data = (uint8_t *)cred_ndr_crypt.data;
     371             : 
     372          45 :         if (DEBUGLVL(10)) {
     373           0 :                 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
     374             :         }
     375             : 
     376          45 :         ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
     377             :                         (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
     378          45 :         krb5_data_free(&cred_ndr_crypt);
     379          45 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     380           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
     381           0 :                 DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
     382             :                             nt_errstr(nt_status));
     383           0 :                 return KRB5KDC_ERR_SVC_UNAVAILABLE;
     384             :         }
     385             : 
     386          45 :         DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32"\n",
     387             :                   cred_info_blob->length, pac_cred_info.encryption_type);
     388          45 :         dump_data_pw("PAC_CREDENTIAL_INFO",
     389          45 :                       cred_info_blob->data, cred_info_blob->length);
     390             : 
     391          45 :         return 0;
     392             : #else /* SAMBA4_USES_HEIMDAL */
     393           0 :         TALLOC_CTX *tmp_ctx = NULL;
     394             :         krb5_key cred_key;
     395             :         krb5_enctype cred_enctype;
     396           0 :         struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
     397           0 :         krb5_error_code code = 0;
     398             :         const char *krb5err;
     399             :         enum ndr_err_code ndr_err;
     400             :         NTSTATUS nt_status;
     401             :         krb5_data cred_ndr_data;
     402             :         krb5_enc_data cred_ndr_crypt;
     403           0 :         size_t enc_len = 0;
     404             : 
     405           0 :         *cred_info_blob = data_blob_null;
     406             : 
     407           0 :         tmp_ctx = talloc_new(mem_ctx);
     408           0 :         if (tmp_ctx == NULL) {
     409           0 :                 return ENOMEM;
     410             :         }
     411             : 
     412           0 :         code = krb5_k_create_key(context,
     413             :                                  pkreplykey,
     414             :                                  &cred_key);
     415           0 :         if (code != 0) {
     416           0 :                 krb5err = krb5_get_error_message(context, code);
     417           0 :                 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err);
     418           0 :                 krb5_free_error_message(context, krb5err);
     419           0 :                 goto out;
     420             :         }
     421             : 
     422           0 :         cred_enctype = krb5_k_key_enctype(context, cred_key);
     423             : 
     424           0 :         DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
     425             :                   cred_ndr_blob->length);
     426           0 :         dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
     427           0 :                      cred_ndr_blob->data, cred_ndr_blob->length);
     428             : 
     429           0 :         pac_cred_info.encryption_type = cred_enctype;
     430             : 
     431           0 :         cred_ndr_data = smb_krb5_data_from_blob(*cred_ndr_blob);
     432             : 
     433           0 :         code = krb5_c_encrypt_length(context,
     434             :                                      cred_enctype,
     435           0 :                                      cred_ndr_data.length,
     436             :                                      &enc_len);
     437           0 :         if (code != 0) {
     438           0 :                 krb5err = krb5_get_error_message(context, code);
     439           0 :                 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err);
     440           0 :                 krb5_free_error_message(context, krb5err);
     441           0 :                 goto out;
     442             :         }
     443             : 
     444           0 :         pac_cred_info.encrypted_data = data_blob_talloc_zero(tmp_ctx, enc_len);
     445           0 :         if (pac_cred_info.encrypted_data.data == NULL) {
     446           0 :                 DBG_ERR("Out of memory\n");
     447           0 :                 code = ENOMEM;
     448           0 :                 goto out;
     449             :         }
     450             : 
     451           0 :         cred_ndr_crypt.ciphertext = smb_krb5_data_from_blob(pac_cred_info.encrypted_data);
     452             : 
     453           0 :         code = krb5_k_encrypt(context,
     454             :                               cred_key,
     455             :                               KRB5_KU_OTHER_ENCRYPTED,
     456             :                               NULL,
     457             :                               &cred_ndr_data,
     458             :                               &cred_ndr_crypt);
     459           0 :         krb5_k_free_key(context, cred_key);
     460           0 :         if (code != 0) {
     461           0 :                 krb5err = krb5_get_error_message(context, code);
     462           0 :                 DBG_WARNING("Failed crypt of cred data: %s\n", krb5err);
     463           0 :                 krb5_free_error_message(context, krb5err);
     464           0 :                 goto out;
     465             :         }
     466             : 
     467           0 :         if (DEBUGLVL(10)) {
     468           0 :                 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
     469             :         }
     470             : 
     471           0 :         ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
     472             :                         (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
     473           0 :         TALLOC_FREE(pac_cred_info.encrypted_data.data);
     474           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     475           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
     476           0 :                 DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
     477             :                             nt_errstr(nt_status));
     478           0 :                 code = KRB5KDC_ERR_SVC_UNAVAILABLE;
     479           0 :                 goto out;
     480             :         }
     481             : 
     482           0 :         DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32"\n",
     483             :                   cred_info_blob->length, pac_cred_info.encryption_type);
     484           0 :         dump_data_pw("PAC_CREDENTIAL_INFO",
     485           0 :                       cred_info_blob->data, cred_info_blob->length);
     486             : 
     487           0 : out:
     488           0 :         talloc_free(tmp_ctx);
     489           0 :         return code;
     490             : #endif /* SAMBA4_USES_HEIMDAL */
     491             : }
     492             : 
     493             : 
     494             : /**
     495             :  * @brief Create a PAC with the given blobs (logon, credentials, upn and
     496             :  * delegation).
     497             :  *
     498             :  * @param[in] context   The KRB5 context to use.
     499             :  *
     500             :  * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
     501             :  *                       use NULL to ignore it.
     502             :  *
     503             :  * @param[in] cred_blob  Fill the credentials info PAC buffer with the given
     504             :  *                       blob, use NULL to ignore it.
     505             :  *
     506             :  * @param[in] upn_blob  Fill the UPN info PAC buffer with the given blob, use
     507             :  *                      NULL to ignore it.
     508             :  *
     509             :  * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
     510             :  *                       blob, use NULL to ignore it.
     511             :  *
     512             :  * @param[in] client_claims_blob Fill the client claims info PAC buffer with the
     513             :  *                               given blob, use NULL to ignore it.
     514             :  *
     515             :  * @param[in] device_info_blob Fill the device info PAC buffer with the given
     516             :  *                             blob, use NULL to ignore it.
     517             :  *
     518             :  * @param[in] device_claims_blob Fill the device claims info PAC buffer with the given
     519             :  *                               blob, use NULL to ignore it.
     520             :  *
     521             :  * @param[in] pac        The pac buffer to fill. This should be allocated with
     522             :  *                       krb5_pac_init() already.
     523             :  *
     524             :  * @returns 0 on success or a corresponding KRB5 error.
     525             :  */
     526       30307 : krb5_error_code samba_make_krb5_pac(krb5_context context,
     527             :                                     const DATA_BLOB *logon_blob,
     528             :                                     const DATA_BLOB *cred_blob,
     529             :                                     const DATA_BLOB *upn_blob,
     530             :                                     const DATA_BLOB *pac_attrs_blob,
     531             :                                     const DATA_BLOB *requester_sid_blob,
     532             :                                     const DATA_BLOB *deleg_blob,
     533             :                                     const DATA_BLOB *client_claims_blob,
     534             :                                     const DATA_BLOB *device_info_blob,
     535             :                                     const DATA_BLOB *device_claims_blob,
     536             :                                     krb5_pac pac)
     537             : {
     538        1184 :         krb5_data logon_data;
     539        1184 :         krb5_error_code ret;
     540       30307 :         char null_byte = '\0';
     541       30307 :         krb5_data null_data = smb_krb5_make_data(&null_byte, 0);
     542             : 
     543             :         /* The user account may be set not to want the PAC */
     544       30307 :         if (logon_blob == NULL) {
     545           0 :                 return 0;
     546             :         }
     547             : 
     548       30307 :         logon_data = smb_krb5_data_from_blob(*logon_blob);
     549       30307 :         ret = krb5_pac_add_buffer(context, pac, PAC_TYPE_LOGON_INFO, &logon_data);
     550       30307 :         if (ret != 0) {
     551           0 :                 return ret;
     552             :         }
     553             : 
     554       30307 :         if (device_info_blob != NULL) {
     555           0 :                 krb5_data device_info_data = smb_krb5_data_from_blob(*device_info_blob);
     556           0 :                 ret = krb5_pac_add_buffer(context, pac,
     557             :                                           PAC_TYPE_DEVICE_INFO,
     558             :                                           &device_info_data);
     559           0 :                 if (ret != 0) {
     560           0 :                         return ret;
     561             :                 }
     562             :         }
     563             : 
     564       30307 :         if (client_claims_blob != NULL) {
     565        1184 :                 krb5_data client_claims_data;
     566       30307 :                 krb5_data *data = NULL;
     567             : 
     568       30307 :                 if (client_claims_blob->length != 0) {
     569         316 :                         client_claims_data = smb_krb5_data_from_blob(*client_claims_blob);
     570         316 :                         data = &client_claims_data;
     571             :                 } else {
     572       28807 :                         data = &null_data;
     573             :                 }
     574             : 
     575       30307 :                 ret = krb5_pac_add_buffer(context, pac,
     576             :                                           PAC_TYPE_CLIENT_CLAIMS_INFO,
     577             :                                           data);
     578       30307 :                 if (ret != 0) {
     579           0 :                         return ret;
     580             :                 }
     581             :         }
     582             : 
     583       30307 :         if (device_claims_blob != NULL) {
     584           0 :                 krb5_data device_claims_data = smb_krb5_data_from_blob(*device_claims_blob);
     585           0 :                 ret = krb5_pac_add_buffer(context, pac,
     586             :                                           PAC_TYPE_DEVICE_CLAIMS_INFO,
     587             :                                           &device_claims_data);
     588           0 :                 if (ret != 0) {
     589           0 :                         return ret;
     590             :                 }
     591             :         }
     592             : 
     593       30307 :         if (cred_blob != NULL) {
     594          45 :                 krb5_data cred_data = smb_krb5_data_from_blob(*cred_blob);
     595          45 :                 ret = krb5_pac_add_buffer(context, pac,
     596             :                                           PAC_TYPE_CREDENTIAL_INFO,
     597             :                                           &cred_data);
     598          45 :                 if (ret != 0) {
     599           0 :                         return ret;
     600             :                 }
     601             :         }
     602             : 
     603             : #ifdef SAMBA4_USES_HEIMDAL
     604             :         /*
     605             :          * null_data will be filled by the generic KDC code in the caller
     606             :          * here we just add it in order to have it before
     607             :          * PAC_TYPE_UPN_DNS_INFO
     608             :          *
     609             :          * Not needed with MIT Kerberos - asn
     610             :          */
     611       30307 :         ret = krb5_pac_add_buffer(context, pac,
     612             :                                   PAC_TYPE_LOGON_NAME,
     613             :                                   &null_data);
     614       30307 :         if (ret != 0) {
     615           0 :                 return ret;
     616             :         }
     617             : #endif
     618             : 
     619       30307 :         if (upn_blob != NULL) {
     620       30307 :                 krb5_data upn_data = smb_krb5_data_from_blob(*upn_blob);
     621       30307 :                 ret = krb5_pac_add_buffer(context, pac,
     622             :                                           PAC_TYPE_UPN_DNS_INFO,
     623             :                                           &upn_data);
     624       30307 :                 if (ret != 0) {
     625           0 :                         return ret;
     626             :                 }
     627             :         }
     628             : 
     629       30307 :         if (pac_attrs_blob != NULL) {
     630       27077 :                 krb5_data pac_attrs_data = smb_krb5_data_from_blob(*pac_attrs_blob);
     631       27077 :                 ret = krb5_pac_add_buffer(context, pac,
     632             :                                           PAC_TYPE_ATTRIBUTES_INFO,
     633             :                                           &pac_attrs_data);
     634       27077 :                 if (ret != 0) {
     635           0 :                         return ret;
     636             :                 }
     637             :         }
     638             : 
     639       30307 :         if (requester_sid_blob != NULL) {
     640       27077 :                 krb5_data requester_sid_data = smb_krb5_data_from_blob(*requester_sid_blob);
     641       27077 :                 ret = krb5_pac_add_buffer(context, pac,
     642             :                                           PAC_TYPE_REQUESTER_SID,
     643             :                                           &requester_sid_data);
     644       27077 :                 if (ret != 0) {
     645           0 :                         return ret;
     646             :                 }
     647             :         }
     648             : 
     649       30307 :         if (deleg_blob != NULL) {
     650           0 :                 krb5_data deleg_data = smb_krb5_data_from_blob(*deleg_blob);
     651           0 :                 ret = krb5_pac_add_buffer(context, pac,
     652             :                                           PAC_TYPE_CONSTRAINED_DELEGATION,
     653             :                                           &deleg_data);
     654           0 :                 if (ret != 0) {
     655           0 :                         return ret;
     656             :                 }
     657             :         }
     658             : 
     659       29123 :         return ret;
     660             : }
     661             : 
     662       48657 : bool samba_princ_needs_pac(const struct samba_kdc_entry *skdc_entry)
     663             : {
     664             : 
     665        1672 :         uint32_t userAccountControl;
     666             : 
     667             :         /* The service account may be set not to want the PAC */
     668       48657 :         userAccountControl = ldb_msg_find_attr_as_uint(skdc_entry->msg, "userAccountControl", 0);
     669       48657 :         if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
     670           5 :                 return false;
     671             :         }
     672             : 
     673       46980 :         return true;
     674             : }
     675             : 
     676       20453 : static krb5_error_code samba_client_requested_pac(krb5_context context,
     677             :                                                   const krb5_const_pac pac,
     678             :                                                   TALLOC_CTX *mem_ctx,
     679             :                                                   bool *requested_pac)
     680             : {
     681         630 :         enum ndr_err_code ndr_err;
     682         630 :         krb5_data k5pac_attrs_in;
     683         630 :         DATA_BLOB pac_attrs_in;
     684         630 :         union PAC_INFO pac_attrs;
     685         630 :         krb5_error_code ret;
     686             : 
     687       20453 :         *requested_pac = true;
     688             : 
     689       20453 :         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_ATTRIBUTES_INFO,
     690             :                                   &k5pac_attrs_in);
     691       20453 :         if (ret != 0) {
     692         138 :                 return ret == ENOENT ? 0 : ret;
     693             :         }
     694             : 
     695       20315 :         pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
     696           0 :                                        k5pac_attrs_in.length);
     697             : 
     698       20315 :         ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
     699             :                                       PAC_TYPE_ATTRIBUTES_INFO,
     700             :                                       (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
     701       20315 :         smb_krb5_free_data_contents(context, &k5pac_attrs_in);
     702       20315 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     703           0 :                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
     704           0 :                 DBG_ERR("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status));
     705           0 :                 return map_errno_from_nt_status(nt_status);
     706             :         }
     707             : 
     708       20315 :         if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
     709             :                                                | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
     710       20309 :                 *requested_pac = true;
     711             :         } else {
     712           6 :                 *requested_pac = false;
     713             :         }
     714             : 
     715       19685 :         return 0;
     716             : }
     717             : 
     718             : /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
     719       50558 : krb5_error_code samba_krbtgt_is_in_db(const struct samba_kdc_entry *p,
     720             :                                       bool *is_in_db,
     721             :                                       bool *is_trusted)
     722             : {
     723        1672 :         NTSTATUS status;
     724        1672 :         krb5_error_code ret;
     725        1672 :         int rodc_krbtgt_number, trust_direction;
     726        1672 :         struct dom_sid sid;
     727        1672 :         uint32_t rid;
     728             : 
     729       50558 :         trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
     730             : 
     731       50558 :         if (trust_direction != 0) {
     732             :                 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
     733             : 
     734             :                    This is exactly where we should flag for SID
     735             :                    validation when we do inter-forest trusts
     736             :                  */
     737          59 :                 *is_trusted = true;
     738          59 :                 *is_in_db = false;
     739          59 :                 return 0;
     740             :         }
     741             : 
     742             :         /* The lack of password controls etc applies to krbtgt by
     743             :          * virtue of being that particular RID */
     744       50499 :         ret = samdb_result_dom_sid_buf(p->msg, "objectSid", &sid);
     745       50499 :         if (ret) {
     746           0 :                 return ret;
     747             :         }
     748             : 
     749       50499 :         status = dom_sid_split_rid(NULL, &sid, NULL, &rid);
     750       50499 :         if (!NT_STATUS_IS_OK(status)) {
     751           0 :                 return map_errno_from_nt_status(status);
     752             :         }
     753             : 
     754       50499 :         rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
     755             : 
     756       50499 :         if (p->kdc_db_ctx->my_krbtgt_number == 0) {
     757       48105 :                 if (rid == DOMAIN_RID_KRBTGT) {
     758       47878 :                         *is_trusted = true;
     759       47878 :                         *is_in_db = true;
     760       47878 :                         return 0;
     761         227 :                 } else if (rodc_krbtgt_number != -1) {
     762         227 :                         *is_in_db = true;
     763         227 :                         *is_trusted = false;
     764         227 :                         return 0;
     765             :                 }
     766        2394 :         } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
     767        2394 :                 *is_trusted = true;
     768        2394 :                 *is_in_db = true;
     769        2394 :                 return 0;
     770           0 :         } else if (rid == DOMAIN_RID_KRBTGT) {
     771             :                 /* krbtgt viewed from an RODC */
     772           0 :                 *is_trusted = true;
     773           0 :                 *is_in_db = false;
     774           0 :                 return 0;
     775             :         }
     776             : 
     777             :         /* Another RODC */
     778           0 :         *is_trusted = false;
     779           0 :         *is_in_db = false;
     780           0 :         return 0;
     781             : }
     782             : 
     783             : /*
     784             :  * Because the KDC does not limit protocol transition, two new well-known SIDs
     785             :  * were introduced to give this control to the resource administrator. These
     786             :  * SIDs identify whether protocol transition has occurred, and can be used with
     787             :  * standard access control lists to grant or limit access as needed.
     788             :  *
     789             :  * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
     790             :  */
     791       30452 : NTSTATUS samba_kdc_add_asserted_identity(enum samba_asserted_identity ai,
     792             :                                          struct auth_user_info_dc *user_info_dc)
     793             : {
     794       30452 :         const struct dom_sid *ai_sid = NULL;
     795             : 
     796       30452 :         switch (ai) {
     797         652 :         case SAMBA_ASSERTED_IDENTITY_SERVICE:
     798         652 :                 ai_sid = &global_sid_Asserted_Identity_Service;
     799         652 :                 break;
     800       29800 :         case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY:
     801       29800 :                 ai_sid = &global_sid_Asserted_Identity_Authentication_Authority;
     802       29800 :                 break;
     803           0 :         case SAMBA_ASSERTED_IDENTITY_IGNORE:
     804           0 :                 return NT_STATUS_OK;
     805           0 :         default:
     806           0 :                 return NT_STATUS_INVALID_PARAMETER;
     807             :         }
     808             : 
     809       30452 :         return add_sid_to_array_attrs_unique(
     810             :                 user_info_dc,
     811             :                 ai_sid,
     812             :                 SE_GROUP_DEFAULT_FLAGS,
     813             :                 &user_info_dc->sids,
     814             :                 &user_info_dc->num_sids);
     815             : }
     816             : 
     817       30481 : NTSTATUS samba_kdc_add_claims_valid(struct auth_user_info_dc *user_info_dc)
     818             : {
     819       30481 :         return add_sid_to_array_attrs_unique(
     820             :                 user_info_dc,
     821             :                 &global_sid_Claims_Valid,
     822             :                 SE_GROUP_DEFAULT_FLAGS,
     823             :                 &user_info_dc->sids,
     824             :                 &user_info_dc->num_sids);
     825             : }
     826             : 
     827           8 : NTSTATUS samba_kdc_add_fresh_public_key_identity(struct auth_user_info_dc *user_info_dc)
     828             : {
     829           8 :         return add_sid_to_array_attrs_unique(
     830             :                 user_info_dc,
     831             :                 &global_sid_Fresh_Public_Key_Identity,
     832             :                 SE_GROUP_DEFAULT_FLAGS,
     833             :                 &user_info_dc->sids,
     834             :                 &user_info_dc->num_sids);
     835             : }
     836             : 
     837          73 : static NTSTATUS samba_kdc_add_compounded_auth(struct auth_user_info_dc *user_info_dc)
     838             : {
     839          73 :         return add_sid_to_array_attrs_unique(
     840             :                 user_info_dc,
     841             :                 &global_sid_Compounded_Authentication,
     842             :                 SE_GROUP_DEFAULT_FLAGS,
     843             :                 &user_info_dc->sids,
     844             :                 &user_info_dc->num_sids);
     845             : }
     846             : 
     847      196800 : bool samba_kdc_entry_is_trust(const struct samba_kdc_entry *entry)
     848             : {
     849      196800 :         return entry != NULL && entry->is_trust;
     850             : }
     851             : 
     852             : /*
     853             :  * Return true if this entry has an associated PAC issued or signed by a KDC
     854             :  * that our KDC trusts. We trust the main krbtgt account, but we don’t trust any
     855             :  * RODC krbtgt besides ourselves.
     856             :  */
     857      450857 : bool samba_krb5_pac_is_trusted(const struct samba_kdc_entry_pac pac)
     858             : {
     859      450857 :         if (pac.pac == NULL) {
     860           0 :                 return false;
     861             :         }
     862             : 
     863             : #ifdef HAVE_KRB5_PAC_IS_TRUSTED /* Heimdal */
     864      450857 :         return krb5_pac_is_trusted(pac.pac);
     865             : #else /* MIT */
     866           0 :         return pac.pac_is_trusted;
     867             : #endif /* HAVE_KRB5_PAC_IS_TRUSTED */
     868             : }
     869             : 
     870             : #ifdef HAVE_KRB5_PAC_IS_TRUSTED /* Heimdal */
     871      245520 : struct samba_kdc_entry_pac samba_kdc_entry_pac(krb5_const_pac pac,
     872             :                                                struct samba_kdc_entry *entry,
     873             :                                                bool is_from_trust)
     874             : {
     875      245520 :         return (struct samba_kdc_entry_pac) {
     876             :                 .entry = entry,
     877             :                 .pac = pac,
     878             :                 .is_from_trust = is_from_trust,
     879             :         };
     880             : }
     881             : #else /* MIT */
     882           0 : struct samba_kdc_entry_pac samba_kdc_entry_pac_from_trusted(krb5_const_pac pac,
     883             :                                                             struct samba_kdc_entry *entry,
     884             :                                                             bool is_from_trust,
     885             :                                                             bool is_trusted)
     886             : {
     887           0 :         return (struct samba_kdc_entry_pac) {
     888             :                 .entry = entry,
     889             :                 .pac = pac,
     890             :                 .is_from_trust = is_from_trust,
     891             :                 .pac_is_trusted = is_trusted,
     892             :         };
     893             : }
     894             : #endif /* HAVE_KRB5_PAC_IS_TRUSTED */
     895             : 
     896       50471 : static bool samba_kdc_entry_pac_issued_by_trust(const struct samba_kdc_entry_pac entry)
     897             : {
     898       50471 :         return entry.pac != NULL && entry.is_from_trust;
     899             : }
     900             : 
     901       30423 : NTSTATUS samba_kdc_get_logon_info_blob(TALLOC_CTX *mem_ctx,
     902             :                                        const struct auth_user_info_dc *user_info_dc,
     903             :                                        const enum auth_group_inclusion group_inclusion,
     904             :                                        DATA_BLOB **_logon_info_blob)
     905             : {
     906       30423 :         DATA_BLOB *logon_blob = NULL;
     907        1184 :         NTSTATUS nt_status;
     908             : 
     909       30423 :         *_logon_info_blob = NULL;
     910             : 
     911       30423 :         logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
     912       30423 :         if (logon_blob == NULL) {
     913           0 :                 return NT_STATUS_NO_MEMORY;
     914             :         }
     915             : 
     916       30423 :         nt_status = samba_get_logon_info_pac_blob(logon_blob,
     917             :                                                   user_info_dc,
     918             :                                                   NULL,
     919             :                                                   group_inclusion,
     920             :                                                   logon_blob);
     921       30423 :         if (!NT_STATUS_IS_OK(nt_status)) {
     922           0 :                 DBG_ERR("Building PAC LOGON INFO failed: %s\n",
     923             :                         nt_errstr(nt_status));
     924           0 :                 talloc_free(logon_blob);
     925           0 :                 return nt_status;
     926             :         }
     927             : 
     928       30423 :         *_logon_info_blob = logon_blob;
     929             : 
     930       30423 :         return NT_STATUS_OK;
     931             : }
     932             : 
     933          45 : NTSTATUS samba_kdc_get_cred_ndr_blob(TALLOC_CTX *mem_ctx,
     934             :                                      const struct samba_kdc_entry *p,
     935             :                                      DATA_BLOB **_cred_ndr_blob)
     936             : {
     937          45 :         DATA_BLOB *cred_blob = NULL;
     938           0 :         NTSTATUS nt_status;
     939             : 
     940          45 :         SMB_ASSERT(_cred_ndr_blob != NULL);
     941             : 
     942          45 :         *_cred_ndr_blob = NULL;
     943             : 
     944          45 :         cred_blob = talloc_zero(mem_ctx, DATA_BLOB);
     945          45 :         if (cred_blob == NULL) {
     946           0 :                 return NT_STATUS_NO_MEMORY;
     947             :         }
     948             : 
     949          45 :         nt_status = samba_get_cred_info_ndr_blob(cred_blob,
     950          45 :                                                  p->msg,
     951             :                                                  cred_blob);
     952          45 :         if (!NT_STATUS_IS_OK(nt_status)) {
     953           0 :                 DBG_ERR("Building PAC CRED INFO failed: %s\n",
     954             :                         nt_errstr(nt_status));
     955           0 :                 talloc_free(cred_blob);
     956           0 :                 return nt_status;
     957             :         }
     958             : 
     959          45 :         *_cred_ndr_blob = cred_blob;
     960             : 
     961          45 :         return NT_STATUS_OK;
     962             : }
     963             : 
     964       30423 : NTSTATUS samba_kdc_get_upn_info_blob(TALLOC_CTX *mem_ctx,
     965             :                                      const struct auth_user_info_dc *user_info_dc,
     966             :                                      DATA_BLOB **_upn_info_blob)
     967             : {
     968       30423 :         DATA_BLOB *upn_blob = NULL;
     969        1184 :         NTSTATUS nt_status;
     970             : 
     971       30423 :         *_upn_info_blob = NULL;
     972             : 
     973       30423 :         upn_blob = talloc_zero(mem_ctx, DATA_BLOB);
     974       30423 :         if (upn_blob == NULL) {
     975           0 :                 return NT_STATUS_NO_MEMORY;
     976             :         }
     977             : 
     978       30423 :         nt_status = samba_get_upn_info_pac_blob(upn_blob,
     979             :                                                 user_info_dc,
     980             :                                                 upn_blob);
     981       30423 :         if (!NT_STATUS_IS_OK(nt_status)) {
     982           0 :                 DBG_ERR("Building PAC UPN INFO failed: %s\n",
     983             :                         nt_errstr(nt_status));
     984           0 :                 talloc_free(upn_blob);
     985           0 :                 return nt_status;
     986             :         }
     987             : 
     988       30423 :         *_upn_info_blob = upn_blob;
     989             : 
     990       30423 :         return NT_STATUS_OK;
     991             : }
     992             : 
     993       27077 : NTSTATUS samba_kdc_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
     994             :                                       uint64_t pac_attributes,
     995             :                                       DATA_BLOB **_pac_attrs_blob)
     996             : {
     997       27077 :         DATA_BLOB *pac_attrs_blob = NULL;
     998       27077 :         union PAC_INFO pac_attrs = {};
     999        1184 :         enum ndr_err_code ndr_err;
    1000        1184 :         NTSTATUS nt_status;
    1001             : 
    1002       27077 :         SMB_ASSERT(_pac_attrs_blob != NULL);
    1003             : 
    1004       27077 :         *_pac_attrs_blob = NULL;
    1005             : 
    1006       27077 :         pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
    1007       27077 :         if (pac_attrs_blob == NULL) {
    1008           0 :                 return NT_STATUS_NO_MEMORY;
    1009             :         }
    1010             : 
    1011             :         /* Set the length of the flags in bits. */
    1012       27077 :         pac_attrs.attributes_info.flags_length = 2;
    1013       27077 :         pac_attrs.attributes_info.flags = pac_attributes;
    1014             : 
    1015       27077 :         ndr_err = ndr_push_union_blob(pac_attrs_blob, pac_attrs_blob, &pac_attrs,
    1016             :                                       PAC_TYPE_ATTRIBUTES_INFO,
    1017             :                                       (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
    1018       27077 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1019           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
    1020           0 :                 DBG_WARNING("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
    1021             :                             nt_errstr(nt_status));
    1022           0 :                 DBG_ERR("Building PAC ATTRIBUTES failed: %s\n",
    1023             :                         nt_errstr(nt_status));
    1024             : 
    1025           0 :                 talloc_free(pac_attrs_blob);
    1026           0 :                 return nt_status;
    1027             :         }
    1028             : 
    1029       27077 :         *_pac_attrs_blob = pac_attrs_blob;
    1030             : 
    1031       27077 :         return NT_STATUS_OK;
    1032             : }
    1033             : 
    1034       27095 : NTSTATUS samba_kdc_get_requester_sid_blob(TALLOC_CTX *mem_ctx,
    1035             :                                           const struct auth_user_info_dc *user_info_dc,
    1036             :                                           DATA_BLOB **_requester_sid_blob)
    1037             : {
    1038       27095 :         DATA_BLOB *requester_sid_blob = NULL;
    1039        1184 :         NTSTATUS nt_status;
    1040             : 
    1041       27095 :         SMB_ASSERT(_requester_sid_blob != NULL);
    1042             : 
    1043       27095 :         *_requester_sid_blob = NULL;
    1044             : 
    1045       27095 :         requester_sid_blob = talloc_zero(mem_ctx, DATA_BLOB);
    1046       27095 :         if (requester_sid_blob == NULL) {
    1047           0 :                 return NT_STATUS_NO_MEMORY;
    1048             :         }
    1049             : 
    1050       27095 :         if (user_info_dc->num_sids > 0) {
    1051       27095 :                 union PAC_INFO pac_requester_sid = {};
    1052        1184 :                 enum ndr_err_code ndr_err;
    1053             : 
    1054       27095 :                 pac_requester_sid.requester_sid.sid = user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid;
    1055             : 
    1056       27095 :                 ndr_err = ndr_push_union_blob(requester_sid_blob, requester_sid_blob,
    1057             :                                               &pac_requester_sid,
    1058             :                                               PAC_TYPE_REQUESTER_SID,
    1059             :                                               (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
    1060       27095 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1061           0 :                         nt_status = ndr_map_error2ntstatus(ndr_err);
    1062           0 :                         DBG_WARNING("PAC_REQUESTER_SID (presig) push failed: %s\n",
    1063             :                                     nt_errstr(nt_status));
    1064           0 :                         DBG_ERR("Building PAC REQUESTER SID failed: %s\n",
    1065             :                                 nt_errstr(nt_status));
    1066             : 
    1067           0 :                         talloc_free(requester_sid_blob);
    1068           0 :                         return nt_status;
    1069             :                 }
    1070             :         }
    1071             : 
    1072       27095 :         *_requester_sid_blob = requester_sid_blob;
    1073             : 
    1074       27095 :         return NT_STATUS_OK;
    1075             : }
    1076             : 
    1077         116 : NTSTATUS samba_kdc_get_claims_blob(TALLOC_CTX *mem_ctx,
    1078             :                                    struct samba_kdc_entry *p,
    1079             :                                    const DATA_BLOB **_claims_blob)
    1080             : {
    1081         116 :         DATA_BLOB *claims_blob = NULL;
    1082         116 :         struct claims_data *claims_data = NULL;
    1083           0 :         NTSTATUS nt_status;
    1084           0 :         int ret;
    1085             : 
    1086         116 :         SMB_ASSERT(_claims_blob != NULL);
    1087             : 
    1088         116 :         *_claims_blob = NULL;
    1089             : 
    1090         116 :         claims_blob = talloc_zero(mem_ctx, DATA_BLOB);
    1091         116 :         if (claims_blob == NULL) {
    1092           0 :                 return NT_STATUS_NO_MEMORY;
    1093             :         }
    1094             : 
    1095         116 :         ret = samba_kdc_get_claims_data_from_db(p->kdc_db_ctx->samdb,
    1096             :                                                 p,
    1097             :                                                 &claims_data);
    1098         116 :         if (ret != LDB_SUCCESS) {
    1099           0 :                 nt_status = dsdb_ldb_err_to_ntstatus(ret);
    1100           0 :                 DBG_ERR("Building claims failed: %s\n",
    1101             :                         nt_errstr(nt_status));
    1102           0 :                 talloc_free(claims_blob);
    1103           0 :                 return nt_status;
    1104             :         }
    1105             : 
    1106         116 :         nt_status = claims_data_encoded_claims_set(claims_blob,
    1107             :                                                    claims_data,
    1108             :                                                    claims_blob);
    1109         116 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1110           0 :                 talloc_free(claims_blob);
    1111           0 :                 return nt_status;
    1112             :         }
    1113             : 
    1114         116 :         *_claims_blob = claims_blob;
    1115             : 
    1116         116 :         return NT_STATUS_OK;
    1117             : }
    1118             : 
    1119       81362 : krb5_error_code samba_kdc_get_user_info_from_db(TALLOC_CTX *mem_ctx,
    1120             :                                                 struct ldb_context *samdb,
    1121             :                                                 struct samba_kdc_entry *entry,
    1122             :                                                 const struct ldb_message *msg,
    1123             :                                                 const struct auth_user_info_dc **info_out)
    1124             : {
    1125        2960 :         NTSTATUS nt_status;
    1126             : 
    1127       81362 :         if (samdb == NULL) {
    1128           0 :                 return EINVAL;
    1129             :         }
    1130             : 
    1131       81362 :         if (msg == NULL) {
    1132           0 :                 return EINVAL;
    1133             :         }
    1134             : 
    1135       81362 :         if (info_out == NULL) {
    1136           0 :                 return EINVAL;
    1137             :         }
    1138             : 
    1139       81362 :         if (entry == NULL) {
    1140           0 :                 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    1141             :         }
    1142             : 
    1143       81362 :         *info_out = NULL;
    1144             : 
    1145       81362 :         if (entry->info_from_db == NULL) {
    1146       51519 :                 struct auth_user_info_dc *info_from_db = NULL;
    1147       51519 :                 struct loadparm_context *lp_ctx = entry->kdc_db_ctx->lp_ctx;
    1148             : 
    1149       51519 :                 nt_status = authsam_make_user_info_dc(entry,
    1150             :                                                       samdb,
    1151             :                                                       lpcfg_netbios_name(lp_ctx),
    1152             :                                                       lpcfg_sam_name(lp_ctx),
    1153             :                                                       lpcfg_sam_dnsname(lp_ctx),
    1154             :                                                       entry->realm_dn,
    1155             :                                                       msg,
    1156             :                                                       data_blob_null,
    1157             :                                                       data_blob_null,
    1158             :                                                       &info_from_db);
    1159       51519 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    1160           0 :                         DBG_ERR("Getting user info for PAC failed: %s\n",
    1161             :                                 nt_errstr(nt_status));
    1162             :                         /* NT_STATUS_OBJECT_NAME_NOT_FOUND is mapped to ENOENT. */
    1163           0 :                         return map_errno_from_nt_status(nt_status);
    1164             :                 }
    1165             : 
    1166       51519 :                 entry->info_from_db = info_from_db;
    1167             :         }
    1168             : 
    1169       81362 :         *info_out = entry->info_from_db;
    1170             : 
    1171       81362 :         return 0;
    1172             : }
    1173             : 
    1174             : /*
    1175             :  * Check whether a PAC contains the Authentication Authority Asserted Identity
    1176             :  * SID.
    1177             :  */
    1178         170 : static krb5_error_code samba_kdc_pac_contains_asserted_identity(
    1179             :         krb5_context context,
    1180             :         const struct samba_kdc_entry_pac entry,
    1181             :         bool *contains_out)
    1182             : {
    1183         170 :         TALLOC_CTX *frame = NULL;
    1184         170 :         struct auth_user_info_dc *info = NULL;
    1185         170 :         krb5_error_code ret = 0;
    1186             : 
    1187         170 :         if (contains_out == NULL) {
    1188           0 :                 ret = EINVAL;
    1189           0 :                 goto out;
    1190             :         }
    1191         170 :         *contains_out = false;
    1192             : 
    1193         170 :         frame = talloc_stackframe();
    1194             : 
    1195             :         /*
    1196             :          * Extract our info from the PAC. This does a bit of unnecessary work,
    1197             :          * setting up fields we don’t care about — we only want the SIDs.
    1198             :          */
    1199         170 :         ret = kerberos_pac_to_user_info_dc(frame,
    1200         170 :                                            entry.pac,
    1201             :                                            context,
    1202             :                                            &info,
    1203             :                                            AUTH_EXCLUDE_RESOURCE_GROUPS,
    1204             :                                            NULL /* pac_srv_sig */,
    1205             :                                            NULL /* pac_kdc_sig */,
    1206             :                                            /* Ignore the resource groups. */
    1207             :                                            NULL /* resource_groups */);
    1208         170 :         if (ret) {
    1209           0 :                 const char *krb5err = krb5_get_error_message(context, ret);
    1210           0 :                 DBG_ERR("kerberos_pac_to_user_info_dc failed: %s\n",
    1211             :                         krb5err != NULL ? krb5err : "?");
    1212           0 :                 krb5_free_error_message(context, krb5err);
    1213             : 
    1214           0 :                 goto out;
    1215             :         }
    1216             : 
    1217             :         /* Determine whether the PAC contains the Asserted Identity SID. */
    1218         170 :         *contains_out = sid_attrs_contains_sid(
    1219         170 :                 info->sids,
    1220         170 :                 info->num_sids,
    1221             :                 &global_sid_Asserted_Identity_Authentication_Authority);
    1222             : 
    1223         170 : out:
    1224         170 :         talloc_free(frame);
    1225         170 :         return ret;
    1226             : }
    1227             : 
    1228       49366 : static krb5_error_code samba_kdc_get_user_info_from_pac(TALLOC_CTX *mem_ctx,
    1229             :                                                         krb5_context context,
    1230             :                                                         struct ldb_context *samdb,
    1231             :                                                         const struct samba_kdc_entry_pac entry,
    1232             :                                                         const struct auth_user_info_dc **info_out,
    1233             :                                                         const struct PAC_DOMAIN_GROUP_MEMBERSHIP **resource_groups_out)
    1234             : {
    1235       49366 :         TALLOC_CTX *frame = NULL;
    1236       49366 :         struct auth_user_info_dc *info = NULL;
    1237       49366 :         struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups = NULL;
    1238       49366 :         krb5_error_code ret = 0;
    1239        1672 :         NTSTATUS nt_status;
    1240             : 
    1241       49366 :         if (samdb == NULL) {
    1242           0 :                 ret = EINVAL;
    1243           0 :                 goto out;
    1244             :         }
    1245             : 
    1246       49366 :         if (!samba_krb5_pac_is_trusted(entry)) {
    1247           0 :                 ret = EINVAL;
    1248           0 :                 goto out;
    1249             :         }
    1250             : 
    1251       49366 :         if (info_out == NULL) {
    1252           0 :                 ret = EINVAL;
    1253           0 :                 goto out;
    1254             :         }
    1255             : 
    1256       49366 :         *info_out = NULL;
    1257       49366 :         if (resource_groups_out != NULL) {
    1258       28083 :                 *resource_groups_out = NULL;
    1259             :         }
    1260             : 
    1261       49366 :         if (entry.entry == NULL || entry.entry->info_from_pac == NULL) {
    1262       49336 :                 frame = talloc_stackframe();
    1263             : 
    1264       51008 :                 ret = kerberos_pac_to_user_info_dc(frame,
    1265       49336 :                                                    entry.pac,
    1266             :                                                    context,
    1267             :                                                    &info,
    1268             :                                                    AUTH_EXCLUDE_RESOURCE_GROUPS,
    1269             :                                                    NULL,
    1270             :                                                    NULL,
    1271             :                                                    &resource_groups);
    1272       49336 :                 if (ret) {
    1273           0 :                         const char *krb5err = krb5_get_error_message(context, ret);
    1274           0 :                         DBG_ERR("kerberos_pac_to_user_info_dc failed: %s\n",
    1275             :                                 krb5err != NULL ? krb5err : "?");
    1276           0 :                         krb5_free_error_message(context, krb5err);
    1277             : 
    1278           0 :                         goto out;
    1279             :                 }
    1280             : 
    1281             :                 /*
    1282             :                  * We need to expand group memberships within our local domain,
    1283             :                  * as the token might be generated by a trusted domain.
    1284             :                  */
    1285       49336 :                 nt_status = authsam_update_user_info_dc(frame,
    1286             :                                                         samdb,
    1287             :                                                         info);
    1288       49336 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    1289           0 :                         DBG_ERR("authsam_update_user_info_dc failed: %s\n",
    1290             :                                 nt_errstr(nt_status));
    1291             : 
    1292           0 :                         ret = map_errno_from_nt_status(nt_status);
    1293           0 :                         goto out;
    1294             :                 }
    1295             : 
    1296       49336 :                 if (entry.entry != NULL) {
    1297       49276 :                         entry.entry->info_from_pac = talloc_steal(entry.entry, info);
    1298       49276 :                         entry.entry->resource_groups_from_pac = talloc_steal(entry.entry, resource_groups);
    1299             :                 }
    1300             :         }
    1301             : 
    1302             : 
    1303       49366 :         if (entry.entry != NULL) {
    1304             :                 /* Note: the caller does not own this! */
    1305       49306 :                 *info_out = entry.entry->info_from_pac;
    1306             : 
    1307       49306 :                 if (resource_groups_out != NULL) {
    1308             :                         /* Note: the caller does not own this! */
    1309       28083 :                         *resource_groups_out = entry.entry->resource_groups_from_pac;
    1310             :                 }
    1311             :         } else {
    1312          60 :                 *info_out = talloc_steal(mem_ctx, info);
    1313             : 
    1314          60 :                 if (resource_groups_out != NULL) {
    1315           0 :                         *resource_groups_out = talloc_steal(mem_ctx, resource_groups);
    1316             :                 }
    1317             :         }
    1318             : 
    1319          60 : out:
    1320       49366 :         talloc_free(frame);
    1321       49366 :         return ret;
    1322             : }
    1323             : 
    1324       49536 : krb5_error_code samba_kdc_get_user_info_dc(TALLOC_CTX *mem_ctx,
    1325             :                                            krb5_context context,
    1326             :                                            struct ldb_context *samdb,
    1327             :                                            const struct samba_kdc_entry_pac entry,
    1328             :                                            const struct auth_user_info_dc **info_out,
    1329             :                                            const struct PAC_DOMAIN_GROUP_MEMBERSHIP **resource_groups_out)
    1330             : {
    1331       49536 :         const struct auth_user_info_dc *info = NULL;
    1332       49536 :         struct auth_user_info_dc *info_shallow_copy = NULL;
    1333       49536 :         bool pac_contains_asserted_identity = false;
    1334       49536 :         krb5_error_code ret = 0;
    1335        1672 :         NTSTATUS nt_status;
    1336             : 
    1337       49536 :         *info_out = NULL;
    1338       49536 :         if (resource_groups_out != NULL) {
    1339       28101 :                 *resource_groups_out = NULL;
    1340             :         }
    1341             : 
    1342       49536 :         if (samba_krb5_pac_is_trusted(entry)) {
    1343       49366 :                 return samba_kdc_get_user_info_from_pac(mem_ctx,
    1344             :                                                         context,
    1345             :                                                         samdb,
    1346             :                                                         entry,
    1347             :                                                         info_out,
    1348             :                                                         resource_groups_out);
    1349             :         }
    1350             : 
    1351         170 :         if (entry.entry == NULL) {
    1352           0 :                 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    1353             :         }
    1354             : 
    1355             :         /*
    1356             :          * In this case the RWDC discards the PAC an RODC generated.
    1357             :          * Windows adds the asserted_identity in this case too.
    1358             :          *
    1359             :          * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
    1360             :          * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
    1361             :          * So we can always use
    1362             :          * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
    1363             :          * here.
    1364             :          */
    1365         170 :         ret = samba_kdc_get_user_info_from_db(mem_ctx,
    1366             :                                               samdb,
    1367         170 :                                               entry.entry,
    1368         170 :                                               entry.entry->msg,
    1369             :                                               &info);
    1370         170 :         if (ret) {
    1371           0 :                 const char *krb5err = krb5_get_error_message(context, ret);
    1372           0 :                 DBG_ERR("samba_kdc_get_user_info_from_db: %s\n",
    1373             :                         krb5err != NULL ? krb5err : "?");
    1374           0 :                 krb5_free_error_message(context, krb5err);
    1375             : 
    1376           0 :                 return KRB5KDC_ERR_TGT_REVOKED;
    1377             :         }
    1378             : 
    1379             :         /* Make a shallow copy of the user_info_dc structure. */
    1380         170 :         nt_status = authsam_shallow_copy_user_info_dc(mem_ctx,
    1381             :                                                       info,
    1382             :                                                       &info_shallow_copy);
    1383         170 :         info = NULL;
    1384             : 
    1385         170 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1386           0 :                 DBG_ERR("Failed to allocate user_info_dc SIDs: %s\n",
    1387             :                         nt_errstr(nt_status));
    1388           0 :                 return map_errno_from_nt_status(nt_status);
    1389             :         }
    1390             : 
    1391             :         /* Determine whether the PAC contains the Asserted Identity SID. */
    1392         170 :         ret = samba_kdc_pac_contains_asserted_identity(
    1393             :                 context, entry, &pac_contains_asserted_identity);
    1394         170 :         if (ret) {
    1395           0 :                 return ret;
    1396             :         }
    1397             : 
    1398         170 :         if (pac_contains_asserted_identity) {
    1399         141 :                 nt_status = samba_kdc_add_asserted_identity(
    1400             :                         SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY,
    1401             :                         info_shallow_copy);
    1402         141 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    1403           0 :                         DBG_ERR("Failed to add asserted identity: %s\n",
    1404             :                                 nt_errstr(nt_status));
    1405           0 :                         TALLOC_FREE(info_shallow_copy);
    1406           0 :                         return KRB5KDC_ERR_TGT_REVOKED;
    1407             :                 }
    1408             :         }
    1409             : 
    1410         170 :         nt_status = samba_kdc_add_claims_valid(info_shallow_copy);
    1411         170 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1412           0 :                 DBG_ERR("Failed to add Claims Valid: %s\n",
    1413             :                         nt_errstr(nt_status));
    1414           0 :                 TALLOC_FREE(info_shallow_copy);
    1415           0 :                 return KRB5KDC_ERR_TGT_REVOKED;
    1416             :         }
    1417             : 
    1418         170 :         *info_out = info_shallow_copy;
    1419             : 
    1420         170 :         return 0;
    1421             : }
    1422             : 
    1423         152 : static NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
    1424             :                                                       krb5_context context,
    1425             :                                                       const krb5_const_pac pac,
    1426             :                                                       const krb5_const_principal server_principal,
    1427             :                                                       const krb5_const_principal proxy_principal,
    1428             :                                                       DATA_BLOB *new_blob)
    1429             : {
    1430         152 :         krb5_data old_data = {};
    1431           0 :         DATA_BLOB old_blob;
    1432           0 :         krb5_error_code ret;
    1433         152 :         NTSTATUS nt_status = NT_STATUS_OK;
    1434           0 :         enum ndr_err_code ndr_err;
    1435         152 :         union PAC_INFO info = {};
    1436         152 :         struct PAC_CONSTRAINED_DELEGATION _d = {};
    1437         152 :         struct PAC_CONSTRAINED_DELEGATION *d = NULL;
    1438         152 :         char *server = NULL;
    1439         152 :         char *proxy = NULL;
    1440           0 :         uint32_t i;
    1441         152 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    1442             : 
    1443         152 :         if (tmp_ctx == NULL) {
    1444           0 :                 nt_status = NT_STATUS_NO_MEMORY;
    1445           0 :                 goto out;
    1446             :         }
    1447             : 
    1448         152 :         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data);
    1449         152 :         if (ret == ENOENT) {
    1450             :                 /* OK. */
    1451           3 :         } else if (ret) {
    1452           0 :                 nt_status = NT_STATUS_UNSUCCESSFUL;
    1453           0 :                 goto out;
    1454             :         }
    1455             : 
    1456         152 :         old_blob.length = old_data.length;
    1457         152 :         old_blob.data = (uint8_t *)old_data.data;
    1458             : 
    1459         152 :         if (old_blob.length > 0) {
    1460           3 :                 ndr_err = ndr_pull_union_blob(&old_blob, tmp_ctx,
    1461             :                                 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
    1462             :                                 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
    1463           3 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1464           0 :                         smb_krb5_free_data_contents(context, &old_data);
    1465           0 :                         nt_status = ndr_map_error2ntstatus(ndr_err);
    1466           0 :                         DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status));
    1467           0 :                         goto out;
    1468             :                 }
    1469             :         } else {
    1470         149 :                 info.constrained_delegation.info = &_d;
    1471             :         }
    1472         152 :         smb_krb5_free_data_contents(context, &old_data);
    1473             : 
    1474         152 :         ret = krb5_unparse_name_flags(context, server_principal,
    1475             :                                       KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server);
    1476         152 :         if (ret) {
    1477           0 :                 nt_status = NT_STATUS_INTERNAL_ERROR;
    1478           0 :                 goto out;
    1479             :         }
    1480             : 
    1481         152 :         ret = krb5_unparse_name(context, proxy_principal, &proxy);
    1482         152 :         if (ret) {
    1483           0 :                 SAFE_FREE(server);
    1484           0 :                 nt_status = NT_STATUS_INTERNAL_ERROR;
    1485           0 :                 goto out;
    1486             :         }
    1487             : 
    1488         152 :         d = info.constrained_delegation.info;
    1489         152 :         i = d->num_transited_services;
    1490         152 :         d->proxy_target.string = server;
    1491         152 :         d->transited_services = talloc_realloc(mem_ctx, d->transited_services,
    1492             :                                                struct lsa_String, i + 1);
    1493         152 :         if (d->transited_services == NULL) {
    1494           0 :                 SAFE_FREE(server);
    1495           0 :                 SAFE_FREE(proxy);
    1496           0 :                 nt_status = NT_STATUS_INTERNAL_ERROR;
    1497           0 :                 goto out;
    1498             :         }
    1499         152 :         d->transited_services[i].string = proxy;
    1500         152 :         d->num_transited_services = i + 1;
    1501             : 
    1502         152 :         ndr_err = ndr_push_union_blob(new_blob, mem_ctx,
    1503             :                                 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
    1504             :                                 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
    1505         152 :         SAFE_FREE(server);
    1506         152 :         SAFE_FREE(proxy);
    1507         152 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1508           0 :                 smb_krb5_free_data_contents(context, &old_data);
    1509           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
    1510           0 :                 DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status));
    1511           0 :                 goto out;
    1512             :         }
    1513             : 
    1514         152 : out:
    1515         152 :         talloc_free(tmp_ctx);
    1516         152 :         return nt_status;
    1517             : }
    1518             : 
    1519             : /* function to map policy errors */
    1520          43 : krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
    1521             : {
    1522           0 :         krb5_error_code ret;
    1523             : 
    1524          43 :         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE))
    1525           5 :                 ret = KRB5KDC_ERR_KEY_EXP;
    1526          38 :         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED))
    1527           0 :                 ret = KRB5KDC_ERR_KEY_EXP;
    1528          38 :         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED))
    1529           0 :                 ret = KRB5KDC_ERR_CLIENT_REVOKED;
    1530          38 :         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED))
    1531           8 :                 ret = KRB5KDC_ERR_CLIENT_REVOKED;
    1532          30 :         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS))
    1533           4 :                 ret = KRB5KDC_ERR_CLIENT_REVOKED;
    1534          26 :         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT))
    1535          26 :                 ret = KRB5KDC_ERR_CLIENT_REVOKED;
    1536           0 :         else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION))
    1537           0 :                 ret = KRB5KDC_ERR_POLICY;
    1538             :         else
    1539           0 :                 ret = KRB5KDC_ERR_POLICY;
    1540             : 
    1541          43 :         return ret;
    1542             : }
    1543             : 
    1544             : /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
    1545             :  * for consistency */
    1546       48307 : NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
    1547             :                                        const char *client_name,
    1548             :                                        const char *workstation,
    1549             :                                        bool password_change)
    1550             : {
    1551        1776 :         TALLOC_CTX *tmp_ctx;
    1552        1776 :         NTSTATUS nt_status;
    1553             : 
    1554       48307 :         tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access");
    1555       48307 :         if (!tmp_ctx) {
    1556           0 :                 return NT_STATUS_NO_MEMORY;
    1557             :         }
    1558             : 
    1559             :         /* we allow all kinds of trusts here */
    1560       48307 :         nt_status = authsam_account_ok(tmp_ctx,
    1561       48307 :                                        kdc_entry->kdc_db_ctx->samdb,
    1562             :                                        MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
    1563             :                                        MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
    1564             :                                        kdc_entry->realm_dn, kdc_entry->msg,
    1565             :                                        workstation, client_name,
    1566             :                                        true, password_change);
    1567             : 
    1568       48307 :         kdc_entry->reject_status = nt_status;
    1569       48307 :         talloc_free(tmp_ctx);
    1570       48307 :         return nt_status;
    1571             : }
    1572             : 
    1573       50457 : static krb5_error_code samba_get_requester_sid(TALLOC_CTX *mem_ctx,
    1574             :                                                krb5_const_pac pac,
    1575             :                                                krb5_context context,
    1576             :                                                struct dom_sid *sid)
    1577             : {
    1578        1672 :         NTSTATUS nt_status;
    1579        1672 :         enum ndr_err_code ndr_err;
    1580       50457 :         krb5_error_code ret = 0;
    1581             : 
    1582        1672 :         DATA_BLOB pac_requester_sid_in;
    1583        1672 :         krb5_data k5pac_requester_sid_in;
    1584             : 
    1585        1672 :         union PAC_INFO info;
    1586             : 
    1587       50457 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    1588       50457 :         if (tmp_ctx == NULL) {
    1589           0 :                 ret = ENOMEM;
    1590           0 :                 goto out;
    1591             :         }
    1592             : 
    1593       50457 :         ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_REQUESTER_SID,
    1594             :                                   &k5pac_requester_sid_in);
    1595       50457 :         if (ret != 0) {
    1596         164 :                 goto out;
    1597             :         }
    1598             : 
    1599       50293 :         pac_requester_sid_in = data_blob_const(k5pac_requester_sid_in.data,
    1600           0 :                                                k5pac_requester_sid_in.length);
    1601             : 
    1602       50293 :         ndr_err = ndr_pull_union_blob(&pac_requester_sid_in, tmp_ctx, &info,
    1603             :                                       PAC_TYPE_REQUESTER_SID,
    1604             :                                       (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
    1605       50293 :         smb_krb5_free_data_contents(context, &k5pac_requester_sid_in);
    1606       50293 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1607           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
    1608           0 :                 DBG_ERR("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status));
    1609           0 :                 ret = map_errno_from_nt_status(nt_status);
    1610           0 :                 goto out;
    1611             :         }
    1612             : 
    1613       50293 :         *sid = info.requester_sid.sid;
    1614             : 
    1615       50457 : out:
    1616       50457 :         talloc_free(tmp_ctx);
    1617       50457 :         return ret;
    1618             : }
    1619             : 
    1620             : /* Does a parse and SID check, but no crypto. */
    1621       50457 : static krb5_error_code samba_kdc_validate_pac_blob(
    1622             :                 krb5_context context,
    1623             :                 const struct samba_kdc_entry_pac client)
    1624             : {
    1625       50457 :         TALLOC_CTX *frame = talloc_stackframe();
    1626       50457 :         struct auth_user_info_dc *pac_user_info = NULL;
    1627        1672 :         struct dom_sid client_sid;
    1628        1672 :         struct dom_sid pac_sid;
    1629        1672 :         krb5_error_code code;
    1630        1672 :         bool ok;
    1631             : 
    1632             :         /*
    1633             :          * First, try to get the SID from the requester SID buffer in the PAC.
    1634             :          */
    1635       50457 :         code = samba_get_requester_sid(frame, client.pac, context, &pac_sid);
    1636             : 
    1637       50457 :         if (code == ENOENT) {
    1638             :                 /*
    1639             :                  * If the requester SID buffer isn't present, fall back to the
    1640             :                  * SID in the LOGON_INFO PAC buffer.
    1641             :                  */
    1642         164 :                 code = kerberos_pac_to_user_info_dc(frame,
    1643         164 :                                                     client.pac,
    1644             :                                                     context,
    1645             :                                                     &pac_user_info,
    1646             :                                                     AUTH_EXCLUDE_RESOURCE_GROUPS,
    1647             :                                                     NULL,
    1648             :                                                     NULL,
    1649             :                                                     NULL);
    1650         164 :                 if (code != 0) {
    1651           0 :                         goto out;
    1652             :                 }
    1653             : 
    1654         164 :                 if (pac_user_info->num_sids == 0) {
    1655           0 :                         code = EINVAL;
    1656           0 :                         goto out;
    1657             :                 }
    1658             : 
    1659         164 :                 pac_sid = pac_user_info->sids[PRIMARY_USER_SID_INDEX].sid;
    1660       50293 :         } else if (code != 0) {
    1661           0 :                 goto out;
    1662             :         }
    1663             : 
    1664       50457 :         code = samdb_result_dom_sid_buf(client.entry->msg,
    1665             :                                         "objectSid",
    1666             :                                         &client_sid);
    1667       50457 :         if (code) {
    1668           0 :                 goto out;
    1669             :         }
    1670             : 
    1671       50457 :         ok = dom_sid_equal(&pac_sid, &client_sid);
    1672       50457 :         if (!ok) {
    1673           0 :                 struct dom_sid_buf buf1;
    1674           0 :                 struct dom_sid_buf buf2;
    1675             : 
    1676          38 :                 DBG_ERR("SID mismatch between PAC and looked up client: "
    1677             :                         "PAC[%s] != CLI[%s]\n",
    1678             :                         dom_sid_str_buf(&pac_sid, &buf1),
    1679             :                         dom_sid_str_buf(&client_sid, &buf2));
    1680          38 :                         code = KRB5KDC_ERR_TGT_REVOKED;
    1681          38 :                 goto out;
    1682             :         }
    1683             : 
    1684       48747 :         code = 0;
    1685       50457 : out:
    1686       50457 :         TALLOC_FREE(frame);
    1687       50457 :         return code;
    1688             : }
    1689             : 
    1690             : 
    1691             : /*
    1692             :  * In the RODC case, to confirm that the returned user is permitted to
    1693             :  * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
    1694             :  */
    1695         211 : static WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids,
    1696             :                                                  const struct dom_sid *object_sids,
    1697             :                                                  const struct samba_kdc_entry *rodc,
    1698             :                                                  const struct samba_kdc_entry *object)
    1699             : {
    1700           0 :         int ret;
    1701           0 :         WERROR werr;
    1702         211 :         TALLOC_CTX *frame = talloc_stackframe();
    1703         211 :         const char *rodc_attrs[] = { "msDS-KrbTgtLink",
    1704             :                                      "msDS-NeverRevealGroup",
    1705             :                                      "msDS-RevealOnDemandGroup",
    1706             :                                      "userAccountControl",
    1707             :                                      "objectSid",
    1708             :                                      NULL };
    1709         211 :         struct ldb_result *rodc_machine_account = NULL;
    1710         211 :         struct ldb_dn *rodc_machine_account_dn = samdb_result_dn(rodc->kdc_db_ctx->samdb,
    1711             :                                                  frame,
    1712         211 :                                                  rodc->msg,
    1713             :                                                  "msDS-KrbTgtLinkBL",
    1714             :                                                  NULL);
    1715         211 :         const struct dom_sid *rodc_machine_account_sid = NULL;
    1716             : 
    1717         211 :         if (rodc_machine_account_dn == NULL) {
    1718           6 :                 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
    1719             :                         ldb_dn_get_linearized(rodc->msg->dn));
    1720           6 :                 TALLOC_FREE(frame);
    1721           6 :                 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
    1722             :         }
    1723             : 
    1724             :         /*
    1725             :          * Follow the link and get the RODC account (the krbtgt
    1726             :          * account is the krbtgt_XXX account, but the
    1727             :          * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
    1728             :          * the RODC$ account)
    1729             :          *
    1730             :          * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
    1731             :          * out of the extended DNs
    1732             :          */
    1733             : 
    1734         205 :         ret = dsdb_search_dn(rodc->kdc_db_ctx->samdb,
    1735             :                              frame,
    1736             :                              &rodc_machine_account,
    1737             :                              rodc_machine_account_dn,
    1738             :                              rodc_attrs,
    1739             :                              DSDB_SEARCH_SHOW_EXTENDED_DN);
    1740         205 :         if (ret != LDB_SUCCESS) {
    1741           0 :                 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
    1742             :                         ldb_dn_get_linearized(rodc_machine_account_dn),
    1743             :                         ldb_dn_get_linearized(rodc->msg->dn),
    1744             :                         ldb_errstring(rodc->kdc_db_ctx->samdb));
    1745           0 :                 TALLOC_FREE(frame);
    1746           0 :                 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
    1747             :         }
    1748             : 
    1749         205 :         if (rodc_machine_account->count != 1) {
    1750           0 :                 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
    1751             :                         ldb_dn_get_linearized(rodc_machine_account_dn),
    1752             :                         ldb_dn_get_linearized(rodc->msg->dn),
    1753             :                         rodc_machine_account->count);
    1754           0 :                 TALLOC_FREE(frame);
    1755           0 :                 return WERR_DS_DRA_BAD_DN;
    1756             :         }
    1757             : 
    1758             :         /* if the object SID is equal to the user_sid, allow */
    1759         205 :         rodc_machine_account_sid = samdb_result_dom_sid(frame,
    1760         205 :                                           rodc_machine_account->msgs[0],
    1761             :                                           "objectSid");
    1762         205 :         if (rodc_machine_account_sid == NULL) {
    1763           0 :                 TALLOC_FREE(frame);
    1764           0 :                 return WERR_DS_DRA_BAD_DN;
    1765             :         }
    1766             : 
    1767         205 :         werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc->kdc_db_ctx->samdb,
    1768             :                                                               rodc_machine_account_sid,
    1769         205 :                                                               rodc_machine_account->msgs[0],
    1770         205 :                                                               object->msg,
    1771             :                                                               num_object_sids,
    1772             :                                                               object_sids);
    1773             : 
    1774         205 :         TALLOC_FREE(frame);
    1775         205 :         return werr;
    1776             : }
    1777             : 
    1778             : /*
    1779             :  * Perform an access check for the client attempting to authenticate to the
    1780             :  * server. ‘client_info’ must be talloc-allocated so that we can make a
    1781             :  * reference to it.
    1782             :  */
    1783         170 : krb5_error_code samba_kdc_allowed_to_authenticate_to(TALLOC_CTX *mem_ctx,
    1784             :                                                      struct ldb_context *samdb,
    1785             :                                                      struct loadparm_context *lp_ctx,
    1786             :                                                      const struct samba_kdc_entry *client,
    1787             :                                                      const struct auth_user_info_dc *client_info,
    1788             :                                                      const struct auth_user_info_dc *device_info,
    1789             :                                                      const struct auth_claims auth_claims,
    1790             :                                                      const struct samba_kdc_entry *server,
    1791             :                                                      struct authn_audit_info **server_audit_info_out,
    1792             :                                                      NTSTATUS *status_out)
    1793             : {
    1794         170 :         krb5_error_code ret = 0;
    1795           0 :         NTSTATUS status;
    1796           0 :         _UNUSED_ NTSTATUS _status;
    1797         170 :         struct dom_sid server_sid = {};
    1798         170 :         const struct authn_server_policy *server_policy = server->server_policy;
    1799             : 
    1800         170 :         if (status_out != NULL) {
    1801         170 :                 *status_out = NT_STATUS_OK;
    1802             :         }
    1803             : 
    1804         170 :         ret = samdb_result_dom_sid_buf(server->msg, "objectSid", &server_sid);
    1805         170 :         if (ret) {
    1806             :                 /*
    1807             :                  * Ignore the return status — we are already in an error path,
    1808             :                  * and overwriting the real error code with the audit info
    1809             :                  * status is unhelpful.
    1810             :                  */
    1811           0 :                 _status = authn_server_policy_audit_info(mem_ctx,
    1812             :                                                          server_policy,
    1813             :                                                          client_info,
    1814             :                                                          AUTHN_AUDIT_EVENT_OTHER_ERROR,
    1815             :                                                          AUTHN_AUDIT_REASON_NONE,
    1816             :                                                          dsdb_ldb_err_to_ntstatus(ret),
    1817             :                                                          server_audit_info_out);
    1818           0 :                 goto out;
    1819             :         }
    1820             : 
    1821         170 :         if (dom_sid_equal(&client_info->sids[PRIMARY_USER_SID_INDEX].sid, &server_sid)) {
    1822             :                 /* Authenticating to ourselves is always allowed. */
    1823           8 :                 status = authn_server_policy_audit_info(mem_ctx,
    1824             :                                                         server_policy,
    1825             :                                                         client_info,
    1826             :                                                         AUTHN_AUDIT_EVENT_OK,
    1827             :                                                         AUTHN_AUDIT_REASON_NONE,
    1828             :                                                         NT_STATUS_OK,
    1829             :                                                         server_audit_info_out);
    1830           8 :                 if (!NT_STATUS_IS_OK(status)) {
    1831           0 :                         ret = KRB5KRB_ERR_GENERIC;
    1832             :                 }
    1833           8 :                 goto out;
    1834             :         }
    1835             : 
    1836         162 :         status = authn_policy_authenticate_to_service(mem_ctx,
    1837             :                                                       samdb,
    1838             :                                                       lp_ctx,
    1839             :                                                       AUTHN_POLICY_AUTH_TYPE_KERBEROS,
    1840             :                                                       client_info,
    1841             :                                                       device_info,
    1842             :                                                       auth_claims,
    1843             :                                                       server_policy,
    1844         162 :                                                       (struct authn_policy_flags) { .force_compounded_authentication = true },
    1845             :                                                       server_audit_info_out);
    1846         162 :         if (!NT_STATUS_IS_OK(status)) {
    1847          67 :                 if (status_out != NULL) {
    1848          67 :                         *status_out = status;
    1849             :                 }
    1850          67 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED)) {
    1851          66 :                         ret = KRB5KDC_ERR_POLICY;
    1852           1 :                 } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
    1853           1 :                         ret = KRB5KDC_ERR_POLICY;
    1854             :                 } else {
    1855           0 :                         ret = KRB5KRB_ERR_GENERIC;
    1856             :                 }
    1857             :         }
    1858             : 
    1859          95 : out:
    1860         170 :         return ret;
    1861             : }
    1862             : 
    1863          94 : static krb5_error_code samba_kdc_add_domain_group_sid(struct PAC_DEVICE_INFO *info,
    1864             :                                                       const struct netr_SidAttr *sid)
    1865             : {
    1866           0 :         uint32_t i;
    1867           0 :         uint32_t rid;
    1868           0 :         NTSTATUS status;
    1869             : 
    1870          94 :         uint32_t domain_group_count = info->domain_group_count;
    1871          94 :         struct PAC_DOMAIN_GROUP_MEMBERSHIP *domain_group = NULL;
    1872          94 :         struct samr_RidWithAttribute *rids = NULL;
    1873             : 
    1874         131 :         for (i = 0; i < domain_group_count; ++i) {
    1875          52 :                 struct PAC_DOMAIN_GROUP_MEMBERSHIP *this_domain_group
    1876          52 :                         = &info->domain_groups[i];
    1877             : 
    1878          52 :                 if (dom_sid_in_domain(this_domain_group->domain_sid, sid->sid)) {
    1879          15 :                         domain_group = this_domain_group;
    1880          15 :                         break;
    1881             :                 }
    1882             :         }
    1883             : 
    1884          94 :         if (domain_group == NULL) {
    1885          79 :                 struct PAC_DOMAIN_GROUP_MEMBERSHIP *domain_groups = NULL;
    1886             : 
    1887          79 :                 if (domain_group_count == UINT32_MAX) {
    1888           0 :                         return EINVAL;
    1889             :                 }
    1890             : 
    1891          79 :                 domain_groups = talloc_realloc(
    1892             :                         info,
    1893             :                         info->domain_groups,
    1894             :                         struct PAC_DOMAIN_GROUP_MEMBERSHIP,
    1895             :                         domain_group_count + 1);
    1896          79 :                 if (domain_groups == NULL) {
    1897           0 :                         return ENOMEM;
    1898             :                 }
    1899             : 
    1900          79 :                 info->domain_groups = domain_groups;
    1901             : 
    1902          79 :                 domain_group = &info->domain_groups[domain_group_count++];
    1903          79 :                 *domain_group = (struct PAC_DOMAIN_GROUP_MEMBERSHIP) {};
    1904             : 
    1905          79 :                 status = dom_sid_split_rid(info->domain_groups,
    1906          79 :                                            sid->sid,
    1907             :                                            &domain_group->domain_sid,
    1908             :                                            &rid);
    1909          79 :                 if (!NT_STATUS_IS_OK(status)) {
    1910           0 :                         return map_errno_from_nt_status(status);
    1911             :                 }
    1912             :         } else {
    1913          15 :                 status = dom_sid_split_rid(NULL,
    1914          15 :                                            sid->sid,
    1915             :                                            NULL,
    1916             :                                            &rid);
    1917          15 :                 if (!NT_STATUS_IS_OK(status)) {
    1918           0 :                         return map_errno_from_nt_status(status);
    1919             :                 }
    1920             :         }
    1921             : 
    1922          94 :         if (domain_group->groups.count == UINT32_MAX) {
    1923           0 :                 return EINVAL;
    1924             :         }
    1925             : 
    1926          94 :         rids = talloc_realloc(info->domain_groups,
    1927             :                               domain_group->groups.rids,
    1928             :                               struct samr_RidWithAttribute,
    1929             :                               domain_group->groups.count + 1);
    1930          94 :         if (rids == NULL) {
    1931           0 :                 return ENOMEM;
    1932             :         }
    1933             : 
    1934          94 :         domain_group->groups.rids = rids;
    1935             : 
    1936          94 :         domain_group->groups.rids[domain_group->groups.count] = (struct samr_RidWithAttribute) {
    1937             :                 .rid = rid,
    1938          94 :                 .attributes = sid->attributes,
    1939             :         };
    1940             : 
    1941          94 :         ++domain_group->groups.count;
    1942             : 
    1943          94 :         info->domain_group_count = domain_group_count;
    1944             : 
    1945          94 :         return 0;
    1946             : }
    1947             : 
    1948          73 : static krb5_error_code samba_kdc_make_device_info(TALLOC_CTX *mem_ctx,
    1949             :                                                   const struct netr_SamInfo3 *info3,
    1950             :                                                   struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups,
    1951             :                                                   union PAC_INFO *info)
    1952             : {
    1953          73 :         TALLOC_CTX *tmp_ctx = NULL;
    1954          73 :         struct PAC_DEVICE_INFO *device_info = NULL;
    1955           0 :         uint32_t i;
    1956          73 :         krb5_error_code ret = 0;
    1957             : 
    1958          73 :         *info = (union PAC_INFO) {};
    1959             : 
    1960          73 :         info->device_info.info = NULL;
    1961             : 
    1962          73 :         tmp_ctx = talloc_new(mem_ctx);
    1963          73 :         if (tmp_ctx == NULL) {
    1964           0 :                 return ENOMEM;
    1965             :         }
    1966             : 
    1967          73 :         device_info = talloc(tmp_ctx, struct PAC_DEVICE_INFO);
    1968          73 :         if (device_info == NULL) {
    1969           0 :                 ret = ENOMEM;
    1970           0 :                 goto out;
    1971             :         }
    1972             : 
    1973          73 :         device_info->rid = info3->base.rid;
    1974          73 :         device_info->primary_gid = info3->base.primary_gid;
    1975          73 :         device_info->domain_sid = info3->base.domain_sid;
    1976          73 :         device_info->groups = info3->base.groups;
    1977             : 
    1978          73 :         device_info->sid_count = 0;
    1979          73 :         device_info->sids = NULL;
    1980             : 
    1981          73 :         if (resource_groups != NULL) {
    1982             :                 /*
    1983             :                  * The account's resource groups all belong to the same domain,
    1984             :                  * so we can add them all in one go.
    1985             :                  */
    1986           1 :                 device_info->domain_group_count = 1;
    1987           1 :                 device_info->domain_groups = talloc_move(device_info, &resource_groups);
    1988             :         } else {
    1989          72 :                 device_info->domain_group_count = 0;
    1990          72 :                 device_info->domain_groups = NULL;
    1991             :         }
    1992             : 
    1993         245 :         for (i = 0; i < info3->sidcount; ++i) {
    1994         172 :                 const struct netr_SidAttr *device_sid = &info3->sids[i];
    1995             : 
    1996         172 :                 if (dom_sid_has_account_domain(device_sid->sid)) {
    1997          68 :                         ret = samba_kdc_add_domain_group_sid(device_info, device_sid);
    1998          68 :                         if (ret != 0) {
    1999           0 :                                 goto out;
    2000             :                         }
    2001             :                 } else {
    2002         104 :                         device_info->sids = talloc_realloc(device_info, device_info->sids,
    2003             :                                                            struct netr_SidAttr,
    2004             :                                                            device_info->sid_count + 1);
    2005         104 :                         if (device_info->sids == NULL) {
    2006           0 :                                 ret = ENOMEM;
    2007           0 :                                 goto out;
    2008             :                         }
    2009             : 
    2010         104 :                         device_info->sids[device_info->sid_count].sid = dom_sid_dup(device_info->sids, device_sid->sid);
    2011         104 :                         if (device_info->sids[device_info->sid_count].sid == NULL) {
    2012           0 :                                 ret = ENOMEM;
    2013           0 :                                 goto out;
    2014             :                         }
    2015             : 
    2016         104 :                         device_info->sids[device_info->sid_count].attributes = device_sid->attributes;
    2017             : 
    2018         104 :                         ++device_info->sid_count;
    2019             :                 }
    2020             :         }
    2021             : 
    2022          73 :         info->device_info.info = talloc_steal(mem_ctx, device_info);
    2023             : 
    2024          73 : out:
    2025          73 :         talloc_free(tmp_ctx);
    2026          73 :         return ret;
    2027             : }
    2028             : 
    2029          64 : static krb5_error_code samba_kdc_update_device_info(TALLOC_CTX *mem_ctx,
    2030             :                                                       struct ldb_context *samdb,
    2031             :                                                       const union PAC_INFO *logon_info,
    2032             :                                                       struct PAC_DEVICE_INFO *device_info)
    2033             : {
    2034           0 :         NTSTATUS nt_status;
    2035          64 :         struct auth_user_info_dc *device_info_dc = NULL;
    2036           0 :         union netr_Validation validation;
    2037           0 :         uint32_t i;
    2038           0 :         uint32_t num_existing_sids;
    2039             : 
    2040             :         /*
    2041             :          * This does a bit of unnecessary work, setting up fields we don't care
    2042             :          * about -- we only want the SIDs.
    2043             :          */
    2044          64 :         validation.sam3 = &logon_info->logon_info.info->info3;
    2045          64 :         nt_status = make_user_info_dc_netlogon_validation(mem_ctx, "", 3, &validation,
    2046             :                                                           true, /* This user was authenticated */
    2047             :                                                           &device_info_dc);
    2048          64 :         if (!NT_STATUS_IS_OK(nt_status)) {
    2049           0 :                 return map_errno_from_nt_status(nt_status);
    2050             :         }
    2051             : 
    2052          64 :         num_existing_sids = device_info_dc->num_sids;
    2053             : 
    2054             :         /*
    2055             :          * We need to expand group memberships within our local domain,
    2056             :          * as the token might be generated by a trusted domain.
    2057             :          */
    2058          64 :         nt_status = authsam_update_user_info_dc(mem_ctx,
    2059             :                                                 samdb,
    2060             :                                                 device_info_dc);
    2061          64 :         if (!NT_STATUS_IS_OK(nt_status)) {
    2062           0 :                 return map_errno_from_nt_status(nt_status);
    2063             :         }
    2064             : 
    2065          90 :         for (i = num_existing_sids; i < device_info_dc->num_sids; ++i) {
    2066          26 :                 struct auth_SidAttr *device_sid = &device_info_dc->sids[i];
    2067          26 :                 const struct netr_SidAttr sid = (struct netr_SidAttr) {
    2068          26 :                         .sid = &device_sid->sid,
    2069          26 :                         .attributes = device_sid->attrs,
    2070             :                 };
    2071             : 
    2072          26 :                 krb5_error_code ret = samba_kdc_add_domain_group_sid(device_info, &sid);
    2073          26 :                 if (ret != 0) {
    2074           0 :                         return ret;
    2075             :                 }
    2076             :         }
    2077             : 
    2078          64 :         return 0;
    2079             : }
    2080             : 
    2081          73 : static krb5_error_code samba_kdc_get_device_info_pac_blob(TALLOC_CTX *mem_ctx,
    2082             :                                                           union PAC_INFO *info,
    2083             :                                                           DATA_BLOB **_device_info_blob)
    2084             : {
    2085          73 :         DATA_BLOB *device_info_blob = NULL;
    2086           0 :         enum ndr_err_code ndr_err;
    2087             : 
    2088          73 :         *_device_info_blob = NULL;
    2089             : 
    2090          73 :         device_info_blob = talloc_zero(mem_ctx, DATA_BLOB);
    2091          73 :         if (device_info_blob == NULL) {
    2092           0 :                 DBG_ERR("Out of memory\n");
    2093           0 :                 return ENOMEM;
    2094             :         }
    2095             : 
    2096          73 :         ndr_err = ndr_push_union_blob(device_info_blob, device_info_blob,
    2097             :                                       info, PAC_TYPE_DEVICE_INFO,
    2098             :                                       (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
    2099          73 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    2100           0 :                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
    2101           0 :                 DBG_WARNING("PAC_DEVICE_INFO (presig) push failed: %s\n",
    2102             :                             nt_errstr(nt_status));
    2103           0 :                 talloc_free(device_info_blob);
    2104           0 :                 return map_errno_from_nt_status(nt_status);
    2105             :         }
    2106             : 
    2107          73 :         *_device_info_blob = device_info_blob;
    2108             : 
    2109          73 :         return 0;
    2110             : }
    2111             : 
    2112          64 : static krb5_error_code samba_kdc_create_device_info_blob(TALLOC_CTX *mem_ctx,
    2113             :                                                          krb5_context context,
    2114             :                                                          struct ldb_context *samdb,
    2115             :                                                          const krb5_const_pac device_pac,
    2116             :                                                          DATA_BLOB **device_info_blob)
    2117             : {
    2118          64 :         TALLOC_CTX *frame = NULL;
    2119           0 :         krb5_data device_logon_info;
    2120          64 :         krb5_error_code code = EINVAL;
    2121           0 :         NTSTATUS nt_status;
    2122             : 
    2123           0 :         union PAC_INFO info;
    2124           0 :         enum ndr_err_code ndr_err;
    2125           0 :         DATA_BLOB device_logon_info_blob;
    2126             : 
    2127           0 :         union PAC_INFO logon_info;
    2128             : 
    2129          64 :         code = krb5_pac_get_buffer(context, device_pac,
    2130             :                                    PAC_TYPE_LOGON_INFO,
    2131             :                                    &device_logon_info);
    2132          64 :         if (code != 0) {
    2133           0 :                 if (code == ENOENT) {
    2134           0 :                         DBG_ERR("Device PAC is missing LOGON_INFO\n");
    2135             :                 } else {
    2136           0 :                         DBG_ERR("Error getting LOGON_INFO from device PAC\n");
    2137             :                 }
    2138           0 :                 return code;
    2139             :         }
    2140             : 
    2141          64 :         frame = talloc_stackframe();
    2142             : 
    2143          64 :         device_logon_info_blob = data_blob_const(device_logon_info.data,
    2144           0 :                                                  device_logon_info.length);
    2145             : 
    2146          64 :         ndr_err = ndr_pull_union_blob(&device_logon_info_blob, frame, &logon_info,
    2147             :                                       PAC_TYPE_LOGON_INFO,
    2148             :                                       (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
    2149          64 :         smb_krb5_free_data_contents(context, &device_logon_info);
    2150          64 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    2151           0 :                 nt_status = ndr_map_error2ntstatus(ndr_err);
    2152           0 :                 DBG_ERR("can't parse device PAC LOGON_INFO: %s\n",
    2153             :                         nt_errstr(nt_status));
    2154           0 :                 talloc_free(frame);
    2155           0 :                 return map_errno_from_nt_status(nt_status);
    2156             :         }
    2157             : 
    2158             :         /*
    2159             :          * When creating the device info structure, existing resource groups are
    2160             :          * discarded.
    2161             :          */
    2162          64 :         code = samba_kdc_make_device_info(frame,
    2163          64 :                                           &logon_info.logon_info.info->info3,
    2164             :                                           NULL, /* resource_groups */
    2165             :                                           &info);
    2166          64 :         if (code != 0) {
    2167           0 :                 talloc_free(frame);
    2168           0 :                 return code;
    2169             :         }
    2170             : 
    2171          64 :         code = samba_kdc_update_device_info(frame,
    2172             :                                             samdb,
    2173             :                                             &logon_info,
    2174             :                                             info.device_info.info);
    2175          64 :         if (code != 0) {
    2176           0 :                 talloc_free(frame);
    2177           0 :                 return code;
    2178             :         }
    2179             : 
    2180          64 :         code = samba_kdc_get_device_info_pac_blob(mem_ctx,
    2181             :                                                   &info,
    2182             :                                                   device_info_blob);
    2183             : 
    2184          64 :         talloc_free(frame);
    2185          64 :         return code;
    2186             : }
    2187             : 
    2188           9 : static krb5_error_code samba_kdc_get_device_info_blob(TALLOC_CTX *mem_ctx,
    2189             :                                                       krb5_context context,
    2190             :                                                       struct ldb_context *samdb,
    2191             :                                                       const struct samba_kdc_entry_pac device,
    2192             :                                                       DATA_BLOB **device_info_blob)
    2193             : {
    2194           9 :         TALLOC_CTX *frame = NULL;
    2195           9 :         krb5_error_code code = EINVAL;
    2196           0 :         NTSTATUS nt_status;
    2197             : 
    2198           9 :         const struct auth_user_info_dc *device_info = NULL;
    2199           9 :         struct netr_SamInfo3 *info3 = NULL;
    2200           9 :         struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups = NULL;
    2201             : 
    2202           0 :         union PAC_INFO info;
    2203             : 
    2204           9 :         frame = talloc_stackframe();
    2205             : 
    2206           9 :         code = samba_kdc_get_user_info_dc(frame,
    2207             :                                           context,
    2208             :                                           samdb,
    2209             :                                           device,
    2210             :                                           &device_info,
    2211             :                                           NULL /* resource_groups_out */);
    2212           9 :         if (code) {
    2213           0 :                 const char *krb5_err = krb5_get_error_message(context, code);
    2214           0 :                 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
    2215             :                         krb5_err != NULL ? krb5_err : "<unknown>");
    2216           0 :                 krb5_free_error_message(context, krb5_err);
    2217             : 
    2218           0 :                 talloc_free(frame);
    2219           0 :                 return KRB5KDC_ERR_TGT_REVOKED;
    2220             :         }
    2221             : 
    2222           9 :         nt_status = auth_convert_user_info_dc_saminfo3(frame, device_info,
    2223             :                                                        AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED,
    2224             :                                                        &info3,
    2225             :                                                        &resource_groups);
    2226           9 :         if (!NT_STATUS_IS_OK(nt_status)) {
    2227           0 :                 DBG_WARNING("Getting Samba info failed: %s\n",
    2228             :                             nt_errstr(nt_status));
    2229           0 :                 talloc_free(frame);
    2230           0 :                 return nt_status_to_krb5(nt_status);
    2231             :         }
    2232             : 
    2233           9 :         code = samba_kdc_make_device_info(frame,
    2234             :                                           info3,
    2235             :                                           resource_groups,
    2236             :                                           &info);
    2237           9 :         if (code != 0) {
    2238           0 :                 talloc_free(frame);
    2239           0 :                 return code;
    2240             :         }
    2241             : 
    2242           9 :         code = samba_kdc_get_device_info_pac_blob(mem_ctx,
    2243             :                                                   &info,
    2244             :                                                   device_info_blob);
    2245             : 
    2246           9 :         talloc_free(frame);
    2247           9 :         return code;
    2248             : }
    2249             : 
    2250             : /**
    2251             :  * @brief Verify a PAC
    2252             :  *
    2253             :  * @param mem_ctx   A talloc memory context
    2254             :  *
    2255             :  * @param context   A krb5 context
    2256             :  *
    2257             :  * @param samdb     An open samdb connection.
    2258             :  *
    2259             :  * @param flags     Bitwise OR'ed flags
    2260             :  *
    2261             :  * @param client    The client samba kdc PAC entry.
    2262             : 
    2263             :  * @param krbtgt    The krbtgt samba kdc entry.
    2264             :  *
    2265             :  * @return A Kerberos error code.
    2266             :  */
    2267       50517 : krb5_error_code samba_kdc_verify_pac(TALLOC_CTX *mem_ctx,
    2268             :                                      krb5_context context,
    2269             :                                      struct ldb_context *samdb,
    2270             :                                      uint32_t flags,
    2271             :                                      const struct samba_kdc_entry_pac client,
    2272             :                                      const struct samba_kdc_entry *krbtgt)
    2273             : {
    2274       50517 :         TALLOC_CTX *tmp_ctx = NULL;
    2275       50517 :         struct pac_blobs *pac_blobs = NULL;
    2276       50517 :         krb5_error_code code = EINVAL;
    2277             : 
    2278       50517 :         tmp_ctx = talloc_new(mem_ctx);
    2279       50517 :         if (tmp_ctx == NULL) {
    2280           0 :                 code = ENOMEM;
    2281           0 :                 goto done;
    2282             :         }
    2283             : 
    2284       50517 :         if (client.entry != NULL) {
    2285             :                 /*
    2286             :                  * Check the objectSID of the client and pac data are the same.
    2287             :                  * Does a parse and SID check, but no crypto.
    2288             :                  */
    2289       50457 :                 code = samba_kdc_validate_pac_blob(context, client);
    2290       50457 :                 if (code != 0) {
    2291          38 :                         goto done;
    2292             :                 }
    2293             :         }
    2294             : 
    2295       50479 :         if (!samba_krb5_pac_is_trusted(client)) {
    2296         211 :                 const struct auth_user_info_dc *user_info_dc = NULL;
    2297           0 :                 WERROR werr;
    2298             : 
    2299         211 :                 struct dom_sid *object_sids = NULL;
    2300           0 :                 uint32_t j;
    2301             : 
    2302         211 :                 if (client.entry == NULL) {
    2303           0 :                         code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    2304          32 :                         goto done;
    2305             :                 }
    2306             : 
    2307         211 :                 code = samba_kdc_get_user_info_from_db(tmp_ctx,
    2308             :                                                        samdb,
    2309         211 :                                                        client.entry,
    2310         211 :                                                        client.entry->msg,
    2311             :                                                        &user_info_dc);
    2312         211 :                 if (code) {
    2313           0 :                         const char *krb5_err = krb5_get_error_message(context, code);
    2314           0 :                         DBG_ERR("Getting user info for PAC failed: %s\n",
    2315             :                                 krb5_err != NULL ? krb5_err : "<unknown>");
    2316           0 :                         krb5_free_error_message(context, krb5_err);
    2317             : 
    2318           0 :                         code = KRB5KDC_ERR_TGT_REVOKED;
    2319           0 :                         goto done;
    2320             :                 }
    2321             : 
    2322             :                 /*
    2323             :                  * Check if the SID list in the user_info_dc intersects
    2324             :                  * correctly with the RODC allow/deny lists.
    2325             :                  */
    2326         211 :                 object_sids = talloc_array(tmp_ctx, struct dom_sid, user_info_dc->num_sids);
    2327         211 :                 if (object_sids == NULL) {
    2328           0 :                         code = ENOMEM;
    2329           0 :                         goto done;
    2330             :                 }
    2331             : 
    2332         936 :                 for (j = 0; j < user_info_dc->num_sids; ++j) {
    2333         725 :                         object_sids[j] = user_info_dc->sids[j].sid;
    2334             :                 }
    2335             : 
    2336         211 :                 werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
    2337             :                                                           object_sids,
    2338             :                                                           krbtgt,
    2339         211 :                                                           client.entry);
    2340         211 :                 if (!W_ERROR_IS_OK(werr)) {
    2341          30 :                         code = KRB5KDC_ERR_TGT_REVOKED;
    2342          30 :                         if (W_ERROR_EQUAL(werr,
    2343             :                                           WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
    2344          12 :                                 code = KRB5KDC_ERR_POLICY;
    2345             :                         }
    2346          30 :                         goto done;
    2347             :                 }
    2348             : 
    2349             :                 /*
    2350             :                  * The RODC PAC data isn't trusted for authorization as it may
    2351             :                  * be stale. The only thing meaningful we can do with an RODC
    2352             :                  * account on a full DC is exchange the RODC TGT for a 'real'
    2353             :                  * TGT.
    2354             :                  *
    2355             :                  * So we match Windows (at least server 2022) and
    2356             :                  * don't allow S4U2Self.
    2357             :                  *
    2358             :                  * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
    2359             :                  */
    2360         181 :                 if (flags & SAMBA_KDC_FLAG_PROTOCOL_TRANSITION) {
    2361           2 :                         code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    2362           2 :                         goto done;
    2363             :                 }
    2364             :         }
    2365             : 
    2366             :         /* Check the types of the given PAC */
    2367             : 
    2368       52119 :         code = pac_blobs_from_krb5_pac(tmp_ctx,
    2369             :                                        context,
    2370       50447 :                                        client.pac,
    2371             :                                        &pac_blobs);
    2372       50447 :         if (code != 0) {
    2373           0 :                 goto done;
    2374             :         }
    2375             : 
    2376       50447 :         code = pac_blobs_ensure_exists(pac_blobs,
    2377             :                                        PAC_TYPE_LOGON_INFO);
    2378       50447 :         if (code != 0) {
    2379           0 :                 goto done;
    2380             :         }
    2381             : 
    2382       50447 :         code = pac_blobs_ensure_exists(pac_blobs,
    2383             :                                        PAC_TYPE_LOGON_NAME);
    2384       50447 :         if (code != 0) {
    2385           0 :                 goto done;
    2386             :         }
    2387             : 
    2388       50447 :         code = pac_blobs_ensure_exists(pac_blobs,
    2389             :                                        PAC_TYPE_SRV_CHECKSUM);
    2390       50447 :         if (code != 0) {
    2391           0 :                 goto done;
    2392             :         }
    2393             : 
    2394       50447 :         code = pac_blobs_ensure_exists(pac_blobs,
    2395             :                                        PAC_TYPE_KDC_CHECKSUM);
    2396       50447 :         if (code != 0) {
    2397           0 :                 goto done;
    2398             :         }
    2399             : 
    2400       50447 :         if (!(flags & SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION)) {
    2401       50292 :                 code = pac_blobs_ensure_exists(pac_blobs,
    2402             :                                                PAC_TYPE_REQUESTER_SID);
    2403       50292 :                 if (code != 0) {
    2404           6 :                         code = KRB5KDC_ERR_TGT_REVOKED;
    2405           6 :                         goto done;
    2406             :                 }
    2407             :         }
    2408             : 
    2409       48769 :         code = 0;
    2410             : 
    2411       50517 : done:
    2412       50517 :         talloc_free(tmp_ctx);
    2413             : 
    2414       50517 :         return code;
    2415             : }
    2416             : 
    2417             : /**
    2418             :  * @brief Update a PAC
    2419             :  *
    2420             :  * @param mem_ctx   A talloc memory context
    2421             :  *
    2422             :  * @param context   A krb5 context
    2423             :  *
    2424             :  * @param samdb     An open samdb connection.
    2425             :  *
    2426             :  * @param lp_ctx    A loadparm context.
    2427             :  *
    2428             :  * @param flags     Bitwise OR'ed flags
    2429             :  *
    2430             :  * @param device_pac_is_trusted Whether the device's PAC was issued by a trusted server,
    2431             :  *                              as opposed to an RODC.
    2432             :  *
    2433             :  * @param client    The client samba kdc PAC entry.
    2434             :  *
    2435             :  * @param server_principal  The server principal
    2436             :  *
    2437             :  * @param server    The server samba kdc entry.
    2438             :  *
    2439             :  * @param delegated_proxy_principal The delegated proxy principal used for
    2440             :  *                                  updating the constrained delegation PAC
    2441             :  *                                  buffer.
    2442             :  *
    2443             :  * @param delegated_proxy   The delegated proxy kdc PAC entry.
    2444             :  *
    2445             :  * @param device    The computer's samba kdc PAC entry; used for compound
    2446             :  *                  authentication.
    2447             :  *
    2448             :  * @param new_pac                   The new already allocated PAC
    2449             :  *
    2450             :  * @return A Kerberos error code. If no PAC should be returned, the code will be
    2451             :  * ENOATTR!
    2452             :  */
    2453       48720 : krb5_error_code samba_kdc_update_pac(TALLOC_CTX *mem_ctx,
    2454             :                                      krb5_context context,
    2455             :                                      struct ldb_context *samdb,
    2456             :                                      struct loadparm_context *lp_ctx,
    2457             :                                      uint32_t flags,
    2458             :                                      const struct samba_kdc_entry_pac client,
    2459             :                                      const krb5_const_principal server_principal,
    2460             :                                      const struct samba_kdc_entry *server,
    2461             :                                      const krb5_const_principal delegated_proxy_principal,
    2462             :                                      const struct samba_kdc_entry_pac delegated_proxy,
    2463             :                                      const struct samba_kdc_entry_pac device,
    2464             :                                      krb5_pac new_pac,
    2465             :                                      struct authn_audit_info **server_audit_info_out,
    2466             :                                      NTSTATUS *status_out)
    2467             : {
    2468       48720 :         TALLOC_CTX *tmp_ctx = NULL;
    2469       48720 :         krb5_error_code code = EINVAL;
    2470        1672 :         NTSTATUS nt_status;
    2471       48720 :         DATA_BLOB *pac_blob = NULL;
    2472       48720 :         DATA_BLOB *upn_blob = NULL;
    2473       48720 :         DATA_BLOB *deleg_blob = NULL;
    2474       48720 :         DATA_BLOB *requester_sid_blob = NULL;
    2475       48720 :         const DATA_BLOB *client_claims_blob = NULL;
    2476       48720 :         DATA_BLOB device_claims_blob = {};
    2477       48720 :         const DATA_BLOB *device_claims_blob_ptr = NULL;
    2478       48720 :         struct auth_claims auth_claims = {};
    2479       48720 :         DATA_BLOB *device_info_blob = NULL;
    2480       48720 :         bool is_tgs = false;
    2481       48720 :         bool server_restrictions_present = false;
    2482       48720 :         struct pac_blobs *pac_blobs = NULL;
    2483       48720 :         const struct auth_user_info_dc *user_info_dc_const = NULL;
    2484       48720 :         struct auth_user_info_dc *user_info_dc_shallow_copy = NULL;
    2485       48720 :         const struct PAC_DOMAIN_GROUP_MEMBERSHIP *_resource_groups = NULL;
    2486        1672 :         enum auth_group_inclusion group_inclusion;
    2487        1672 :         bool compounded_auth;
    2488       48720 :         size_t i = 0;
    2489             : 
    2490       48720 :         if (server_audit_info_out != NULL) {
    2491       48720 :                 *server_audit_info_out = NULL;
    2492             :         }
    2493             : 
    2494       48720 :         if (status_out != NULL) {
    2495       48720 :                 *status_out = NT_STATUS_OK;
    2496             :         }
    2497             : 
    2498       48720 :         tmp_ctx = talloc_new(mem_ctx);
    2499       48720 :         if (tmp_ctx == NULL) {
    2500           0 :                 code = ENOMEM;
    2501           0 :                 goto done;
    2502             :         }
    2503             : 
    2504             :         {
    2505       48720 :                 int result = smb_krb5_principal_is_tgs(context, server_principal);
    2506       48720 :                 if (result == -1) {
    2507           0 :                         code = ENOMEM;
    2508           0 :                         goto done;
    2509             :                 }
    2510             : 
    2511       48720 :                 is_tgs = result;
    2512             :         }
    2513             : 
    2514       48720 :         server_restrictions_present = !is_tgs && authn_policy_restrictions_present(server->server_policy);
    2515             : 
    2516             :         /* Only include resource groups in a service ticket. */
    2517       48720 :         if (is_tgs) {
    2518       27059 :                 group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
    2519       20619 :         } else if (server->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
    2520          21 :                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
    2521             :         } else {
    2522       20598 :                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
    2523             :         }
    2524             : 
    2525         281 :         compounded_auth = device.entry != NULL && !is_tgs
    2526       49001 :                 && server->supported_enctypes & KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED;
    2527             : 
    2528       48720 :         if (compounded_auth || (server_restrictions_present && device.entry != NULL)) {
    2529             :                 /*
    2530             :                  * [MS-KILE] 3.3.5.7.4 Compound Identity: the client claims from
    2531             :                  * the device PAC become the device claims in the new PAC.
    2532             :                  */
    2533         211 :                 code = samba_kdc_get_claims_data(tmp_ctx,
    2534             :                                                  context,
    2535             :                                                  samdb,
    2536             :                                                  device,
    2537             :                                                  &auth_claims.device_claims);
    2538         211 :                 if (code) {
    2539           0 :                         goto done;
    2540             :                 }
    2541             : 
    2542         211 :                 if (compounded_auth) {
    2543          73 :                         nt_status = claims_data_encoded_claims_set(tmp_ctx,
    2544             :                                                                    auth_claims.device_claims,
    2545             :                                                                    &device_claims_blob);
    2546          73 :                         if (!NT_STATUS_IS_OK(nt_status)) {
    2547           0 :                                 DBG_ERR("claims_data_encoded_claims_set failed: %s\n",
    2548             :                                         nt_errstr(nt_status));
    2549           0 :                                 code = map_errno_from_nt_status(nt_status);
    2550           0 :                                 goto done;
    2551             :                         }
    2552             : 
    2553          73 :                         device_claims_blob_ptr = &device_claims_blob;
    2554             : 
    2555          73 :                         if (samba_krb5_pac_is_trusted(device)) {
    2556          64 :                                 code = samba_kdc_create_device_info_blob(tmp_ctx,
    2557             :                                                                          context,
    2558             :                                                                          samdb,
    2559          64 :                                                                          device.pac,
    2560             :                                                                          &device_info_blob);
    2561          64 :                                 if (code != 0) {
    2562           0 :                                         goto done;
    2563             :                                 }
    2564             :                         } else {
    2565             :                                 /* Don't trust an RODC‐issued PAC; regenerate the device info. */
    2566           9 :                                 code = samba_kdc_get_device_info_blob(tmp_ctx,
    2567             :                                                                       context,
    2568             :                                                                       samdb,
    2569             :                                                                       device,
    2570             :                                                                       &device_info_blob);
    2571           9 :                                 if (code != 0) {
    2572           0 :                                         goto done;
    2573             :                                 }
    2574             :                         }
    2575             :                 }
    2576             :         }
    2577             : 
    2578       48720 :         if (delegated_proxy_principal != NULL) {
    2579         152 :                 deleg_blob = talloc_zero(tmp_ctx, DATA_BLOB);
    2580         152 :                 if (deleg_blob == NULL) {
    2581           0 :                         code = ENOMEM;
    2582           0 :                         goto done;
    2583             :                 }
    2584             : 
    2585         152 :                 nt_status = samba_kdc_update_delegation_info_blob(
    2586             :                                 deleg_blob,
    2587             :                                 context,
    2588         152 :                                 client.pac,
    2589             :                                 server_principal,
    2590             :                                 delegated_proxy_principal,
    2591             :                                 deleg_blob);
    2592         152 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    2593           0 :                         DBG_ERR("update delegation info blob failed: %s\n",
    2594             :                                 nt_errstr(nt_status));
    2595           0 :                         code = map_errno_from_nt_status(nt_status);
    2596           0 :                         goto done;
    2597             :                 }
    2598             :         }
    2599             : 
    2600             :         /*
    2601             :          * If we are creating a TGT, resource groups from our domain are not to
    2602             :          * be put into the PAC. Instead, we take the resource groups directly
    2603             :          * from the original PAC and copy them unmodified into the new one.
    2604             :          */
    2605       49350 :         code = samba_kdc_get_user_info_dc(tmp_ctx,
    2606             :                                           context,
    2607             :                                           samdb,
    2608             :                                           client,
    2609             :                                           &user_info_dc_const,
    2610             :                                           is_tgs ? &_resource_groups : NULL);
    2611       48720 :         if (code != 0) {
    2612           0 :                 const char *err_str = krb5_get_error_message(context, code);
    2613           0 :                 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
    2614             :                         err_str != NULL ? err_str : "<unknown>");
    2615           0 :                 krb5_free_error_message(context, err_str);
    2616             : 
    2617           0 :                 goto done;
    2618             :         }
    2619             : 
    2620             :         /*
    2621             :          * Enforce the AllowedToAuthenticateTo part of an authentication policy,
    2622             :          * if one is present.
    2623             :          */
    2624       48720 :         if (server_restrictions_present) {
    2625           0 :                 struct samba_kdc_entry_pac auth_entry;
    2626         161 :                 const struct auth_user_info_dc *auth_user_info_dc = NULL;
    2627         161 :                 const struct auth_user_info_dc *device_info = NULL;
    2628             : 
    2629         161 :                 if (delegated_proxy.entry != NULL) {
    2630          34 :                         auth_entry = delegated_proxy;
    2631             : 
    2632          34 :                         code = samba_kdc_get_user_info_dc(tmp_ctx,
    2633             :                                                           context,
    2634             :                                                           samdb,
    2635             :                                                           delegated_proxy,
    2636             :                                                           &auth_user_info_dc,
    2637             :                                                           NULL /* resource_groups_out */);
    2638          34 :                         if (code) {
    2639          63 :                                 goto done;
    2640             :                         }
    2641             :                 } else {
    2642         127 :                         auth_entry = client;
    2643         127 :                         auth_user_info_dc = user_info_dc_const;
    2644             :                 }
    2645             : 
    2646             :                 /* Fetch the user’s claims. */
    2647         161 :                 code = samba_kdc_get_claims_data(tmp_ctx,
    2648             :                                                  context,
    2649             :                                                  samdb,
    2650             :                                                  auth_entry,
    2651             :                                                  &auth_claims.user_claims);
    2652         161 :                 if (code) {
    2653           0 :                         goto done;
    2654             :                 }
    2655             : 
    2656         161 :                 if (device.entry != NULL) {
    2657         146 :                         code = samba_kdc_get_user_info_dc(tmp_ctx,
    2658             :                                                           context,
    2659             :                                                           samdb,
    2660             :                                                           device,
    2661             :                                                           &device_info,
    2662             :                                                           NULL /* resource_groups_out */);
    2663         146 :                         if (code) {
    2664           0 :                                 goto done;
    2665             :                         }
    2666             :                 }
    2667             : 
    2668             :                 /*
    2669             :                  * Allocate the audit info and output status on to the parent
    2670             :                  * mem_ctx, not the temporary context.
    2671             :                  */
    2672         161 :                 code = samba_kdc_allowed_to_authenticate_to(mem_ctx,
    2673             :                                                             samdb,
    2674             :                                                             lp_ctx,
    2675         161 :                                                             auth_entry.entry,
    2676             :                                                             auth_user_info_dc,
    2677             :                                                             device_info,
    2678             :                                                             auth_claims,
    2679             :                                                             server,
    2680             :                                                             server_audit_info_out,
    2681             :                                                             status_out);
    2682         161 :                 if (code) {
    2683          63 :                         goto done;
    2684             :                 }
    2685             :         }
    2686             : 
    2687       48657 :         if (compounded_auth) {
    2688             :                 /* Make a shallow copy of the user_info_dc structure. */
    2689          73 :                 nt_status = authsam_shallow_copy_user_info_dc(tmp_ctx,
    2690             :                                                               user_info_dc_const,
    2691             :                                                               &user_info_dc_shallow_copy);
    2692          73 :                 user_info_dc_const = NULL;
    2693             : 
    2694          73 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    2695           0 :                         DBG_ERR("Failed to copy user_info_dc: %s\n",
    2696             :                                 nt_errstr(nt_status));
    2697             : 
    2698           0 :                         code = KRB5KDC_ERR_TGT_REVOKED;
    2699           0 :                         goto done;
    2700             :                 }
    2701             : 
    2702          73 :                 nt_status = samba_kdc_add_compounded_auth(user_info_dc_shallow_copy);
    2703          73 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    2704           0 :                         DBG_ERR("Failed to add Compounded Authentication: %s\n",
    2705             :                                 nt_errstr(nt_status));
    2706             : 
    2707           0 :                         code = KRB5KDC_ERR_TGT_REVOKED;
    2708           0 :                         goto done;
    2709             :                 }
    2710             : 
    2711             :                 /* We can now set back to the const, it will not be modified */
    2712          73 :                 user_info_dc_const = user_info_dc_shallow_copy;
    2713             :         }
    2714             : 
    2715       48657 :         if (samba_krb5_pac_is_trusted(client)) {
    2716       48541 :                 pac_blob = talloc_zero(tmp_ctx, DATA_BLOB);
    2717       48541 :                 if (pac_blob == NULL) {
    2718           0 :                         code = ENOMEM;
    2719           0 :                         goto done;
    2720             :                 }
    2721             : 
    2722       48541 :                 nt_status = samba_get_logon_info_pac_blob(tmp_ctx,
    2723             :                                                           user_info_dc_const,
    2724             :                                                           _resource_groups,
    2725             :                                                           group_inclusion,
    2726             :                                                           pac_blob);
    2727       48541 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    2728           0 :                         DBG_ERR("samba_get_logon_info_pac_blob failed: %s\n",
    2729             :                                 nt_errstr(nt_status));
    2730             : 
    2731           0 :                         code = map_errno_from_nt_status(nt_status);
    2732           0 :                         goto done;
    2733             :                 }
    2734             : 
    2735             :                 /*
    2736             :                  * TODO: we need claim translation over trusts,
    2737             :                  * for now we just clear them...
    2738             :                  */
    2739       50213 :                 if (samba_kdc_entry_pac_issued_by_trust(client)) {
    2740          59 :                         client_claims_blob = &data_blob_null;
    2741             :                 }
    2742             :         } else {
    2743         116 :                 nt_status = samba_kdc_get_logon_info_blob(tmp_ctx,
    2744             :                                                           user_info_dc_const,
    2745             :                                                           group_inclusion,
    2746             :                                                           &pac_blob);
    2747         116 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    2748           0 :                         DBG_ERR("samba_kdc_get_logon_info_blob failed: %s\n",
    2749             :                                 nt_errstr(nt_status));
    2750           0 :                         code = KRB5KDC_ERR_TGT_REVOKED;
    2751           0 :                         goto done;
    2752             :                 }
    2753             : 
    2754         116 :                 nt_status = samba_kdc_get_upn_info_blob(tmp_ctx,
    2755             :                                                         user_info_dc_const,
    2756             :                                                         &upn_blob);
    2757         116 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    2758           0 :                         DBG_ERR("samba_kdc_get_upn_info_blob failed: %s\n",
    2759             :                                 nt_errstr(nt_status));
    2760           0 :                         code = KRB5KDC_ERR_TGT_REVOKED;
    2761           0 :                         goto done;
    2762             :                 }
    2763             : 
    2764         116 :                 if (is_tgs) {
    2765          18 :                         nt_status = samba_kdc_get_requester_sid_blob(tmp_ctx,
    2766             :                                                                      user_info_dc_const,
    2767             :                                                                      &requester_sid_blob);
    2768          18 :                         if (!NT_STATUS_IS_OK(nt_status)) {
    2769           0 :                                 DBG_ERR("samba_kdc_get_requester_sid_blob failed: %s\n",
    2770             :                                         nt_errstr(nt_status));
    2771           0 :                                 code = KRB5KDC_ERR_TGT_REVOKED;
    2772           0 :                                 goto done;
    2773             :                         }
    2774             :                 }
    2775             : 
    2776             :                 /* Don't trust RODC-issued claims. Regenerate them. */
    2777         116 :                 nt_status = samba_kdc_get_claims_blob(tmp_ctx,
    2778         116 :                                                       client.entry,
    2779             :                                                       &client_claims_blob);
    2780         116 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    2781           0 :                         DBG_ERR("samba_kdc_get_claims_blob failed: %s\n",
    2782             :                                 nt_errstr(nt_status));
    2783           0 :                         code = map_errno_from_nt_status(nt_status);
    2784           0 :                         goto done;
    2785             :                 }
    2786             :         }
    2787             : 
    2788             :         /* Check the types of the given PAC */
    2789       48657 :         code = pac_blobs_from_krb5_pac(tmp_ctx,
    2790             :                                        context,
    2791       46985 :                                        client.pac,
    2792             :                                        &pac_blobs);
    2793       48657 :         if (code != 0) {
    2794           0 :                 goto done;
    2795             :         }
    2796             : 
    2797       48657 :         code = pac_blobs_replace_existing(pac_blobs,
    2798             :                                           PAC_TYPE_LOGON_INFO,
    2799             :                                           pac_blob);
    2800       48657 :         if (code != 0) {
    2801           0 :                 goto done;
    2802             :         }
    2803             : 
    2804             : #ifdef SAMBA4_USES_HEIMDAL
    2805             :         /* Not needed with MIT Kerberos */
    2806       48657 :         code = pac_blobs_replace_existing(pac_blobs,
    2807             :                                           PAC_TYPE_LOGON_NAME,
    2808             :                                           &data_blob_null);
    2809       48657 :         if (code != 0) {
    2810           0 :                 goto done;
    2811             :         }
    2812             : 
    2813       48657 :         code = pac_blobs_replace_existing(pac_blobs,
    2814             :                                           PAC_TYPE_SRV_CHECKSUM,
    2815             :                                           &data_blob_null);
    2816       48657 :         if (code != 0) {
    2817           0 :                 goto done;
    2818             :         }
    2819             : 
    2820       48657 :         code = pac_blobs_replace_existing(pac_blobs,
    2821             :                                           PAC_TYPE_KDC_CHECKSUM,
    2822             :                                           &data_blob_null);
    2823       48657 :         if (code != 0) {
    2824           0 :                 goto done;
    2825             :         }
    2826             : #endif
    2827             : 
    2828       48657 :         code = pac_blobs_add_blob(pac_blobs,
    2829             :                                   PAC_TYPE_CONSTRAINED_DELEGATION,
    2830             :                                   deleg_blob);
    2831       48657 :         if (code != 0) {
    2832           0 :                 goto done;
    2833             :         }
    2834             : 
    2835       48657 :         code = pac_blobs_add_blob(pac_blobs,
    2836             :                                   PAC_TYPE_UPN_DNS_INFO,
    2837             :                                   upn_blob);
    2838       48657 :         if (code != 0) {
    2839           0 :                 goto done;
    2840             :         }
    2841             : 
    2842       48657 :         code = pac_blobs_add_blob(pac_blobs,
    2843             :                                   PAC_TYPE_CLIENT_CLAIMS_INFO,
    2844             :                                   client_claims_blob);
    2845       48657 :         if (code != 0) {
    2846           0 :                 goto done;
    2847             :         }
    2848             : 
    2849       48657 :         code = pac_blobs_add_blob(pac_blobs,
    2850             :                                   PAC_TYPE_DEVICE_INFO,
    2851             :                                   device_info_blob);
    2852       48657 :         if (code != 0) {
    2853           0 :                 goto done;
    2854             :         }
    2855             : 
    2856       48657 :         code = pac_blobs_add_blob(pac_blobs,
    2857             :                                   PAC_TYPE_DEVICE_CLAIMS_INFO,
    2858             :                                   device_claims_blob_ptr);
    2859       48657 :         if (code != 0) {
    2860           0 :                 goto done;
    2861             :         }
    2862             : 
    2863       48657 :         if (!samba_krb5_pac_is_trusted(client) || !is_tgs) {
    2864       20574 :                 pac_blobs_remove_blob(pac_blobs,
    2865             :                                       PAC_TYPE_ATTRIBUTES_INFO);
    2866             :         }
    2867             : 
    2868       48657 :         if (!is_tgs) {
    2869       20556 :                 pac_blobs_remove_blob(pac_blobs,
    2870             :                                       PAC_TYPE_REQUESTER_SID);
    2871             :         }
    2872             : 
    2873       48657 :         code = pac_blobs_add_blob(pac_blobs,
    2874             :                                   PAC_TYPE_REQUESTER_SID,
    2875             :                                   requester_sid_blob);
    2876       48657 :         if (code != 0) {
    2877           0 :                 goto done;
    2878             :         }
    2879             : 
    2880             :         /*
    2881             :          * The server account may be set not to want the PAC.
    2882             :          *
    2883             :          * While this is wasteful if the above calculations were done
    2884             :          * and now thrown away, this is cleaner as we do any ticket
    2885             :          * signature checking etc always.
    2886             :          *
    2887             :          * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
    2888             :          * time (eg not accepting a ticket from the RODC) we do not
    2889             :          * need to re-generate anything anyway.
    2890             :          */
    2891       48657 :         if (!samba_princ_needs_pac(server)) {
    2892           5 :                 code = ENOATTR;
    2893           5 :                 goto done;
    2894             :         }
    2895             : 
    2896       48652 :         if (samba_krb5_pac_is_trusted(client) && !is_tgs) {
    2897             :                 /*
    2898             :                  * The client may have requested no PAC when obtaining the
    2899             :                  * TGT.
    2900             :                  */
    2901       20453 :                 bool requested_pac = false;
    2902             : 
    2903       20453 :                 code = samba_client_requested_pac(context,
    2904       19823 :                                                   client.pac,
    2905             :                                                   tmp_ctx,
    2906             :                                                   &requested_pac);
    2907       20453 :                 if (code != 0 || !requested_pac) {
    2908           6 :                         if (!requested_pac) {
    2909           6 :                                 code = ENOATTR;
    2910             :                         }
    2911           6 :                         goto done;
    2912             :                 }
    2913             :         }
    2914             : 
    2915      397329 :         for (i = 0; i < pac_blobs->num_types; ++i) {
    2916       12116 :                 krb5_data type_data;
    2917      348683 :                 const DATA_BLOB *type_blob = pac_blobs->type_blobs[i].data;
    2918      348683 :                 uint32_t type = pac_blobs->type_blobs[i].type;
    2919             : 
    2920       12116 :                 static char null_byte = '\0';
    2921      348683 :                 const krb5_data null_data = smb_krb5_make_data(&null_byte, 0);
    2922             : 
    2923             : #ifndef SAMBA4_USES_HEIMDAL
    2924             :                 /* Not needed with MIT Kerberos */
    2925           0 :                 switch(type) {
    2926           0 :                 case PAC_TYPE_LOGON_NAME:
    2927             :                 case PAC_TYPE_SRV_CHECKSUM:
    2928             :                 case PAC_TYPE_KDC_CHECKSUM:
    2929             :                 case PAC_TYPE_FULL_CHECKSUM:
    2930           0 :                         continue;
    2931           0 :                 default:
    2932           0 :                         break;
    2933             :                 }
    2934             : #endif
    2935             : 
    2936      348683 :                 if (type_blob != NULL) {
    2937      195176 :                         type_data = smb_krb5_data_from_blob(*type_blob);
    2938             :                         /*
    2939             :                          * Passing a NULL pointer into krb5_pac_add_buffer() is
    2940             :                          * not allowed, so pass null_data instead if needed.
    2941             :                          */
    2942      195176 :                         code = krb5_pac_add_buffer(context,
    2943             :                                                    new_pac,
    2944             :                                                    type,
    2945      195176 :                                                    (type_data.data != NULL) ? &type_data : &null_data);
    2946      195176 :                         if (code != 0) {
    2947           0 :                                 goto done;
    2948             :                         }
    2949      153507 :                 } else if (samba_krb5_pac_is_trusted(client)) {
    2950             :                         /*
    2951             :                          * Convey the buffer from the original PAC if we can
    2952             :                          * trust it.
    2953             :                          */
    2954             : 
    2955      153482 :                         code = krb5_pac_get_buffer(context,
    2956      148054 :                                                    client.pac,
    2957             :                                                    type,
    2958             :                                                    &type_data);
    2959      153482 :                         if (code != 0) {
    2960           0 :                                 goto done;
    2961             :                         }
    2962             :                         /*
    2963             :                          * Passing a NULL pointer into krb5_pac_add_buffer() is
    2964             :                          * not allowed, so pass null_data instead if needed.
    2965             :                          */
    2966      153482 :                         code = krb5_pac_add_buffer(context,
    2967             :                                                    new_pac,
    2968             :                                                    type,
    2969      153482 :                                                    (type_data.data != NULL) ? &type_data : &null_data);
    2970      153482 :                         smb_krb5_free_data_contents(context, &type_data);
    2971      153482 :                         if (code != 0) {
    2972           0 :                                 goto done;
    2973             :                         }
    2974             :                 }
    2975             :         }
    2976             : 
    2977       46974 :         code = 0;
    2978       48720 : done:
    2979       48720 :         TALLOC_FREE(tmp_ctx);
    2980       48720 :         return code;
    2981             : }
    2982             : 
    2983         999 : krb5_error_code samba_kdc_get_claims_data(TALLOC_CTX *mem_ctx,
    2984             :                                           krb5_context context,
    2985             :                                           struct ldb_context *samdb,
    2986             :                                           struct samba_kdc_entry_pac entry,
    2987             :                                           struct claims_data **claims_data_out)
    2988             : {
    2989         999 :         if (samba_kdc_entry_pac_issued_by_trust(entry)) {
    2990           0 :                 NTSTATUS status;
    2991             : 
    2992             :                 /*
    2993             :                  * TODO: we need claim translation over trusts; for now we just
    2994             :                  * clear them…
    2995             :                  */
    2996           0 :                 status = claims_data_from_encoded_claims_set(mem_ctx,
    2997             :                                                              NULL,
    2998             :                                                              claims_data_out);
    2999           0 :                 if (!NT_STATUS_IS_OK(status)) {
    3000           0 :                         return map_errno_from_nt_status(status);
    3001             :                 }
    3002             : 
    3003           0 :                 return 0;
    3004             :         }
    3005             : 
    3006         999 :         if (samba_krb5_pac_is_trusted(entry)) {
    3007         931 :                 return samba_kdc_get_claims_data_from_pac(mem_ctx,
    3008             :                                                           context,
    3009             :                                                           entry,
    3010             :                                                           claims_data_out);
    3011             :         }
    3012             : 
    3013          68 :         return samba_kdc_get_claims_data_from_db(samdb,
    3014             :                                                  entry.entry,
    3015             :                                                  claims_data_out);
    3016             : }
    3017             : 
    3018         931 : krb5_error_code samba_kdc_get_claims_data_from_pac(TALLOC_CTX *mem_ctx,
    3019             :                                                    krb5_context context,
    3020             :                                                    struct samba_kdc_entry_pac entry,
    3021             :                                                    struct claims_data **claims_data_out)
    3022             : {
    3023         931 :         TALLOC_CTX *frame = NULL;
    3024         931 :         krb5_data claims_info = {};
    3025         931 :         struct claims_data *claims_data = NULL;
    3026         931 :         NTSTATUS status = NT_STATUS_OK;
    3027           0 :         krb5_error_code code;
    3028             : 
    3029         931 :         if (!samba_krb5_pac_is_trusted(entry)) {
    3030           0 :                 code = EINVAL;
    3031           0 :                 goto out;
    3032             :         }
    3033             : 
    3034         931 :         if (samba_kdc_entry_pac_issued_by_trust(entry)) {
    3035           0 :                 code = EINVAL;
    3036           0 :                 goto out;
    3037             :         }
    3038             : 
    3039         931 :         if (claims_data_out == NULL) {
    3040           0 :                 code = EINVAL;
    3041           0 :                 goto out;
    3042             :         }
    3043             : 
    3044         931 :         *claims_data_out = NULL;
    3045             : 
    3046         931 :         if (entry.entry != NULL && entry.entry->claims_from_pac_are_initialized) {
    3047             :                 /* Note: the caller does not own this! */
    3048          30 :                 *claims_data_out = entry.entry->claims_from_pac;
    3049          30 :                 return 0;
    3050             :         }
    3051             : 
    3052         901 :         frame = talloc_stackframe();
    3053             : 
    3054             :         /* Fetch the claims from the PAC. */
    3055         901 :         code = krb5_pac_get_buffer(context, entry.pac,
    3056             :                                    PAC_TYPE_CLIENT_CLAIMS_INFO,
    3057             :                                    &claims_info);
    3058         901 :         if (code == ENOENT) {
    3059             :                 /* OK. */
    3060         901 :         } else if (code != 0) {
    3061           0 :                 DBG_ERR("Error getting CLIENT_CLAIMS_INFO from PAC\n");
    3062           0 :                 goto out;
    3063         901 :         } else if (claims_info.length) {
    3064         341 :                 DATA_BLOB claims_blob = data_blob_const(claims_info.data,
    3065           0 :                                                         claims_info.length);
    3066             : 
    3067         341 :                 status = claims_data_from_encoded_claims_set(frame,
    3068             :                                                              &claims_blob,
    3069             :                                                              &claims_data);
    3070         341 :                 if (!NT_STATUS_IS_OK(status)) {
    3071           0 :                         code = map_errno_from_nt_status(status);
    3072           0 :                         goto out;
    3073             :                 }
    3074             :         }
    3075             : 
    3076         901 :         if (entry.entry != NULL) {
    3077             :                 /* Note: the caller does not own this! */
    3078         901 :                 entry.entry->claims_from_pac = talloc_steal(entry.entry,
    3079             :                                                             claims_data);
    3080         901 :                 entry.entry->claims_from_pac_are_initialized = true;
    3081             :         } else {
    3082           0 :                 talloc_steal(mem_ctx, claims_data);
    3083             :         }
    3084             : 
    3085         901 :         *claims_data_out = claims_data;
    3086             : 
    3087         901 : out:
    3088         901 :         smb_krb5_free_data_contents(context, &claims_info);
    3089         901 :         talloc_free(frame);
    3090         901 :         return code;
    3091             : }
    3092             : 
    3093       30495 : krb5_error_code samba_kdc_get_claims_data_from_db(struct ldb_context *samdb,
    3094             :                                                   struct samba_kdc_entry *entry,
    3095             :                                                   struct claims_data **claims_data_out)
    3096             : {
    3097       30495 :         TALLOC_CTX *frame = NULL;
    3098             : 
    3099       30495 :         struct claims_data *claims_data = NULL;
    3100       30495 :         struct CLAIMS_SET *claims_set = NULL;
    3101       30495 :         NTSTATUS status = NT_STATUS_OK;
    3102        1184 :         krb5_error_code code;
    3103             : 
    3104       30495 :         if (samdb == NULL) {
    3105           0 :                 code = EINVAL;
    3106           0 :                 goto out;
    3107             :         }
    3108             : 
    3109       30495 :         if (claims_data_out == NULL) {
    3110           0 :                 code = EINVAL;
    3111           0 :                 goto out;
    3112             :         }
    3113             : 
    3114       30495 :         if (entry == NULL) {
    3115           0 :                 code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    3116           0 :                 goto out;
    3117             :         }
    3118             : 
    3119       30495 :         *claims_data_out = NULL;
    3120             : 
    3121       30495 :         if (entry->claims_from_db_are_initialized) {
    3122             :                 /* Note: the caller does not own this! */
    3123          14 :                 *claims_data_out = entry->claims_from_db;
    3124          14 :                 return 0;
    3125             :         }
    3126             : 
    3127       30481 :         frame = talloc_stackframe();
    3128             : 
    3129       31665 :         code = get_claims_set_for_principal(samdb,
    3130             :                                             frame,
    3131       30481 :                                             entry->msg,
    3132             :                                             &claims_set);
    3133       30481 :         if (code) {
    3134           0 :                 DBG_ERR("Failed to fetch claims\n");
    3135           0 :                 goto out;
    3136             :         }
    3137             : 
    3138       30481 :         if (claims_set != NULL) {
    3139         324 :                 status = claims_data_from_claims_set(claims_data,
    3140             :                                                      claims_set,
    3141             :                                                      &claims_data);
    3142         324 :                 if (!NT_STATUS_IS_OK(status)) {
    3143           0 :                         code = map_errno_from_nt_status(status);
    3144           0 :                         goto out;
    3145             :                 }
    3146             :         }
    3147             : 
    3148       30481 :         entry->claims_from_db = talloc_steal(entry,
    3149             :                                              claims_data);
    3150       30481 :         entry->claims_from_db_are_initialized = true;
    3151             : 
    3152             :         /* Note: the caller does not own this! */
    3153       30481 :         *claims_data_out = entry->claims_from_db;
    3154             : 
    3155       30481 : out:
    3156       30481 :         talloc_free(frame);
    3157       30481 :         return code;
    3158             : }
    3159             : 
    3160       48569 : krb5_error_code samba_kdc_check_device(TALLOC_CTX *mem_ctx,
    3161             :                                        krb5_context context,
    3162             :                                        struct ldb_context *samdb,
    3163             :                                        struct loadparm_context *lp_ctx,
    3164             :                                        const struct samba_kdc_entry_pac device,
    3165             :                                        const struct authn_kerberos_client_policy *client_policy,
    3166             :                                        struct authn_audit_info **client_audit_info_out,
    3167             :                                        NTSTATUS *status_out)
    3168             : {
    3169       48569 :         TALLOC_CTX *frame = NULL;
    3170       48569 :         krb5_error_code code = 0;
    3171        1776 :         NTSTATUS nt_status;
    3172       48569 :         const struct auth_user_info_dc *device_info = NULL;
    3173       48569 :         struct authn_audit_info *client_audit_info = NULL;
    3174       48569 :         struct auth_claims auth_claims = {};
    3175             : 
    3176       48569 :         if (status_out != NULL) {
    3177       48569 :                 *status_out = NT_STATUS_OK;
    3178             :         }
    3179             : 
    3180       48569 :         if (!authn_policy_device_restrictions_present(client_policy)) {
    3181       46396 :                 return 0;
    3182             :         }
    3183             : 
    3184         397 :         if (device.entry == NULL || device.pac == NULL) {
    3185           3 :                 NTSTATUS out_status = NT_STATUS_INVALID_WORKSTATION;
    3186             : 
    3187           3 :                 nt_status = authn_kerberos_client_policy_audit_info(mem_ctx,
    3188             :                                                                     client_policy,
    3189             :                                                                     NULL /* client_info */,
    3190             :                                                                     AUTHN_AUDIT_EVENT_KERBEROS_DEVICE_RESTRICTION,
    3191             :                                                                     AUTHN_AUDIT_REASON_FAST_REQUIRED,
    3192             :                                                                     out_status,
    3193             :                                                                     client_audit_info_out);
    3194           3 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    3195           0 :                         code = KRB5KRB_ERR_GENERIC;
    3196           3 :                 } else if (authn_kerberos_client_policy_is_enforced(client_policy)) {
    3197           2 :                         code = KRB5KDC_ERR_POLICY;
    3198             : 
    3199           2 :                         if (status_out != NULL) {
    3200           2 :                                 *status_out = out_status;
    3201             :                         }
    3202             :                 } else {
    3203             :                         /* OK. */
    3204           1 :                         code = 0;
    3205             :                 }
    3206             : 
    3207           3 :                 goto out;
    3208             :         }
    3209             : 
    3210         394 :         frame = talloc_stackframe();
    3211             : 
    3212         394 :         code = samba_kdc_get_user_info_dc(frame,
    3213             :                                           context,
    3214             :                                           samdb,
    3215             :                                           device,
    3216             :                                           &device_info,
    3217             :                                           NULL);
    3218         394 :         if (code) {
    3219           0 :                 goto out;
    3220             :         }
    3221             : 
    3222             :         /*
    3223             :          * The device claims become the *user* claims for the purpose of
    3224             :          * evaluating a conditional ACE expression.
    3225             :          */
    3226         394 :         code = samba_kdc_get_claims_data(frame,
    3227             :                                          context,
    3228             :                                          samdb,
    3229             :                                          device,
    3230             :                                          &auth_claims.user_claims);
    3231         394 :         if (code) {
    3232           0 :                 goto out;
    3233             :         }
    3234             : 
    3235         394 :         nt_status = authn_policy_authenticate_from_device(frame,
    3236             :                                                           samdb,
    3237             :                                                           lp_ctx,
    3238             :                                                           device_info,
    3239             :                                                           auth_claims,
    3240             :                                                           client_policy,
    3241             :                                                           &client_audit_info);
    3242         394 :         if (client_audit_info != NULL) {
    3243         394 :                 *client_audit_info_out = talloc_move(mem_ctx, &client_audit_info);
    3244             :         }
    3245         394 :         if (!NT_STATUS_IS_OK(nt_status)) {
    3246         260 :                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED)) {
    3247         242 :                         code = KRB5KDC_ERR_POLICY;
    3248             :                 } else {
    3249          18 :                         code = KRB5KRB_ERR_GENERIC;
    3250             :                 }
    3251             : 
    3252         260 :                 goto out;
    3253             :         }
    3254             : 
    3255         134 : out:
    3256         397 :         talloc_free(frame);
    3257         397 :         return code;
    3258             : }

Generated by: LCOV version 1.14