LCOV - code coverage report
Current view: top level - source4/kdc - wdc-samba4.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 348 421 82.7 %
Date: 2024-04-21 15:09:00 Functions: 11 12 91.7 %

          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 "includes.h"
      25             : #include "kdc/authn_policy_util.h"
      26             : #include "kdc/kdc-glue.h"
      27             : #include "kdc/db-glue.h"
      28             : #include "kdc/pac-glue.h"
      29             : #include "sdb.h"
      30             : #include "sdb_hdb.h"
      31             : #include "librpc/gen_ndr/auth.h"
      32             : #include <krb5_locl.h>
      33             : #include "lib/replace/system/filesys.h"
      34             : 
      35             : #undef DBGC_CLASS
      36             : #define DBGC_CLASS DBGC_KERBEROS
      37             : 
      38       81506 : static bool samba_wdc_is_s4u2self_req(astgs_request_t r)
      39             : {
      40       81506 :         const KDC_REQ *req = kdc_request_get_req(r);
      41       81506 :         const PA_DATA *pa_for_user = NULL;
      42             : 
      43       81506 :         if (req->msg_type != krb_tgs_req) {
      44       29600 :                 return false;
      45             :         }
      46             : 
      47       50736 :         if (req->padata != NULL) {
      48       50736 :                 int idx = 0;
      49             : 
      50       50736 :                 pa_for_user = krb5_find_padata(req->padata->val,
      51       49078 :                                                req->padata->len,
      52             :                                                KRB5_PADATA_FOR_USER,
      53             :                                                &idx);
      54             :         }
      55             : 
      56       50736 :         if (pa_for_user != NULL) {
      57        1330 :                 return true;
      58             :         }
      59             : 
      60       47748 :         return false;
      61             : }
      62             : 
      63             : /*
      64             :  * Given the right private pointer from hdb_samba4,
      65             :  * get a PAC from the attached ldb messages.
      66             :  *
      67             :  * For PKINIT we also get pk_reply_key and can add PAC_CREDENTIAL_INFO.
      68             :  */
      69       30956 : static krb5_error_code samba_wdc_get_pac(void *priv,
      70             :                                          astgs_request_t r,
      71             :                                          hdb_entry *client,
      72             :                                          hdb_entry *server,
      73             :                                          const krb5_keyblock *pk_reply_key,
      74             :                                          uint64_t pac_attributes,
      75             :                                          krb5_pac *pac)
      76             : {
      77       30956 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
      78        1170 :         TALLOC_CTX *mem_ctx;
      79       30956 :         DATA_BLOB *logon_blob = NULL;
      80       30956 :         DATA_BLOB *cred_ndr = NULL;
      81       30956 :         DATA_BLOB **cred_ndr_ptr = NULL;
      82       30956 :         DATA_BLOB _cred_blob = data_blob_null;
      83       30956 :         DATA_BLOB *cred_blob = NULL;
      84       30956 :         DATA_BLOB *upn_blob = NULL;
      85       30956 :         DATA_BLOB *pac_attrs_blob = NULL;
      86       30956 :         DATA_BLOB *requester_sid_blob = NULL;
      87       30956 :         DATA_BLOB client_claims_blob = {};
      88        1170 :         krb5_error_code ret;
      89        1170 :         NTSTATUS nt_status;
      90        1170 :         struct samba_kdc_entry *skdc_entry =
      91       30956 :                 talloc_get_type_abort(client->context,
      92             :                 struct samba_kdc_entry);
      93        1170 :         const struct samba_kdc_entry *server_entry =
      94       30956 :                 talloc_get_type_abort(server->context,
      95             :                 struct samba_kdc_entry);
      96       30956 :         bool is_krbtgt = krb5_principal_is_krbtgt(context, server->principal);
      97        1170 :         enum auth_group_inclusion group_inclusion;
      98       30956 :         bool is_s4u2self = samba_wdc_is_s4u2self_req(r);
      99       32126 :         enum samba_asserted_identity asserted_identity =
     100             :                 (is_s4u2self) ?
     101       30956 :                         SAMBA_ASSERTED_IDENTITY_SERVICE :
     102             :                         SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
     103       30956 :         struct authn_audit_info *server_audit_info = NULL;
     104       30956 :         NTSTATUS reply_status = NT_STATUS_OK;
     105             : 
     106       30956 :         const struct auth_user_info_dc *user_info_dc_const = NULL;
     107       30956 :         struct auth_user_info_dc *user_info_dc_shallow_copy = NULL;
     108       30956 :         struct auth_claims auth_claims = {};
     109             : 
     110             :         /* Only include resource groups in a service ticket. */
     111       30956 :         if (is_krbtgt) {
     112       26553 :                 group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
     113        3233 :         } else if (server_entry->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
     114           4 :                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
     115             :         } else {
     116        3229 :                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
     117             :         }
     118             : 
     119       30956 :         mem_ctx = talloc_named(client->context, 0, "samba_wdc_get_pac context");
     120       30956 :         if (!mem_ctx) {
     121           0 :                 return ENOMEM;
     122             :         }
     123             : 
     124       30956 :         if (pk_reply_key != NULL) {
     125          45 :                 cred_ndr_ptr = &cred_ndr;
     126             :         }
     127             : 
     128       32126 :         ret = samba_kdc_get_user_info_from_db(mem_ctx,
     129       30956 :                                               server_entry->kdc_db_ctx->samdb,
     130             :                                               skdc_entry,
     131       30956 :                                               skdc_entry->msg,
     132             :                                               &user_info_dc_const);
     133       30956 :         if (ret) {
     134           0 :                 talloc_free(mem_ctx);
     135           0 :                 return ret;
     136             :         }
     137             : 
     138             :         /* Make a shallow copy of the user_info_dc structure. */
     139       30956 :         nt_status = authsam_shallow_copy_user_info_dc(mem_ctx,
     140             :                                                       user_info_dc_const,
     141             :                                                       &user_info_dc_shallow_copy);
     142       30956 :         user_info_dc_const = NULL;
     143             : 
     144       30956 :         if (!NT_STATUS_IS_OK(nt_status)) {
     145           0 :                 DBG_ERR("Failed to allocate user_info_dc SIDs: %s\n",
     146             :                         nt_errstr(nt_status));
     147           0 :                 talloc_free(mem_ctx);
     148           0 :                 return map_errno_from_nt_status(nt_status);
     149             :         }
     150             : 
     151       30956 :         nt_status = samba_kdc_add_asserted_identity(asserted_identity,
     152             :                                                     user_info_dc_shallow_copy);
     153       30956 :         if (!NT_STATUS_IS_OK(nt_status)) {
     154           0 :                 DBG_ERR("Failed to add asserted identity: %s\n",
     155             :                         nt_errstr(nt_status));
     156           0 :                 talloc_free(mem_ctx);
     157           0 :                 return map_errno_from_nt_status(nt_status);
     158             :         }
     159             : 
     160       30956 :         nt_status = samba_kdc_add_claims_valid(user_info_dc_shallow_copy);
     161       30956 :         if (!NT_STATUS_IS_OK(nt_status)) {
     162           0 :                 DBG_ERR("Failed to add Claims Valid: %s\n",
     163             :                         nt_errstr(nt_status));
     164           0 :                 talloc_free(mem_ctx);
     165           0 :                 return map_errno_from_nt_status(nt_status);
     166             :         }
     167             : 
     168       30956 :         if (kdc_request_get_pkinit_freshness_used(r)) {
     169           8 :                 nt_status = samba_kdc_add_fresh_public_key_identity(user_info_dc_shallow_copy);
     170           8 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     171           0 :                         DBG_ERR("Failed to add Fresh Public Key Identity: %s\n",
     172             :                                 nt_errstr(nt_status));
     173           0 :                         talloc_free(mem_ctx);
     174           0 :                         return map_errno_from_nt_status(nt_status);
     175             :                 }
     176             :         }
     177             : 
     178       30956 :         ret = samba_kdc_get_claims_data_from_db(server_entry->kdc_db_ctx->samdb,
     179             :                                                 skdc_entry,
     180             :                                                 &auth_claims.user_claims);
     181       30956 :         if (ret) {
     182           0 :                 talloc_free(mem_ctx);
     183           0 :                 return ret;
     184             :         }
     185             : 
     186       30956 :         nt_status = claims_data_encoded_claims_set(mem_ctx,
     187             :                                                    auth_claims.user_claims,
     188             :                                                    &client_claims_blob);
     189       30956 :         if (!NT_STATUS_IS_OK(nt_status)) {
     190           0 :                 talloc_free(mem_ctx);
     191           0 :                 return map_errno_from_nt_status(nt_status);
     192             :         }
     193             : 
     194             :         /*
     195             :          * For an S4U2Self request, the authentication policy is not enforced.
     196             :          */
     197       30956 :         if (!is_s4u2self && authn_policy_restrictions_present(server_entry->server_policy)) {
     198           9 :                 const hdb_entry *device = kdc_request_get_armor_client(r);
     199           9 :                 const struct auth_user_info_dc *device_info = NULL;
     200             : 
     201           9 :                 if (device != NULL) {
     202           7 :                         const hdb_entry *device_krbtgt = NULL;
     203           7 :                         struct samba_kdc_entry *device_skdc_entry = NULL;
     204           7 :                         const struct samba_kdc_entry *device_krbtgt_skdc_entry = NULL;
     205           7 :                         const krb5_const_pac device_pac = kdc_request_get_armor_pac(r);
     206           7 :                         struct samba_kdc_entry_pac device_pac_entry = {};
     207             : 
     208           7 :                         device_skdc_entry = talloc_get_type_abort(device->context,
     209             :                                                                   struct samba_kdc_entry);
     210             : 
     211           7 :                         device_krbtgt = kdc_request_get_armor_server(r);
     212           7 :                         if (device_krbtgt != NULL) {
     213           7 :                                 device_krbtgt_skdc_entry = talloc_get_type_abort(device_krbtgt->context,
     214             :                                                                                  struct samba_kdc_entry);
     215             :                         }
     216             : 
     217           7 :                         device_pac_entry = samba_kdc_entry_pac(device_pac,
     218             :                                                                device_skdc_entry,
     219           7 :                                                                samba_kdc_entry_is_trust(device_krbtgt_skdc_entry));
     220             : 
     221           7 :                         ret = samba_kdc_get_user_info_dc(mem_ctx,
     222             :                                                          context,
     223           7 :                                                          server_entry->kdc_db_ctx->samdb,
     224             :                                                          device_pac_entry,
     225             :                                                          &device_info,
     226             :                                                          NULL /* resource_groups_out */);
     227           7 :                         if (ret) {
     228           0 :                                 talloc_free(mem_ctx);
     229           0 :                                 return ret;
     230             :                         }
     231             : 
     232           7 :                         ret = samba_kdc_get_claims_data(mem_ctx,
     233             :                                                         context,
     234           7 :                                                         server_entry->kdc_db_ctx->samdb,
     235             :                                                         device_pac_entry,
     236             :                                                         &auth_claims.device_claims);
     237           7 :                         if (ret) {
     238           0 :                                 talloc_free(mem_ctx);
     239           0 :                                 return ret;
     240             :                         }
     241             :                 }
     242             : 
     243           9 :                 ret = samba_kdc_allowed_to_authenticate_to(mem_ctx,
     244           9 :                                                            server_entry->kdc_db_ctx->samdb,
     245           9 :                                                            server_entry->kdc_db_ctx->lp_ctx,
     246             :                                                            skdc_entry,
     247             :                                                            user_info_dc_shallow_copy,
     248             :                                                            device_info,
     249             :                                                            auth_claims,
     250             :                                                            server_entry,
     251             :                                                            &server_audit_info,
     252             :                                                            &reply_status);
     253           9 :                 if (server_audit_info != NULL) {
     254           0 :                         krb5_error_code ret2;
     255             : 
     256           9 :                         ret2 = hdb_samba4_set_steal_server_audit_info(r, server_audit_info);
     257           9 :                         if (ret == 0) {
     258           5 :                                 ret = ret2;
     259             :                         }
     260             :                 }
     261           9 :                 if (!NT_STATUS_IS_OK(reply_status)) {
     262           0 :                         krb5_error_code ret2;
     263             : 
     264           4 :                         ret2 = hdb_samba4_set_ntstatus(r, reply_status, ret);
     265           4 :                         if (ret == 0) {
     266           0 :                                 ret = ret2;
     267             :                         }
     268             :                 }
     269           9 :                 if (ret) {
     270           4 :                         talloc_free(mem_ctx);
     271           4 :                         return ret;
     272             :                 }
     273             :         }
     274             : 
     275       30952 :         nt_status = samba_kdc_get_logon_info_blob(mem_ctx,
     276             :                                                   user_info_dc_shallow_copy,
     277             :                                                   group_inclusion,
     278             :                                                   &logon_blob);
     279       30952 :         if (!NT_STATUS_IS_OK(nt_status)) {
     280           0 :                 talloc_free(mem_ctx);
     281           0 :                 return map_errno_from_nt_status(nt_status);
     282             :         }
     283             : 
     284       30952 :         if (cred_ndr_ptr != NULL) {
     285          45 :                 nt_status = samba_kdc_get_cred_ndr_blob(mem_ctx,
     286             :                                                         skdc_entry,
     287             :                                                         cred_ndr_ptr);
     288          45 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     289           0 :                         talloc_free(mem_ctx);
     290           0 :                         return map_errno_from_nt_status(nt_status);
     291             :                 }
     292             :         }
     293             : 
     294       30952 :         nt_status = samba_kdc_get_upn_info_blob(mem_ctx,
     295             :                                                 user_info_dc_shallow_copy,
     296             :                                                 &upn_blob);
     297       30952 :         if (!NT_STATUS_IS_OK(nt_status)) {
     298           0 :                 talloc_free(mem_ctx);
     299           0 :                 return map_errno_from_nt_status(nt_status);
     300             :         }
     301             : 
     302       30952 :         if (is_krbtgt) {
     303       27723 :                 nt_status = samba_kdc_get_pac_attrs_blob(mem_ctx,
     304             :                                                          pac_attributes,
     305             :                                                          &pac_attrs_blob);
     306       27723 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     307           0 :                         talloc_free(mem_ctx);
     308           0 :                         return map_errno_from_nt_status(nt_status);
     309             :                 }
     310             : 
     311       27723 :                 nt_status = samba_kdc_get_requester_sid_blob(mem_ctx,
     312             :                                                              user_info_dc_shallow_copy,
     313             :                                                              &requester_sid_blob);
     314       27723 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     315           0 :                         talloc_free(mem_ctx);
     316           0 :                         return map_errno_from_nt_status(nt_status);
     317             :                 }
     318             :         }
     319             : 
     320       30952 :         if (pk_reply_key != NULL && cred_ndr != NULL) {
     321          45 :                 ret = samba_kdc_encrypt_pac_credentials(context,
     322             :                                                         pk_reply_key,
     323             :                                                         cred_ndr,
     324             :                                                         mem_ctx,
     325             :                                                         &_cred_blob);
     326          45 :                 if (ret != 0) {
     327           0 :                         talloc_free(mem_ctx);
     328           0 :                         return ret;
     329             :                 }
     330          45 :                 cred_blob = &_cred_blob;
     331             :         }
     332             : 
     333       30952 :         ret = krb5_pac_init(context, pac);
     334       30952 :         if (ret != 0) {
     335           0 :                 talloc_free(mem_ctx);
     336           0 :                 return ret;
     337             :         }
     338             : 
     339       30952 :         ret = samba_make_krb5_pac(context, logon_blob, cred_blob,
     340             :                                   upn_blob, pac_attrs_blob,
     341             :                                   requester_sid_blob, NULL,
     342             :                                   &client_claims_blob, NULL, NULL,
     343             :                                   *pac);
     344             : 
     345       30952 :         talloc_free(mem_ctx);
     346       30952 :         return ret;
     347             : }
     348             : 
     349       50550 : static krb5_error_code samba_wdc_verify_pac2(astgs_request_t r,
     350             :                                              const hdb_entry *delegated_proxy,
     351             :                                              const hdb_entry *client,
     352             :                                              const hdb_entry *krbtgt,
     353             :                                              const krb5_pac pac,
     354             :                                              krb5_cksumtype ctype)
     355             : {
     356       50550 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
     357       50550 :         struct samba_kdc_entry *client_skdc_entry = NULL;
     358        1658 :         struct samba_kdc_entry *krbtgt_skdc_entry =
     359       50550 :                 talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry);
     360       50550 :         struct samba_kdc_entry_pac client_pac_entry = {};
     361       50550 :         TALLOC_CTX *mem_ctx = NULL;
     362        1658 :         krb5_error_code ret;
     363       50550 :         bool is_s4u2self = samba_wdc_is_s4u2self_req(r);
     364       50550 :         bool is_in_db = false;
     365       50550 :         bool is_trusted = false;
     366       50550 :         uint32_t flags = 0;
     367             : 
     368       50550 :         if (pac == NULL) {
     369           0 :                 return EINVAL;
     370             :         }
     371             : 
     372       50550 :         mem_ctx = talloc_named(NULL, 0, "samba_wdc_verify_pac2 context");
     373       50550 :         if (mem_ctx == NULL) {
     374           0 :                 return ENOMEM;
     375             :         }
     376             : 
     377       50550 :         if (client != NULL) {
     378       50498 :                 client_skdc_entry = talloc_get_type_abort(client->context,
     379             :                                                           struct samba_kdc_entry);
     380             :         }
     381             : 
     382             :         /*
     383             :          * If the krbtgt was generated by an RODC, and we are not that
     384             :          * RODC, then we need to regenerate the PAC - we can't trust
     385             :          * it, and confirm that the RODC was permitted to print this ticket
     386             :          *
     387             :          * Because of the samba_kdc_validate_pac_blob() step we can be
     388             :          * sure that the record in 'client' matches the SID in the
     389             :          * original PAC.
     390             :          */
     391       50550 :         ret = samba_krbtgt_is_in_db(krbtgt_skdc_entry, &is_in_db, &is_trusted);
     392       50550 :         if (ret != 0) {
     393           0 :                 goto out;
     394             :         }
     395             : 
     396       50550 :         krb5_pac_set_trusted(pac, is_trusted);
     397       50550 :         client_pac_entry = samba_kdc_entry_pac(pac,
     398             :                                                client_skdc_entry,
     399       50550 :                                                samba_kdc_entry_is_trust(krbtgt_skdc_entry));
     400             : 
     401       50550 :         if (is_s4u2self) {
     402         678 :                 flags |= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION;
     403             :         }
     404             : 
     405       50550 :         if (delegated_proxy != NULL) {
     406           0 :                 krb5_enctype etype;
     407         196 :                 Key *key = NULL;
     408             : 
     409         196 :                 if (!is_in_db) {
     410             :                         /*
     411             :                          * The RODC-issued PAC was signed by a KDC entry that we
     412             :                          * don't have a key for. The server signature is not
     413             :                          * trustworthy, since it could have been created by the
     414             :                          * server we got the ticket from. We must not proceed as
     415             :                          * otherwise the ticket signature is unchecked.
     416             :                          */
     417           0 :                         ret = HDB_ERR_NOT_FOUND_HERE;
     418          41 :                         goto out;
     419             :                 }
     420             : 
     421             :                 /* Fetch the correct key depending on the checksum type. */
     422         196 :                 if (ctype == CKSUMTYPE_HMAC_MD5) {
     423          41 :                         etype = ENCTYPE_ARCFOUR_HMAC;
     424             :                 } else {
     425         155 :                         ret = krb5_cksumtype_to_enctype(context,
     426             :                                                         ctype,
     427             :                                                         &etype);
     428         155 :                         if (ret != 0) {
     429           6 :                                 goto out;
     430             :                         }
     431             :                 }
     432         190 :                 ret = hdb_enctype2key(context, krbtgt, NULL, etype, &key);
     433         190 :                 if (ret != 0) {
     434           2 :                         goto out;
     435             :                 }
     436             : 
     437             :                 /* Check the KDC, whole-PAC and ticket signatures. */
     438         188 :                 ret = krb5_pac_verify(context,
     439             :                                       pac,
     440             :                                       0,
     441             :                                       NULL,
     442             :                                       NULL,
     443         188 :                                       &key->key);
     444         188 :                 if (ret != 0) {
     445          33 :                         DBG_WARNING("PAC KDC signature failed to verify\n");
     446          33 :                         goto out;
     447             :                 }
     448             : 
     449         155 :                 flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
     450             :         }
     451             : 
     452       52167 :         ret = samba_kdc_verify_pac(mem_ctx,
     453             :                                    context,
     454       50509 :                                    krbtgt_skdc_entry->kdc_db_ctx->samdb,
     455             :                                    flags,
     456             :                                    client_pac_entry,
     457             :                                    krbtgt_skdc_entry);
     458       50509 :         if (ret != 0) {
     459          76 :                 goto out;
     460             :         }
     461             : 
     462       50433 : out:
     463       50550 :         talloc_free(mem_ctx);
     464       50550 :         return ret;
     465             : }
     466             : 
     467             : /* Re-sign (and reform, including possibly new groups) a PAC */
     468             : 
     469       48712 : static krb5_error_code samba_wdc_reget_pac(void *priv, astgs_request_t r,
     470             :                                            krb5_const_principal _client_principal,
     471             :                                            hdb_entry *delegated_proxy,
     472             :                                            krb5_const_pac delegated_proxy_pac,
     473             :                                            hdb_entry *client,
     474             :                                            hdb_entry *server,
     475             :                                            hdb_entry *krbtgt,
     476             :                                            krb5_pac *pac)
     477             : {
     478       48712 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
     479       48712 :         struct samba_kdc_entry *delegated_proxy_skdc_entry = NULL;
     480       48712 :         krb5_const_principal delegated_proxy_principal = NULL;
     481       48712 :         struct samba_kdc_entry_pac delegated_proxy_pac_entry = {};
     482       48712 :         struct samba_kdc_entry *client_skdc_entry = NULL;
     483       48712 :         struct samba_kdc_entry_pac client_pac_entry = {};
     484       48712 :         struct samba_kdc_entry_pac device = {};
     485        1658 :         const struct samba_kdc_entry *server_skdc_entry =
     486       48712 :                 talloc_get_type_abort(server->context, struct samba_kdc_entry);
     487        1658 :         const struct samba_kdc_entry *krbtgt_skdc_entry =
     488       48712 :                 talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry);
     489       48712 :         TALLOC_CTX *mem_ctx = NULL;
     490       48712 :         krb5_pac new_pac = NULL;
     491       48712 :         struct authn_audit_info *server_audit_info = NULL;
     492        1658 :         krb5_error_code ret;
     493       48712 :         NTSTATUS reply_status = NT_STATUS_OK;
     494       48712 :         uint32_t flags = 0;
     495             : 
     496       48712 :         if (pac == NULL) {
     497           0 :                 return EINVAL;
     498             :         }
     499             : 
     500       48712 :         mem_ctx = talloc_named(NULL, 0, "samba_wdc_reget_pac context");
     501       48712 :         if (mem_ctx == NULL) {
     502           0 :                 return ENOMEM;
     503             :         }
     504             : 
     505       48712 :         if (delegated_proxy != NULL) {
     506         152 :                 delegated_proxy_skdc_entry = talloc_get_type_abort(delegated_proxy->context,
     507             :                                                                    struct samba_kdc_entry);
     508         152 :                 delegated_proxy_principal = delegated_proxy->principal;
     509             :         }
     510             : 
     511       48712 :         delegated_proxy_pac_entry = samba_kdc_entry_pac(delegated_proxy_pac,
     512             :                                                         delegated_proxy_skdc_entry,
     513             :                                                         /* The S4U2Proxy
     514             :                                                          * evidence ticket could
     515             :                                                          * not have been signed
     516             :                                                          * or issued by a krbtgt
     517             :                                                          * trust account. */
     518             :                                                         false /* is_from_trust */);
     519             : 
     520       48712 :         if (client != NULL) {
     521       48660 :                 client_skdc_entry = talloc_get_type_abort(client->context,
     522             :                                                           struct samba_kdc_entry);
     523             :         }
     524             : 
     525       48712 :         device = samba_kdc_get_device_pac(r);
     526             : 
     527       48712 :         ret = krb5_pac_init(context, &new_pac);
     528       48712 :         if (ret != 0) {
     529           0 :                 new_pac = NULL;
     530           0 :                 goto out;
     531             :         }
     532             : 
     533       48712 :         client_pac_entry = samba_kdc_entry_pac(*pac,
     534             :                                                client_skdc_entry,
     535       48712 :                                                samba_kdc_entry_is_trust(krbtgt_skdc_entry));
     536             : 
     537       50370 :         ret = samba_kdc_update_pac(mem_ctx,
     538             :                                    context,
     539       47054 :                                    krbtgt_skdc_entry->kdc_db_ctx->samdb,
     540       48712 :                                    krbtgt_skdc_entry->kdc_db_ctx->lp_ctx,
     541             :                                    flags,
     542             :                                    client_pac_entry,
     543       48712 :                                    server->principal,
     544             :                                    server_skdc_entry,
     545             :                                    delegated_proxy_principal,
     546             :                                    delegated_proxy_pac_entry,
     547             :                                    device,
     548             :                                    new_pac,
     549             :                                    &server_audit_info,
     550             :                                    &reply_status);
     551       48712 :         if (server_audit_info != NULL) {
     552           0 :                 krb5_error_code ret2;
     553             : 
     554         161 :                 ret2 = hdb_samba4_set_steal_server_audit_info(r, server_audit_info);
     555         161 :                 if (ret == 0) {
     556          98 :                         ret = ret2;
     557             :                 }
     558             :         }
     559       48712 :         if (!NT_STATUS_IS_OK(reply_status)) {
     560           0 :                 krb5_error_code ret2;
     561             : 
     562          63 :                 ret2 = hdb_samba4_set_ntstatus(r, reply_status, ret);
     563          63 :                 if (ret == 0) {
     564           0 :                         ret = ret2;
     565             :                 }
     566             :         }
     567       48712 :         if (ret != 0) {
     568          74 :                 krb5_pac_free(context, new_pac);
     569          74 :                 if (ret == ENOATTR) {
     570          11 :                         krb5_pac_free(context, *pac);
     571          11 :                         *pac = NULL;
     572          11 :                         ret = 0;
     573             :                 }
     574          74 :                 goto out;
     575             :         }
     576             : 
     577             :         /* Replace the pac */
     578       48638 :         krb5_pac_free(context, *pac);
     579       48638 :         *pac = new_pac;
     580             : 
     581       48712 : out:
     582       48712 :         talloc_free(mem_ctx);
     583       48712 :         return ret;
     584             : }
     585             : 
     586             : /* Verify a PAC's SID and signatures */
     587             : 
     588       50561 : static krb5_error_code samba_wdc_verify_pac(void *priv, astgs_request_t r,
     589             :                                             krb5_const_principal _client_principal,
     590             :                                             hdb_entry *delegated_proxy,
     591             :                                             hdb_entry *client,
     592             :                                             hdb_entry *_server,
     593             :                                             hdb_entry *krbtgt,
     594             :                                             EncTicketPart *ticket,
     595             :                                             krb5_pac pac)
     596             : {
     597       50561 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
     598       50561 :         krb5_kdc_configuration *config = kdc_request_get_config((kdc_request_t)r);
     599        1658 :         struct samba_kdc_entry *krbtgt_skdc_entry =
     600       50561 :                 talloc_get_type_abort(krbtgt->context,
     601             :                                       struct samba_kdc_entry);
     602        1658 :         krb5_error_code ret;
     603       50561 :         krb5_cksumtype ctype = CKSUMTYPE_NONE;
     604        1658 :         hdb_entry signing_krbtgt_hdb;
     605             : 
     606       50561 :         if (delegated_proxy) {
     607           0 :                 uint16_t pac_kdc_signature_rodc_id;
     608         199 :                 const unsigned int local_tgs_rodc_id = krbtgt_skdc_entry->kdc_db_ctx->my_krbtgt_number;
     609         199 :                 const uint16_t header_ticket_rodc_id = krbtgt->kvno >> 16;
     610             : 
     611             :                 /*
     612             :                  * We're using delegated_proxy for the moment to indicate cases
     613             :                  * where the ticket was encrypted with the server key, and not a
     614             :                  * krbtgt key. This cannot be trusted, so we need to find a
     615             :                  * krbtgt key that signs the PAC in order to trust the ticket.
     616             :                  *
     617             :                  * The krbtgt passed in to this function refers to the krbtgt
     618             :                  * used to decrypt the ticket of the server requesting
     619             :                  * S4U2Proxy.
     620             :                  *
     621             :                  * When we implement service ticket renewal, we need to check
     622             :                  * the PAC, and this will need to be updated.
     623             :                  */
     624         199 :                 ret = krb5_pac_get_kdc_checksum_info(context,
     625             :                                                      pac,
     626             :                                                      &ctype,
     627             :                                                      &pac_kdc_signature_rodc_id);
     628         199 :                 if (ret != 0) {
     629           3 :                         DBG_WARNING("Failed to get PAC checksum info\n");
     630           3 :                         return ret;
     631             :                 }
     632             : 
     633             :                 /*
     634             :                  * We need to check the KDC and ticket signatures, fetching the
     635             :                  * correct key based on the enctype.
     636             :                  */
     637         196 :                 if (local_tgs_rodc_id != 0) {
     638             :                         /*
     639             :                          * If we are an RODC, and we are not the KDC that signed
     640             :                          * the evidence ticket, then we need to proxy the
     641             :                          * request.
     642             :                          */
     643           0 :                         if (local_tgs_rodc_id != pac_kdc_signature_rodc_id) {
     644           0 :                                 return HDB_ERR_NOT_FOUND_HERE;
     645             :                         }
     646             :                 } else {
     647             :                         /*
     648             :                          * If we are a DC, the ticket may have been signed by a
     649             :                          * different KDC than the one that issued the header
     650             :                          * ticket.
     651             :                          */
     652         196 :                         if (pac_kdc_signature_rodc_id != header_ticket_rodc_id) {
     653           0 :                                 struct sdb_entry signing_krbtgt_sdb;
     654             : 
     655             :                                 /*
     656             :                                  * Fetch our key from the database. To support
     657             :                                  * key rollover, we're going to need to try
     658             :                                  * multiple keys by trial and error. For now,
     659             :                                  * krbtgt keys aren't assumed to change.
     660             :                                  */
     661           4 :                                 ret = samba_kdc_fetch(context,
     662             :                                                       krbtgt_skdc_entry->kdc_db_ctx,
     663           4 :                                                       krbtgt->principal,
     664             :                                                       SDB_F_GET_KRBTGT | SDB_F_RODC_NUMBER_SPECIFIED | SDB_F_CANON,
     665           4 :                                                       ((uint32_t)pac_kdc_signature_rodc_id) << 16,
     666             :                                                       &signing_krbtgt_sdb);
     667           4 :                                 if (ret != 0) {
     668           0 :                                         return ret;
     669             :                                 }
     670             : 
     671           4 :                                 ret = sdb_entry_to_hdb_entry(context,
     672             :                                                              &signing_krbtgt_sdb,
     673             :                                                              &signing_krbtgt_hdb);
     674           4 :                                 sdb_entry_free(&signing_krbtgt_sdb);
     675           4 :                                 if (ret != 0) {
     676           0 :                                         return ret;
     677             :                                 }
     678             : 
     679             :                                 /*
     680             :                                  * Replace the krbtgt entry with our own entry
     681             :                                  * for further processing.
     682             :                                  */
     683           4 :                                 krbtgt = &signing_krbtgt_hdb;
     684             :                         }
     685             :                 }
     686       50362 :         } else if (!krbtgt_skdc_entry->is_trust) {
     687             :                 /*
     688             :                  * We expect to have received a TGT, so check that we haven't
     689             :                  * been given a kpasswd ticket instead. We don't need to do this
     690             :                  * check for an incoming trust, as they use a different secret
     691             :                  * and can't be confused with a normal TGT.
     692             :                  */
     693             : 
     694       50311 :                 struct timeval now = krb5_kdc_get_time();
     695             : 
     696             :                 /*
     697             :                  * Check if the ticket is in the last two minutes of its
     698             :                  * life.
     699             :                  */
     700       50311 :                 KerberosTime lifetime = rk_time_sub(ticket->endtime, now.tv_sec);
     701       50311 :                 if (lifetime <= CHANGEPW_LIFETIME) {
     702             :                         /*
     703             :                          * This ticket has at most two minutes left to live. It
     704             :                          * may be a kpasswd ticket rather than a TGT, so don't
     705             :                          * accept it.
     706             :                          */
     707           8 :                         kdc_audit_addreason((kdc_request_t)r,
     708             :                                             "Ticket is not a ticket-granting ticket");
     709           8 :                         return KRB5KRB_AP_ERR_TKT_EXPIRED;
     710             :                 }
     711             :         }
     712             : 
     713       50550 :         ret = samba_wdc_verify_pac2(r,
     714             :                                     delegated_proxy,
     715             :                                     client,
     716             :                                     krbtgt,
     717             :                                     pac,
     718             :                                     ctype);
     719             : 
     720       50550 :         if (krbtgt == &signing_krbtgt_hdb) {
     721           4 :                 hdb_free_entry(context, config->db[0], &signing_krbtgt_hdb);
     722             :         }
     723             : 
     724       48892 :         return ret;
     725             : }
     726             : 
     727       49267 : static char *get_netbios_name(TALLOC_CTX *mem_ctx, HostAddresses *addrs)
     728             : {
     729       49267 :         char *nb_name = NULL;
     730        1755 :         size_t len;
     731        1755 :         unsigned int i;
     732             : 
     733       49267 :         for (i = 0; addrs && i < addrs->len; i++) {
     734         181 :                 if (addrs->val[i].addr_type != KRB5_ADDRESS_NETBIOS) {
     735           0 :                         continue;
     736             :                 }
     737         181 :                 len = MIN(addrs->val[i].address.length, 15);
     738         181 :                 nb_name = talloc_strndup(mem_ctx,
     739         181 :                                          addrs->val[i].address.data, len);
     740         181 :                 if (nb_name) {
     741         181 :                         break;
     742             :                 }
     743             :         }
     744             : 
     745       49267 :         if ((nb_name == NULL) || (nb_name[0] == '\0')) {
     746       47331 :                 return NULL;
     747             :         }
     748             : 
     749             :         /* Strip space padding */
     750         181 :         for (len = strlen(nb_name) - 1;
     751         944 :              (len > 0) && (nb_name[len] == ' ');
     752         763 :              --len) {
     753         763 :                 nb_name[len] = '\0';
     754             :         }
     755             : 
     756         181 :         return nb_name;
     757             : }
     758             : 
     759       49529 : static krb5_error_code samba_wdc_check_client_access(void *priv,
     760             :                                                      astgs_request_t r)
     761             : {
     762       49529 :         krb5_context context = kdc_request_get_context((kdc_request_t)r);
     763       49529 :         TALLOC_CTX *tmp_ctx = NULL;
     764       49529 :         const hdb_entry *client = NULL;
     765        1755 :         struct samba_kdc_entry *kdc_entry;
     766       49529 :         struct samba_kdc_entry_pac device = {};
     767       49529 :         struct authn_audit_info *client_audit_info = NULL;
     768        1755 :         bool password_change;
     769        1755 :         char *workstation;
     770        1755 :         NTSTATUS nt_status;
     771       49529 :         NTSTATUS check_device_status = NT_STATUS_OK;
     772       49529 :         krb5_error_code ret = 0;
     773             : 
     774       49529 :         client = kdc_request_get_client(r);
     775             : 
     776       49529 :         tmp_ctx = talloc_named(client->context, 0, "samba_wdc_check_client_access");
     777       49529 :         if (tmp_ctx == NULL) {
     778           0 :                 return ENOMEM;
     779             :         }
     780             : 
     781       49529 :         kdc_entry = talloc_get_type_abort(client->context, struct samba_kdc_entry);
     782             : 
     783       49529 :         device = samba_kdc_get_device_pac(r);
     784             : 
     785       51284 :         ret = samba_kdc_check_device(tmp_ctx,
     786             :                                      context,
     787       47774 :                                      kdc_entry->kdc_db_ctx->samdb,
     788       49529 :                                      kdc_entry->kdc_db_ctx->lp_ctx,
     789             :                                      device,
     790             :                                      kdc_entry->client_policy,
     791             :                                      &client_audit_info,
     792             :                                      &check_device_status);
     793       49529 :         if (client_audit_info != NULL) {
     794           0 :                 krb5_error_code ret2;
     795             : 
     796         397 :                 ret2 = hdb_samba4_set_steal_client_audit_info(r, client_audit_info);
     797         397 :                 if (ret2) {
     798           0 :                         ret = ret2;
     799             :                 }
     800             :         }
     801       49529 :         kdc_entry->reject_status = check_device_status;
     802       49529 :         if (!NT_STATUS_IS_OK(check_device_status)) {
     803           0 :                 krb5_error_code ret2;
     804             : 
     805             :                 /*
     806             :                  * Add the NTSTATUS to the request so we can return it in the
     807             :                  * ‘e-data’ field later.
     808             :                  */
     809           2 :                 ret2 = hdb_samba4_set_ntstatus(r, check_device_status, ret);
     810           2 :                 if (ret2) {
     811           0 :                         ret = ret2;
     812             :                 }
     813             :         }
     814             : 
     815       49529 :         if (ret) {
     816             :                 /*
     817             :                  * As we didn’t get far enough to check the server policy, only
     818             :                  * the client policy will be referenced in the authentication
     819             :                  * log message.
     820             :                  */
     821             : 
     822         262 :                 talloc_free(tmp_ctx);
     823         262 :                 return ret;
     824             :         }
     825             : 
     826       52777 :         workstation = get_netbios_name(tmp_ctx,
     827       49267 :                                        kdc_request_get_req(r)->req_body.addresses);
     828       49267 :         password_change = (kdc_request_get_server(r) && kdc_request_get_server(r)->flags.change_pw);
     829             : 
     830       49267 :         nt_status = samba_kdc_check_client_access(kdc_entry,
     831             :                                                   kdc_request_get_cname((kdc_request_t)r),
     832             :                                                   workstation,
     833             :                                                   password_change);
     834             : 
     835       49267 :         kdc_entry->reject_status = nt_status;
     836       49267 :         if (!NT_STATUS_IS_OK(nt_status)) {
     837           0 :                 krb5_error_code ret2;
     838             : 
     839          43 :                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
     840           0 :                         talloc_free(tmp_ctx);
     841           0 :                         return ENOMEM;
     842             :                 }
     843             : 
     844          43 :                 ret = samba_kdc_map_policy_err(nt_status);
     845             : 
     846             :                 /*
     847             :                  * Add the NTSTATUS to the request so we can return it in the
     848             :                  * ‘e-data’ field later.
     849             :                  */
     850          43 :                 ret2 = hdb_samba4_set_ntstatus(r, nt_status, ret);
     851          43 :                 if (ret2) {
     852           0 :                         ret = ret2;
     853             :                 }
     854             : 
     855          43 :                 talloc_free(tmp_ctx);
     856          43 :                 return ret;
     857             :         }
     858             : 
     859             :         /* Now do the standard Heimdal check */
     860       49224 :         talloc_free(tmp_ctx);
     861       49224 :         return KRB5_PLUGIN_NO_HANDLE;
     862             : }
     863             : 
     864             : /* this function allocates 'data' using malloc.
     865             :  * The caller is responsible for freeing it */
     866       36657 : static krb5_error_code samba_kdc_build_supported_etypes(uint32_t supported_etypes,
     867             :                                                         krb5_data *e_data)
     868             : {
     869       36657 :         e_data->data = malloc(4);
     870       36657 :         if (e_data->data == NULL) {
     871           0 :                 return ENOMEM;
     872             :         }
     873       36657 :         e_data->length = 4;
     874             : 
     875       36657 :         PUSH_LE_U32(e_data->data, 0, supported_etypes);
     876             : 
     877       36657 :         return 0;
     878             : }
     879             : 
     880       79598 : static krb5_error_code samba_wdc_finalize_reply(void *priv,
     881             :                                                 astgs_request_t r)
     882             : {
     883        2828 :         struct samba_kdc_entry *server_kdc_entry;
     884        2828 :         uint32_t supported_enctypes;
     885             : 
     886       79598 :         server_kdc_entry = talloc_get_type(kdc_request_get_server(r)->context, struct samba_kdc_entry);
     887             : 
     888             :         /*
     889             :          * If the canonicalize flag is set, add PA-SUPPORTED-ENCTYPES padata
     890             :          * type to indicate what encryption types the server supports.
     891             :          */
     892       79598 :         supported_enctypes = server_kdc_entry->supported_enctypes;
     893       79598 :         if (kdc_request_get_req(r)->req_body.kdc_options.canonicalize && supported_enctypes != 0) {
     894        1170 :                 krb5_error_code ret;
     895             : 
     896        1170 :                 PA_DATA md;
     897             : 
     898       36657 :                 ret = samba_kdc_build_supported_etypes(supported_enctypes, &md.padata_value);
     899       36657 :                 if (ret != 0) {
     900           0 :                         return ret;
     901             :                 }
     902             : 
     903       36657 :                 md.padata_type = KRB5_PADATA_SUPPORTED_ETYPES;
     904             : 
     905       36657 :                 ret = kdc_request_add_encrypted_padata(r, &md);
     906       36657 :                 if (ret != 0) {
     907             :                         /*
     908             :                          * So we do not leak the allocated
     909             :                          * memory on md in the error case
     910             :                          */
     911           0 :                         krb5_data_free(&md.padata_value);
     912             :                 }
     913             :         }
     914             : 
     915       76770 :         return 0;
     916             : }
     917             : 
     918          93 : static krb5_error_code samba_wdc_plugin_init(krb5_context context, void **ptr)
     919             : {
     920          93 :         *ptr = NULL;
     921          93 :         return 0;
     922             : }
     923             : 
     924           0 : static void samba_wdc_plugin_fini(void *ptr)
     925             : {
     926           0 :         return;
     927             : }
     928             : 
     929        1246 : static krb5_error_code samba_wdc_referral_policy(void *priv,
     930             :                                                  astgs_request_t r)
     931             : {
     932        1246 :         return kdc_request_get_error_code((kdc_request_t)r);
     933             : }
     934             : 
     935             : struct krb5plugin_kdc_ftable kdc_plugin_table = {
     936             :         .minor_version = KRB5_PLUGIN_KDC_VERSION_11,
     937             :         .init = samba_wdc_plugin_init,
     938             :         .fini = samba_wdc_plugin_fini,
     939             :         .pac_verify = samba_wdc_verify_pac,
     940             :         .pac_update = samba_wdc_reget_pac,
     941             :         .client_access = samba_wdc_check_client_access,
     942             :         .finalize_reply = samba_wdc_finalize_reply,
     943             :         .pac_generate = samba_wdc_get_pac,
     944             :         .referral_policy = samba_wdc_referral_policy,
     945             : };
     946             : 
     947             : 

Generated by: LCOV version 1.14