LCOV - code coverage report
Current view: top level - third_party/heimdal/kdc - mssfu.c (source / functions) Hit Total Coverage
Test: coverage report for master 469b22b8 Lines: 235 326 72.1 %
Date: 2024-06-10 12:05:21 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "kdc_locl.h"
      35             : 
      36             : /*
      37             :  * [MS-SFU] Kerberos Protocol Extensions:
      38             :  * Service for User (S4U2Self) and Constrained Delegation Protocol (S4U2Proxy)
      39             :  * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/
      40             :  */
      41             : 
      42             : /*
      43             :  * Determine if constrained delegation is allowed from this client to this server
      44             :  */
      45             : 
      46             : static krb5_error_code
      47         146 : check_constrained_delegation(krb5_context context,
      48             :                              krb5_kdc_configuration *config,
      49             :                              HDB *clientdb,
      50             :                              hdb_entry *client,
      51             :                              hdb_entry *server,
      52             :                              krb5_const_principal target)
      53             : {
      54           0 :     const HDB_Ext_Constrained_delegation_acl *acl;
      55           0 :     krb5_error_code ret;
      56           0 :     size_t i;
      57             : 
      58             :     /*
      59             :      * constrained delegation (S4U2Proxy) only works within
      60             :      * the same realm. We use the already canonicalized version
      61             :      * of the principals here, while "target" is the principal
      62             :      * provided by the client.
      63             :      */
      64         146 :     if (!krb5_realm_compare(context, client->principal, server->principal)) {
      65           0 :         ret = KRB5KDC_ERR_BADOPTION;
      66           0 :         kdc_log(context, config, 4,
      67             :             "Bad request for constrained delegation");
      68           0 :         return ret;
      69             :     }
      70             : 
      71         146 :     if (clientdb->hdb_check_constrained_delegation) {
      72         146 :         ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
      73         146 :         if (ret == 0)
      74         116 :             return 0;
      75             :     } else {
      76             :         /* if client delegates to itself, that ok */
      77           0 :         if (krb5_principal_compare(context, client->principal, server->principal) == TRUE)
      78           0 :             return 0;
      79             : 
      80           0 :         ret = hdb_entry_get_ConstrainedDelegACL(client, &acl);
      81           0 :         if (ret) {
      82           0 :             krb5_clear_error_message(context);
      83           0 :             return ret;
      84             :         }
      85             : 
      86           0 :         if (acl) {
      87           0 :             for (i = 0; i < acl->len; i++) {
      88           0 :                 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
      89           0 :                     return 0;
      90             :             }
      91             :         }
      92           0 :         ret = KRB5KDC_ERR_BADOPTION;
      93             :     }
      94          30 :     kdc_log(context, config, 4,
      95             :             "Bad request for constrained delegation");
      96          30 :     return ret;
      97             : }
      98             : 
      99             : /*
     100             :  * Determine if resource-based constrained delegation is allowed from this
     101             :  * client to this server
     102             :  */
     103             : 
     104             : static krb5_error_code
     105         136 : check_rbcd(krb5_context context,
     106             :            krb5_kdc_configuration *config,
     107             :            HDB *clientdb,
     108             :            krb5_const_principal s4u_principal,
     109             :            const hdb_entry *client_krbtgt,
     110             :            const hdb_entry *client,
     111             :            const hdb_entry *device_krbtgt,
     112             :            const hdb_entry *device,
     113             :            krb5_const_pac client_pac,
     114             :            krb5_const_pac device_pac,
     115             :            const hdb_entry *target)
     116             : {
     117         136 :     krb5_error_code ret = KRB5KDC_ERR_BADOPTION;
     118             : 
     119         136 :     if (clientdb->hdb_check_rbcd) {
     120         136 :         ret = clientdb->hdb_check_rbcd(context,
     121             :                                        clientdb,
     122             :                                        client_krbtgt,
     123             :                                        client,
     124             :                                        device_krbtgt,
     125             :                                        device,
     126             :                                        s4u_principal,
     127             :                                        client_pac,
     128             :                                        device_pac,
     129             :                                        target);
     130         136 :         if (ret == 0)
     131         109 :             return 0;
     132             :     }
     133             : 
     134          27 :     kdc_log(context, config, 4,
     135             :             "Bad request for resource-based constrained delegation");
     136          27 :     return ret;
     137             : }
     138             : 
     139             : /*
     140             :  * Validate a protocol transition (S4U2Self) request. If successfully
     141             :  * validated then the client in the request structure will be replaced
     142             :  * with the impersonated client.
     143             :  */
     144             : 
     145             : krb5_error_code
     146         658 : _kdc_validate_protocol_transition(astgs_request_t r, const PA_DATA *for_user)
     147             : {
     148           0 :     krb5_error_code ret;
     149         658 :     KDC_REQ_BODY *b = &r->req.req_body;
     150         658 :     EncTicketPart *ticket = &r->ticket->ticket;
     151         658 :     hdb_entry *s4u_client = NULL;
     152           0 :     HDB *s4u_clientdb;
     153         658 :     int flags = HDB_F_FOR_TGS_REQ;
     154         658 :     krb5_principal s4u_client_name = NULL, s4u_canon_client_name = NULL;
     155         658 :     krb5_pac s4u_pac = NULL;
     156         658 :     char *s4ucname = NULL;
     157           0 :     krb5_crypto crypto;
     158           0 :     krb5_data datack;
     159           0 :     PA_S4U2Self self;
     160           0 :     const char *str;
     161             : 
     162         658 :     heim_assert(r->client != NULL, "client must be non-NULL");
     163             : 
     164         658 :     memset(&self, 0, sizeof(self));
     165             : 
     166         658 :     if (b->kdc_options.canonicalize)
     167         576 :         flags |= HDB_F_CANON;
     168             : 
     169         658 :     ret = decode_PA_S4U2Self(for_user->padata_value.data,
     170         658 :                              for_user->padata_value.length,
     171             :                              &self, NULL);
     172         658 :     if (ret) {
     173           0 :         kdc_audit_addreason((kdc_request_t)r,
     174             :                             "Failed to decode PA-S4U2Self");
     175           0 :         kdc_log(r->context, r->config, 4, "Failed to decode PA-S4U2Self");
     176           0 :         goto out;
     177             :     }
     178             : 
     179         658 :     if (!krb5_checksum_is_keyed(r->context, self.cksum.cksumtype)) {
     180           4 :         kdc_audit_addreason((kdc_request_t)r,
     181             :                             "PA-S4U2Self with unkeyed checksum");
     182           4 :         kdc_log(r->context, r->config, 4, "Reject PA-S4U2Self with unkeyed checksum");
     183           4 :         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
     184           4 :         goto out;
     185             :     }
     186             : 
     187         654 :     ret = _krb5_s4u2self_to_checksumdata(r->context, &self, &datack);
     188         654 :     if (ret)
     189           0 :         goto out;
     190             : 
     191         654 :     ret = krb5_crypto_init(r->context, &ticket->key, 0, &crypto);
     192         654 :     if (ret) {
     193           0 :         const char *msg = krb5_get_error_message(r->context, ret);
     194           0 :         krb5_data_free(&datack);
     195           0 :         kdc_log(r->context, r->config, 4, "krb5_crypto_init failed: %s", msg);
     196           0 :         krb5_free_error_message(r->context, msg);
     197           0 :         goto out;
     198             :     }
     199             : 
     200             :     /* Allow HMAC_MD5 checksum with any key type */
     201         654 :     if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
     202           0 :         struct krb5_crypto_iov iov;
     203           0 :         unsigned char csdata[16];
     204           0 :         Checksum cs;
     205             : 
     206         123 :         cs.checksum.length = sizeof(csdata);
     207         123 :         cs.checksum.data = &csdata;
     208             : 
     209         123 :         iov.data.data = datack.data;
     210         123 :         iov.data.length = datack.length;
     211         123 :         iov.flags = KRB5_CRYPTO_TYPE_DATA;
     212             : 
     213         123 :         ret = _krb5_HMAC_MD5_checksum(r->context, NULL, &crypto->key,
     214             :                                       KRB5_KU_OTHER_CKSUM, &iov, 1,
     215             :                                       &cs);
     216         246 :         if (ret == 0 &&
     217         123 :             krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
     218           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
     219             :     } else {
     220         531 :         ret = _kdc_verify_checksum(r->context,
     221             :                                    crypto,
     222             :                                    KRB5_KU_OTHER_CKSUM,
     223             :                                    &datack,
     224             :                                    &self.cksum);
     225             :     }
     226         654 :     krb5_data_free(&datack);
     227         654 :     krb5_crypto_destroy(r->context, crypto);
     228         654 :     if (ret) {
     229           2 :         const char *msg = krb5_get_error_message(r->context, ret);
     230           2 :         kdc_audit_addreason((kdc_request_t)r,
     231             :                             "S4U2Self checksum failed");
     232           2 :         kdc_log(r->context, r->config, 4,
     233             :                 "krb5_verify_checksum failed for S4U2Self: %s", msg);
     234           2 :         krb5_free_error_message(r->context, msg);
     235           2 :         goto out;
     236             :     }
     237             : 
     238         652 :     ret = _krb5_principalname2krb5_principal(r->context,
     239             :                                              &s4u_client_name,
     240             :                                              self.name,
     241             :                                              self.realm);
     242         652 :     if (ret)
     243           0 :         goto out;
     244             : 
     245         652 :     ret = krb5_unparse_name(r->context, s4u_client_name, &s4ucname);
     246         652 :     if (ret)
     247           0 :         goto out;
     248             : 
     249             :     /*
     250             :      * Note no HDB_F_SYNTHETIC_OK -- impersonating non-existent clients
     251             :      * is probably not desirable!
     252             :      */
     253         652 :     ret = _kdc_db_fetch(r->context, r->config, s4u_client_name,
     254         652 :                         HDB_F_GET_CLIENT | flags, NULL,
     255             :                         &s4u_clientdb, &s4u_client);
     256         652 :     if (ret) {
     257           0 :         const char *msg;
     258             : 
     259             :         /*
     260             :          * If the client belongs to the same realm as our krbtgt, it
     261             :          * should exist in the local database.
     262             :          *
     263             :          */
     264           0 :         if (ret == HDB_ERR_NOENTRY)
     265           0 :             ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
     266           0 :         msg = krb5_get_error_message(r->context, ret);
     267           0 :         kdc_audit_addreason((kdc_request_t)r,
     268             :                             "S4U2Self principal to impersonate not found");
     269           0 :         kdc_log(r->context, r->config, 2,
     270             :                 "S4U2Self principal to impersonate %s not found in database: %s",
     271             :                 s4ucname, msg);
     272           0 :         krb5_free_error_message(r->context, msg);
     273           0 :         goto out;
     274             :     }
     275             : 
     276             :     /*
     277             :      * Ignore require_pwchange and pw_end attributes (as Windows does),
     278             :      * since S4U2Self is not password authentication.
     279             :      */
     280         652 :     s4u_client->flags.require_pwchange = FALSE;
     281         652 :     free(s4u_client->pw_end);
     282         652 :     s4u_client->pw_end = NULL;
     283             : 
     284         652 :     ret = kdc_check_flags(r, FALSE, s4u_client, r->server);
     285         652 :     if (ret)
     286           0 :         goto out; /* kdc_check_flags() calls kdc_audit_addreason() */
     287             : 
     288         652 :     ret = _kdc_pac_generate(r,
     289             :                             s4u_client,
     290             :                             r->server,
     291             :                             NULL,
     292             :                             KRB5_PAC_WAS_GIVEN_IMPLICITLY,
     293             :                             &s4u_pac);
     294         652 :     if (ret) {
     295           0 :         kdc_log(r->context, r->config, 4, "PAC generation failed for -- %s", s4ucname);
     296           0 :         goto out;
     297             :     }
     298             : 
     299             :     /*
     300             :      * Check that service doing the impersonating is
     301             :      * requesting a ticket to it-self.
     302             :      */
     303         652 :     ret = _kdc_check_client_matches_target_service(r->context,
     304             :                                                    r->config,
     305             :                                                    r->clientdb,
     306             :                                                    r->client,
     307             :                                                    r->server,
     308         652 :                                                    r->server_princ);
     309         652 :     if (ret) {
     310           2 :         kdc_log(r->context, r->config, 4, "S4U2Self: %s is not allowed "
     311             :                 "to impersonate to service "
     312             :                  "(tried for user %s to service %s)",
     313             :                  r->cname, s4ucname, r->sname);
     314           2 :         goto out;
     315             :     }
     316             : 
     317         650 :     ret = krb5_copy_principal(r->context, s4u_client->principal,
     318             :                               &s4u_canon_client_name);
     319         650 :     if (ret)
     320           0 :         goto out;
     321             : 
     322             :     /*
     323             :      * If the service isn't trusted for authentication to
     324             :      * delegation or if the impersonate client is disallowed
     325             :      * forwardable, remove the forwardable flag.
     326             :      */
     327         650 :     if (r->client->flags.trusted_for_delegation &&
     328         125 :         s4u_client->flags.forwardable) {
     329         124 :         str = " [forwardable]";
     330             :     } else {
     331         526 :         b->kdc_options.forwardable = 0;
     332         526 :         str = "";
     333             :     }
     334         650 :     kdc_log(r->context, r->config, 4, "s4u2self %s impersonating %s to "
     335             :             "service %s%s", r->cname, s4ucname, r->sname, str);
     336             : 
     337             :     /*
     338             :      * Replace all client information in the request with the
     339             :      * impersonated client. (The audit entry containing the original
     340             :      * client name will have been created before this point.)
     341             :      */
     342         650 :     _kdc_request_set_cname_nocopy((kdc_request_t)r, &s4ucname);
     343         650 :     _kdc_request_set_client_princ_nocopy(r, &s4u_client_name);
     344             : 
     345         650 :     _kdc_free_ent(r->context, r->clientdb, r->client);
     346         650 :     r->client = s4u_client;
     347         650 :     s4u_client = NULL;
     348         650 :     r->clientdb = s4u_clientdb;
     349         650 :     s4u_clientdb = NULL;
     350             : 
     351         650 :     _kdc_request_set_canon_client_princ_nocopy(r, &s4u_canon_client_name);
     352         650 :     _kdc_request_set_pac_nocopy(r, &s4u_pac);
     353             : 
     354         658 : out:
     355         658 :     if (s4u_client)
     356           2 :         _kdc_free_ent(r->context, s4u_clientdb, s4u_client);
     357         658 :     krb5_free_principal(r->context, s4u_client_name);
     358         658 :     krb5_xfree(s4ucname);
     359         658 :     krb5_free_principal(r->context, s4u_canon_client_name);
     360         658 :     krb5_pac_free(r->context, s4u_pac);
     361             : 
     362         658 :     free_PA_S4U2Self(&self);
     363             : 
     364         658 :     return ret;
     365             : }
     366             : 
     367             : /*
     368             :  * Validate a constrained delegation (S4U2Proxy) request. If
     369             :  * successfully validated then the client in the request structure will
     370             :  * be replaced with the client from the evidence ticket.
     371             :  */
     372             : 
     373             : krb5_error_code
     374         264 : _kdc_validate_constrained_delegation(astgs_request_t r)
     375             : {
     376           0 :     krb5_error_code ret;
     377         264 :     KDC_REQ_BODY *b = &r->req.req_body;
     378         264 :     int flags = HDB_F_FOR_TGS_REQ;
     379         264 :     krb5_principal s4u_client_name = NULL, s4u_server_name = NULL;
     380         264 :     krb5_principal s4u_canon_client_name = NULL;
     381         264 :     krb5_pac s4u_pac = NULL;
     382           0 :     uint64_t s4u_pac_attributes;
     383         264 :     char *s4ucname = NULL, *s4usname = NULL;
     384           0 :     EncTicketPart evidence_tkt;
     385           0 :     HDB *s4u_clientdb;
     386         264 :     hdb_entry *s4u_client = NULL;
     387         264 :     HDB *s4u_serverdb = NULL;
     388         264 :     hdb_entry *s4u_server = NULL;
     389         264 :     krb5_boolean ad_kdc_issued = FALSE;
     390           0 :     Key *clientkey;
     391           0 :     Ticket *t;
     392           0 :     krb5_const_realm local_realm;
     393         264 :     const PA_DATA *pac_options_data = NULL;
     394         264 :     int pac_options_data_idx = 0;
     395         264 :     krb5_boolean rbcd_support = FALSE;
     396             : 
     397         264 :     memset(&evidence_tkt, 0, sizeof(evidence_tkt));
     398           0 :     local_realm =
     399         264 :             krb5_principal_get_comp_string(r->context, r->krbtgt->principal, 1);
     400             : 
     401             :     /*
     402             :      * We require that the service's TGT has a PAC; this will have been
     403             :      * validated prior to this function being called.
     404             :      */
     405         264 :     if (r->pac == NULL) {
     406           0 :         ret = KRB5KDC_ERR_BADOPTION;
     407           0 :         kdc_audit_addreason((kdc_request_t)r, "Missing PAC");
     408           0 :         kdc_log(r->context, r->config, 4,
     409             :                 "Constrained delegation without PAC, %s/%s",
     410             :                 r->cname, r->sname);
     411           0 :         goto out;
     412             :     }
     413             : 
     414         264 :     t = &b->additional_tickets->val[0];
     415             : 
     416         264 :     ret = _krb5_principalname2krb5_principal(r->context,
     417             :                                              &s4u_server_name,
     418             :                                              t->sname,
     419             :                                              t->realm);
     420         264 :     if (ret)
     421           0 :         goto out;
     422             : 
     423         264 :     ret = krb5_unparse_name(r->context, s4u_server_name, &s4usname);
     424         264 :     if (ret)
     425           0 :         goto out;
     426             : 
     427             :     /*
     428             :      * Look up the name given in the ticket in the database. We don’t ask for
     429             :      * canonicalisation, so that we get back the same principal that was
     430             :      * specified in the ticket.
     431             :      */
     432         264 :     ret = _kdc_db_fetch(r->context, r->config, s4u_server_name,
     433         264 :                         HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags,
     434             :                         NULL, &s4u_serverdb, &s4u_server);
     435         264 :     if (ret == HDB_ERR_NOENTRY)
     436           0 :         ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
     437         264 :     if (ret) {
     438           0 :         kdc_audit_addreason((kdc_request_t)r,
     439             :                             "Constrained delegation service principal unknown");
     440           0 :         goto out;
     441             :     }
     442             : 
     443             :     /*
     444             :      * Check that the delegating server (r->client) is the same one as specified
     445             :      * in the ticket. This is to make sure that the server hasn’t forged the
     446             :      * sname, which is in the unencrypted part of the ticket.
     447             :      */
     448         264 :     ret = _kdc_check_client_matches_target_service(r->context,
     449             :                                                    r->config,
     450             :                                                    s4u_serverdb,
     451             :                                                    s4u_server,
     452             :                                                    r->client,
     453         264 :                                                    r->client_princ);
     454         264 :     if (ret == KRB5KRB_AP_ERR_BADMATCH)
     455           2 :         ret = KRB5KDC_ERR_BADOPTION;
     456         264 :     if (ret)
     457           2 :         goto out;
     458             : 
     459         262 :     ret = hdb_enctype2key(r->context, r->client,
     460         262 :                           hdb_kvno2keys(r->context, r->client,
     461         262 :                                         t->enc_part.kvno ? * t->enc_part.kvno : 0),
     462             :                           t->enc_part.etype, &clientkey);
     463         262 :     if (ret) {
     464           0 :         ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
     465           0 :         goto out;
     466             :     }
     467             : 
     468         262 :     ret = krb5_decrypt_ticket(r->context, t, &clientkey->key, &evidence_tkt, 0);
     469         262 :     if (ret) {
     470           0 :         kdc_audit_addreason((kdc_request_t)r,
     471             :                             "Failed to decrypt constrained delegation ticket");
     472           0 :         kdc_log(r->context, r->config, 4,
     473             :                 "failed to decrypt ticket for "
     474             :                 "constrained delegation from %s to %s", r->cname, r->sname);
     475           0 :         goto out;
     476             :     }
     477             : 
     478         262 :     ret = _krb5_principalname2krb5_principal(r->context,
     479             :                                              &s4u_client_name,
     480             :                                              evidence_tkt.cname,
     481             :                                              evidence_tkt.crealm);
     482         262 :     if (ret)
     483           0 :         goto out;
     484             : 
     485         262 :     ret = krb5_unparse_name(r->context, s4u_client_name, &s4ucname);
     486         262 :     if (ret)
     487           0 :         goto out;
     488             : 
     489         262 :     kdc_audit_addkv((kdc_request_t)r, 0, "impersonatee", "%s", s4ucname);
     490             : 
     491             :         /* check that ticket is valid */
     492         262 :     if (evidence_tkt.flags.forwardable == 0) {
     493           7 :         kdc_audit_addreason((kdc_request_t)r,
     494             :                             "Missing forwardable flag on ticket for constrained delegation");
     495           7 :         kdc_log(r->context, r->config, 4,
     496             :                 "Missing forwardable flag on ticket for "
     497             :                 "constrained delegation from %s (%s) as %s to %s ",
     498             :                 r->cname, s4usname, s4ucname, r->sname);
     499           7 :         ret = KRB5KDC_ERR_BADOPTION;
     500           7 :         goto out;
     501             :     }
     502             : 
     503         255 :     pac_options_data = _kdc_find_padata(&r->req,
     504             :                                         &pac_options_data_idx,
     505             :                                         KRB5_PADATA_PAC_OPTIONS);
     506         255 :     if (pac_options_data != NULL) {
     507           0 :         PA_PAC_OPTIONS pac_options;
     508         145 :         size_t size = 0;
     509             : 
     510         145 :         ret = decode_PA_PAC_OPTIONS(pac_options_data->padata_value.data,
     511         145 :                                     pac_options_data->padata_value.length,
     512             :                                     &pac_options,
     513             :                                     &size);
     514         145 :         if (ret) {
     515           0 :             goto out;
     516             :         }
     517             : 
     518         145 :         if (size != pac_options_data->padata_value.length) {
     519           0 :             free_PA_PAC_OPTIONS(&pac_options);
     520           0 :             ret = KRB5KDC_ERR_BADOPTION;
     521           0 :             goto out;
     522             :         }
     523             : 
     524         145 :         rbcd_support = pac_options.flags.resource_based_constrained_delegation != 0;
     525             : 
     526         145 :         free_PA_PAC_OPTIONS(&pac_options);
     527             :     }
     528             : 
     529         255 :     if (rbcd_support) {
     530         136 :         ret = check_rbcd(r->context, r->config, r->clientdb,
     531             :                          s4u_client_name,
     532         136 :                          r->krbtgt, r->client,
     533         136 :                          r->armor_server, r->armor_client,
     534         136 :                          r->pac, r->armor_pac,
     535         136 :                          r->server);
     536             :     } else {
     537         119 :         ret = KRB5KDC_ERR_BADOPTION;
     538             :     }
     539         255 :     if (ret == KRB5KDC_ERR_BADOPTION) {
     540             :         /* RBCD was denied or not supported; try constrained delegation. */
     541         146 :         ret = check_constrained_delegation(r->context, r->config, r->clientdb,
     542         146 :                                            r->client, r->server, r->server_princ);
     543         146 :         if (ret) {
     544          30 :             kdc_audit_addreason((kdc_request_t)r,
     545             :                                 "Constrained delegation not allowed");
     546          30 :             kdc_log(r->context, r->config, 4,
     547             :                     "constrained delegation from %s (%s) as %s to %s not allowed",
     548             :                     r->cname, s4usname, s4ucname, r->sname);
     549          30 :             goto out;
     550             :         }
     551         109 :     } else if (ret) {
     552           0 :         kdc_audit_addreason((kdc_request_t)r,
     553             :                             "Resource-based constrained delegation not allowed");
     554           0 :         kdc_log(r->context, r->config, 4,
     555             :                 "resource-based constrained delegation from %s (%s) as %s to %s not allowed",
     556             :                 r->cname, s4usname, s4ucname, r->sname);
     557           0 :         goto out;
     558             :     }
     559             : 
     560         225 :     ret = _kdc_verify_flags(r->context, r->config, &evidence_tkt, s4ucname);
     561         225 :     if (ret) {
     562           0 :         kdc_audit_addreason((kdc_request_t)r,
     563             :                             "Constrained delegation ticket expired or invalid");
     564           0 :         goto out;
     565             :     }
     566             : 
     567             :     /* Try lookup the delegated client in DB */
     568         225 :     ret = _kdc_db_fetch_client(r->context, r->config, flags,
     569             :                                s4u_client_name, s4ucname, local_realm,
     570             :                                &s4u_clientdb, &s4u_client);
     571         225 :     if (ret)
     572           0 :         goto out;
     573             : 
     574         225 :     if (s4u_client != NULL) {
     575         224 :         ret = kdc_check_flags(r, FALSE, s4u_client, r->server);
     576         224 :         if (ret)
     577           0 :             goto out;
     578             :     }
     579             : 
     580             :     /*
     581             :      * TODO: pass in t->sname and t->realm and build
     582             :      * a S4U_DELEGATION_INFO blob to the PAC.
     583             :      */
     584         225 :     ret = _kdc_check_pac(r, s4u_client_name, s4u_server,
     585             :                          s4u_client, r->server, r->krbtgt, r->client,
     586         225 :                          &clientkey->key, &r->ticket_key->key, &evidence_tkt,
     587             :                          &ad_kdc_issued, &s4u_pac,
     588             :                          &s4u_canon_client_name, &s4u_pac_attributes);
     589         225 :     if (ret) {
     590          70 :         const char *msg = krb5_get_error_message(r->context, ret);
     591          70 :         kdc_audit_addreason((kdc_request_t)r,
     592             :                             "Constrained delegation ticket PAC check failed");
     593          70 :         kdc_log(r->context, r->config, 4,
     594             :                 "Verify delegated PAC failed to %s for client "
     595             :                 "%s (%s) as %s from %s with %s",
     596             :                 r->sname, r->cname, s4usname, s4ucname, r->from, msg);
     597          70 :         krb5_free_error_message(r->context, msg);
     598          70 :         goto out;
     599             :     }
     600             : 
     601         155 :     if (s4u_pac == NULL || !ad_kdc_issued) {
     602           3 :         ret = KRB5KDC_ERR_BADOPTION;
     603           3 :         kdc_log(r->context, r->config, 4,
     604             :                 "Ticket not signed with PAC; service %s failed for "
     605             :                 "for delegation to %s for client %s (%s) from %s; (%s).",
     606             :                 r->sname, s4ucname, s4usname, r->cname, r->from,
     607           3 :                 s4u_pac ? "Ticket unsigned" : "No PAC");
     608           3 :         kdc_audit_addreason((kdc_request_t)r,
     609             :                             "Constrained delegation ticket not signed");
     610           3 :         goto out;
     611             :     }
     612             : 
     613         152 :     heim_assert(s4u_pac != NULL, "ad_kdc_issued implies the PAC is non-NULL");
     614             : 
     615         152 :     ret = _kdc_pac_update(r, s4u_client_name, s4u_server, r->pac,
     616             :                           s4u_client, r->server, r->krbtgt,
     617             :                           &s4u_pac);
     618         152 :     if (ret == KRB5_PLUGIN_NO_HANDLE) {
     619           0 :         ret = 0;
     620             :     }
     621         152 :     if (ret) {
     622          12 :         const char *msg = krb5_get_error_message(r->context, ret);
     623          12 :         kdc_audit_addreason((kdc_request_t)r,
     624             :                             "Constrained delegation ticket PAC update failed");
     625          12 :         kdc_log(r->context, r->config, 4,
     626             :                 "Update delegated PAC failed to %s for client "
     627             :                 "%s (%s) as %s from %s with %s",
     628             :                 r->sname, r->cname, s4usname, s4ucname, r->from, msg);
     629          12 :         krb5_free_error_message(r->context, msg);
     630          12 :         goto out;
     631             :     }
     632             : 
     633             :     /*
     634             :      * If the evidence ticket PAC didn't include PAC_UPN_DNS_INFO with
     635             :      * the canonical client name, but the user is local to our KDC, we
     636             :      * can insert the canonical client name ourselves.
     637             :      */
     638         140 :     if (s4u_canon_client_name == NULL && s4u_client != NULL) {
     639           0 :         ret = krb5_copy_principal(r->context, s4u_client->principal,
     640             :                                   &s4u_canon_client_name);
     641           0 :         if (ret)
     642           0 :             goto out;
     643             :     }
     644             : 
     645         140 :     if (b->enc_authorization_data && r->rk_is_subkey == 0) {
     646           2 :         krb5_free_keyblock_contents(r->context, &r->enc_ad_key);
     647           2 :         ret = krb5_copy_keyblock_contents(r->context,
     648             :                                           &evidence_tkt.key,
     649             :                                           &r->enc_ad_key);
     650           2 :         if (ret)
     651           0 :             goto out;
     652             :     }
     653             : 
     654         140 :     kdc_log(r->context, r->config, 4, "constrained delegation for %s "
     655             :             "from %s (%s) to %s", s4ucname, r->cname, s4usname, r->sname);
     656             : 
     657             :     /*
     658             :      * Replace all client information in the request with the
     659             :      * impersonated client. (The audit entry containing the original
     660             :      * client name will have been created before this point.)
     661             :      */
     662         140 :     _kdc_request_set_cname_nocopy((kdc_request_t)r, &s4ucname);
     663         140 :     _kdc_request_set_client_princ_nocopy(r, &s4u_client_name);
     664             : 
     665         140 :     _kdc_free_ent(r->context, r->clientdb, r->client);
     666         140 :     r->client = s4u_client;
     667         140 :     s4u_client = NULL;
     668         140 :     r->clientdb = s4u_clientdb;
     669         140 :     s4u_clientdb = NULL;
     670             : 
     671         140 :     _kdc_request_set_canon_client_princ_nocopy(r, &s4u_canon_client_name);
     672         140 :     _kdc_request_set_pac_nocopy(r, &s4u_pac);
     673             : 
     674         140 :     r->pac_attributes = s4u_pac_attributes;
     675             : 
     676         140 :     r->et.authtime = evidence_tkt.authtime;
     677             : 
     678         264 : out:
     679         264 :     if (s4u_client)
     680          85 :         _kdc_free_ent(r->context, s4u_clientdb, s4u_client);
     681         264 :     if (s4u_server)
     682         264 :         _kdc_free_ent(r->context, s4u_serverdb, s4u_server);
     683         264 :     krb5_free_principal(r->context, s4u_client_name);
     684         264 :     krb5_xfree(s4ucname);
     685         264 :     krb5_free_principal(r->context, s4u_server_name);
     686         264 :     krb5_xfree(s4usname);
     687         264 :     krb5_free_principal(r->context, s4u_canon_client_name);
     688         264 :     krb5_pac_free(r->context, s4u_pac);
     689             : 
     690         264 :     free_EncTicketPart(&evidence_tkt);
     691             : 
     692         264 :     return ret;
     693             : }

Generated by: LCOV version 1.14