LCOV - code coverage report
Current view: top level - source4/heimdal/kdc - krb5tgs.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 704 1229 57.3 %
Date: 2021-09-23 10:06:22 Functions: 20 26 76.9 %

          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             :  * return the realm of a krbtgt-ticket or NULL
      38             :  */
      39             : 
      40             : static Realm
      41       79385 : get_krbtgt_realm(const PrincipalName *p)
      42             : {
      43       81563 :     if(p->name_string.len == 2
      44       79691 :        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
      45       65125 :         return p->name_string.val[1];
      46             :     else
      47       16099 :         return NULL;
      48             : }
      49             : 
      50             : /*
      51             :  * The KDC might add a signed path to the ticket authorization data
      52             :  * field. This is to avoid server impersonating clients and the
      53             :  * request constrained delegation.
      54             :  *
      55             :  * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
      56             :  * entry of type KRB5SignedPath.
      57             :  */
      58             : 
      59             : static krb5_error_code
      60       39896 : find_KRB5SignedPath(krb5_context context,
      61             :                     const AuthorizationData *ad,
      62             :                     krb5_data *data)
      63             : {
      64             :     AuthorizationData child;
      65             :     krb5_error_code ret;
      66             :     int pos;
      67             : 
      68       39896 :     if (ad == NULL || ad->len == 0)
      69           0 :         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
      70             : 
      71       39896 :     pos = ad->len - 1;
      72             : 
      73       39896 :     if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
      74           0 :         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
      75             : 
      76       39896 :     ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
      77       38807 :                                    ad->val[pos].ad_data.length,
      78             :                                    &child,
      79             :                                    NULL);
      80       39896 :     if (ret) {
      81           0 :         krb5_set_error_message(context, ret, "Failed to decode "
      82             :                                "IF_RELEVANT with %d", ret);
      83           0 :         return ret;
      84             :     }
      85             : 
      86       39896 :     if (child.len != 1) {
      87           0 :         free_AuthorizationData(&child);
      88           0 :         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
      89             :     }
      90             : 
      91       39896 :     if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
      92         297 :         free_AuthorizationData(&child);
      93         297 :         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
      94             :     }
      95             : 
      96       39599 :     if (data)
      97       39599 :         ret = der_copy_octet_string(&child.val[0].ad_data, data);
      98       39599 :     free_AuthorizationData(&child);
      99       39599 :     return ret;
     100             : }
     101             : 
     102             : krb5_error_code
     103       64870 : _kdc_add_KRB5SignedPath(krb5_context context,
     104             :                         krb5_kdc_configuration *config,
     105             :                         hdb_entry_ex *krbtgt,
     106             :                         krb5_enctype enctype,
     107             :                         krb5_principal client,
     108             :                         krb5_const_principal server,
     109             :                         krb5_principals principals,
     110             :                         EncTicketPart *tkt)
     111             : {
     112             :     krb5_error_code ret;
     113             :     KRB5SignedPath sp;
     114             :     krb5_data data;
     115       64870 :     krb5_crypto crypto = NULL;
     116       64870 :     size_t size = 0;
     117             : 
     118       64870 :     if (server && principals) {
     119           0 :         ret = add_Principals(principals, server);
     120           0 :         if (ret)
     121           0 :             return ret;
     122             :     }
     123             : 
     124             :     {
     125             :         KRB5SignedPathData spd;
     126             : 
     127       64870 :         spd.client = client;
     128       64870 :         spd.authtime = tkt->authtime;
     129       64870 :         spd.delegated = principals;
     130       64870 :         spd.method_data = NULL;
     131             : 
     132       64870 :         ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
     133             :                            &spd, &size, ret);
     134       64870 :         if (ret)
     135           0 :             return ret;
     136       64870 :         if (data.length != size)
     137           0 :             krb5_abortx(context, "internal asn.1 encoder error");
     138             :     }
     139             : 
     140             :     {
     141             :         Key *key;
     142       64870 :         ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
     143       64870 :         if (ret == 0)
     144       64870 :             ret = krb5_crypto_init(context, &key->key, 0, &crypto);
     145       64870 :         if (ret) {
     146           0 :             free(data.data);
     147           0 :             return ret;
     148             :         }
     149             :     }
     150             : 
     151             :     /*
     152             :      * Fill in KRB5SignedPath
     153             :      */
     154             : 
     155       64870 :     sp.etype = enctype;
     156       64870 :     sp.delegated = principals;
     157       64870 :     sp.method_data = NULL;
     158             : 
     159       64870 :     ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
     160             :                                data.data, data.length, &sp.cksum);
     161       64870 :     krb5_crypto_destroy(context, crypto);
     162       64870 :     free(data.data);
     163       64870 :     if (ret)
     164           0 :         return ret;
     165             : 
     166       64870 :     ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
     167       64870 :     free_Checksum(&sp.cksum);
     168       64870 :     if (ret)
     169           0 :         return ret;
     170       64870 :     if (data.length != size)
     171           0 :         krb5_abortx(context, "internal asn.1 encoder error");
     172             : 
     173             : 
     174             :     /*
     175             :      * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
     176             :      * authorization data field.
     177             :      */
     178             : 
     179       64870 :     ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
     180             :                                       KRB5_AUTHDATA_SIGNTICKET, &data);
     181       64870 :     krb5_data_free(&data);
     182             : 
     183       64870 :     return ret;
     184             : }
     185             : 
     186             : static krb5_error_code
     187       39896 : check_KRB5SignedPath(krb5_context context,
     188             :                      krb5_kdc_configuration *config,
     189             :                      hdb_entry_ex *krbtgt,
     190             :                      krb5_principal cp,
     191             :                      EncTicketPart *tkt,
     192             :                      krb5_principals *delegated,
     193             :                      int *signedpath)
     194             : {
     195             :     krb5_error_code ret;
     196             :     krb5_data data;
     197       39896 :     krb5_crypto crypto = NULL;
     198             : 
     199       39896 :     if (delegated)
     200       39878 :         *delegated = NULL;
     201             : 
     202       39896 :     ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
     203       39896 :     if (ret == 0) {
     204             :         KRB5SignedPathData spd;
     205             :         KRB5SignedPath sp;
     206       39599 :         size_t size = 0;
     207             : 
     208       39599 :         ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
     209       39599 :         krb5_data_free(&data);
     210       39599 :         if (ret)
     211           2 :             return ret;
     212             : 
     213       39599 :         spd.client = cp;
     214       39599 :         spd.authtime = tkt->authtime;
     215       39599 :         spd.delegated = sp.delegated;
     216       39599 :         spd.method_data = sp.method_data;
     217             : 
     218       39599 :         ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
     219             :                            &spd, &size, ret);
     220       39599 :         if (ret) {
     221           0 :             free_KRB5SignedPath(&sp);
     222           0 :             return ret;
     223             :         }
     224       39599 :         if (data.length != size)
     225           0 :             krb5_abortx(context, "internal asn.1 encoder error");
     226             : 
     227             :         {
     228             :             Key *key;
     229       39599 :             ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
     230       39599 :             if (ret == 0)
     231       39599 :                 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
     232       39599 :             if (ret) {
     233           0 :                 free(data.data);
     234           0 :                 free_KRB5SignedPath(&sp);
     235           0 :                 return ret;
     236             :             }
     237             :         }
     238       39599 :         ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
     239             :                                    data.data, data.length,
     240             :                                    &sp.cksum);
     241       39599 :         krb5_crypto_destroy(context, crypto);
     242       39599 :         free(data.data);
     243       39599 :         if (ret) {
     244           2 :             free_KRB5SignedPath(&sp);
     245           2 :             kdc_log(context, config, 5,
     246             :                     "KRB5SignedPath not signed correctly, not marking as signed");
     247           2 :             return 0;
     248             :         }
     249             : 
     250       39597 :         if (delegated && sp.delegated) {
     251             : 
     252           0 :             *delegated = malloc(sizeof(*sp.delegated));
     253           0 :             if (*delegated == NULL) {
     254           0 :                 free_KRB5SignedPath(&sp);
     255           0 :                 return ENOMEM;
     256             :             }
     257             : 
     258           0 :             ret = copy_Principals(*delegated, sp.delegated);
     259           0 :             if (ret) {
     260           0 :                 free_KRB5SignedPath(&sp);
     261           0 :                 free(*delegated);
     262           0 :                 *delegated = NULL;
     263           0 :                 return ret;
     264             :             }
     265             :         }
     266       39597 :         free_KRB5SignedPath(&sp);
     267             : 
     268       39597 :         *signedpath = 1;
     269             :     }
     270             : 
     271       38805 :     return 0;
     272             : }
     273             : 
     274             : /*
     275             :  *
     276             :  */
     277             : 
     278             : static krb5_error_code
     279       39896 : check_PAC(krb5_context context,
     280             :           krb5_kdc_configuration *config,
     281             :           const krb5_principal client_principal,
     282             :           const krb5_principal delegated_proxy_principal,
     283             :           hdb_entry_ex *client,
     284             :           hdb_entry_ex *server,
     285             :           hdb_entry_ex *krbtgt,
     286             :           const EncryptionKey *server_check_key,
     287             :           const EncryptionKey *server_sign_key,
     288             :           const EncryptionKey *krbtgt_sign_key,
     289             :           EncTicketPart *tkt,
     290             :           krb5_data *rspac,
     291             :           int *signedpath)
     292             : {
     293       39896 :     AuthorizationData *ad = tkt->authorization_data;
     294             :     unsigned i, j;
     295             :     krb5_error_code ret;
     296             : 
     297       39896 :     if (ad == NULL || ad->len == 0)
     298           0 :         return 0;
     299             : 
     300       38839 :     for (i = 0; i < ad->len; i++) {
     301             :         AuthorizationData child;
     302             : 
     303       39928 :         if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
     304           0 :             continue;
     305             : 
     306       39928 :         ret = decode_AuthorizationData(ad->val[i].ad_data.data,
     307       38839 :                                        ad->val[i].ad_data.length,
     308             :                                        &child,
     309             :                                        NULL);
     310       39928 :         if (ret) {
     311           0 :             krb5_set_error_message(context, ret, "Failed to decode "
     312             :                                    "IF_RELEVANT with %d", ret);
     313       39896 :             return ret;
     314             :         }
     315       38871 :         for (j = 0; j < child.len; j++) {
     316             : 
     317       39928 :             if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
     318       39896 :                 int signed_pac = 0;
     319             :                 krb5_pac pac;
     320             : 
     321             :                 /* Found PAC */
     322       79792 :                 ret = krb5_pac_parse(context,
     323       39896 :                                      child.val[j].ad_data.data,
     324       38807 :                                      child.val[j].ad_data.length,
     325             :                                      &pac);
     326       39896 :                 free_AuthorizationData(&child);
     327       39896 :                 if (ret)
     328           0 :                     return ret;
     329             : 
     330       39896 :                 ret = krb5_pac_verify(context, pac, tkt->authtime,
     331             :                                       client_principal,
     332             :                                       server_check_key, NULL);
     333       39896 :                 if (ret) {
     334           0 :                     krb5_pac_free(context, pac);
     335           0 :                     return ret;
     336             :                 }
     337             : 
     338       39896 :                 ret = _kdc_pac_verify(context, client_principal,
     339             :                                       delegated_proxy_principal,
     340             :                                       client, server, krbtgt, &pac, &signed_pac);
     341       39896 :                 if (ret) {
     342           0 :                     krb5_pac_free(context, pac);
     343           0 :                     return ret;
     344             :                 }
     345             : 
     346             :                 /*
     347             :                  * Only re-sign PAC if we could verify it with the PAC
     348             :                  * function. The no-verify case happens when we get in
     349             :                  * a PAC from cross realm from a Windows domain and
     350             :                  * that there is no PAC verification function.
     351             :                  */
     352       39896 :                 if (signed_pac) {
     353       39896 :                     *signedpath = 1;
     354       39896 :                     ret = _krb5_pac_sign(context, pac, tkt->authtime,
     355             :                                          client_principal,
     356             :                                          server_sign_key, krbtgt_sign_key, rspac);
     357             :                 }
     358       39896 :                 krb5_pac_free(context, pac);
     359             : 
     360       38807 :                 return ret;
     361             :             }
     362             :         }
     363          32 :         free_AuthorizationData(&child);
     364             :     }
     365           0 :     return 0;
     366             : }
     367             : 
     368             : /*
     369             :  *
     370             :  */
     371             : 
     372             : static krb5_error_code
     373       39871 : check_tgs_flags(krb5_context context,
     374             :                 krb5_kdc_configuration *config,
     375             :                 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
     376             : {
     377       39871 :     KDCOptions f = b->kdc_options;
     378             : 
     379       39871 :     if(f.validate){
     380           0 :         if(!tgt->flags.invalid || tgt->starttime == NULL){
     381           0 :             kdc_log(context, config, 0,
     382             :                     "Bad request to validate ticket");
     383           0 :             return KRB5KDC_ERR_BADOPTION;
     384             :         }
     385           0 :         if(*tgt->starttime > kdc_time){
     386           0 :             kdc_log(context, config, 0,
     387             :                     "Early request to validate ticket");
     388           0 :             return KRB5KRB_AP_ERR_TKT_NYV;
     389             :         }
     390             :         /* XXX  tkt = tgt */
     391           0 :         et->flags.invalid = 0;
     392       39871 :     }else if(tgt->flags.invalid){
     393           0 :         kdc_log(context, config, 0,
     394             :                 "Ticket-granting ticket has INVALID flag set");
     395           0 :         return KRB5KRB_AP_ERR_TKT_INVALID;
     396             :     }
     397             : 
     398       39871 :     if(f.forwardable){
     399       19479 :         if(!tgt->flags.forwardable){
     400         186 :             kdc_log(context, config, 0,
     401             :                     "Bad request for forwardable ticket");
     402         186 :             return KRB5KDC_ERR_BADOPTION;
     403             :         }
     404       19293 :         et->flags.forwardable = 1;
     405             :     }
     406       39685 :     if(f.forwarded){
     407       19229 :         if(!tgt->flags.forwardable){
     408           0 :             kdc_log(context, config, 0,
     409             :                     "Request to forward non-forwardable ticket");
     410           0 :             return KRB5KDC_ERR_BADOPTION;
     411             :         }
     412       19229 :         et->flags.forwarded = 1;
     413       19229 :         et->caddr = b->addresses;
     414             :     }
     415       39685 :     if(tgt->flags.forwarded)
     416         299 :         et->flags.forwarded = 1;
     417             : 
     418       39685 :     if(f.proxiable){
     419           0 :         if(!tgt->flags.proxiable){
     420           0 :             kdc_log(context, config, 0,
     421             :                     "Bad request for proxiable ticket");
     422           0 :             return KRB5KDC_ERR_BADOPTION;
     423             :         }
     424           0 :         et->flags.proxiable = 1;
     425             :     }
     426       39685 :     if(f.proxy){
     427           0 :         if(!tgt->flags.proxiable){
     428           0 :             kdc_log(context, config, 0,
     429             :                     "Request to proxy non-proxiable ticket");
     430           0 :             return KRB5KDC_ERR_BADOPTION;
     431             :         }
     432           0 :         et->flags.proxy = 1;
     433           0 :         et->caddr = b->addresses;
     434             :     }
     435       39685 :     if(tgt->flags.proxy)
     436           0 :         et->flags.proxy = 1;
     437             : 
     438       39685 :     if(f.allow_postdate){
     439           0 :         if(!tgt->flags.may_postdate){
     440           0 :             kdc_log(context, config, 0,
     441             :                     "Bad request for post-datable ticket");
     442           0 :             return KRB5KDC_ERR_BADOPTION;
     443             :         }
     444           0 :         et->flags.may_postdate = 1;
     445             :     }
     446       39685 :     if(f.postdated){
     447           0 :         if(!tgt->flags.may_postdate){
     448           0 :             kdc_log(context, config, 0,
     449             :                     "Bad request for postdated ticket");
     450           0 :             return KRB5KDC_ERR_BADOPTION;
     451             :         }
     452           0 :         if(b->from)
     453           0 :             *et->starttime = *b->from;
     454           0 :         et->flags.postdated = 1;
     455           0 :         et->flags.invalid = 1;
     456       39685 :     }else if(b->from && *b->from > kdc_time + context->max_skew){
     457           0 :         kdc_log(context, config, 0, "Ticket cannot be postdated");
     458           0 :         return KRB5KDC_ERR_CANNOT_POSTDATE;
     459             :     }
     460             : 
     461       39685 :     if(f.renewable){
     462          42 :         if(!tgt->flags.renewable || tgt->renew_till == NULL){
     463          12 :             kdc_log(context, config, 0,
     464             :                     "Bad request for renewable ticket");
     465          12 :             return KRB5KDC_ERR_BADOPTION;
     466             :         }
     467          30 :         et->flags.renewable = 1;
     468          30 :         ALLOC(et->renew_till);
     469          30 :         _kdc_fix_time(&b->rtime);
     470          30 :         *et->renew_till = *b->rtime;
     471             :     }
     472       39673 :     if(f.renew){
     473             :         time_t old_life;
     474          30 :         if(!tgt->flags.renewable || tgt->renew_till == NULL){
     475           0 :             kdc_log(context, config, 0,
     476             :                     "Request to renew non-renewable ticket");
     477           0 :             return KRB5KDC_ERR_BADOPTION;
     478             :         }
     479          30 :         old_life = tgt->endtime;
     480          30 :         if(tgt->starttime)
     481           0 :             old_life -= *tgt->starttime;
     482             :         else
     483          30 :             old_life -= tgt->authtime;
     484          30 :         et->endtime = *et->starttime + old_life;
     485          30 :         if (et->renew_till != NULL)
     486          30 :             et->endtime = min(*et->renew_till, et->endtime);
     487             :     }
     488             : 
     489             : #if 0
     490             :     /* checks for excess flags */
     491             :     if(f.request_anonymous && !config->allow_anonymous){
     492             :         kdc_log(context, config, 0,
     493             :                 "Request for anonymous ticket");
     494             :         return KRB5KDC_ERR_BADOPTION;
     495             :     }
     496             : #endif
     497       38584 :     return 0;
     498             : }
     499             : 
     500             : /*
     501             :  * Determine if constrained delegation is allowed from this client to this server
     502             :  */
     503             : 
     504             : static krb5_error_code
     505          18 : check_constrained_delegation(krb5_context context,
     506             :                              krb5_kdc_configuration *config,
     507             :                              HDB *clientdb,
     508             :                              hdb_entry_ex *client,
     509             :                              hdb_entry_ex *server,
     510             :                              krb5_const_principal target)
     511             : {
     512             :     const HDB_Ext_Constrained_delegation_acl *acl;
     513             :     krb5_error_code ret;
     514             :     size_t i;
     515             : 
     516             :     /*
     517             :      * constrained_delegation (S4U2Proxy) only works within
     518             :      * the same realm. We use the already canonicalized version
     519             :      * of the principals here, while "target" is the principal
     520             :      * provided by the client.
     521             :      */
     522          18 :     if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
     523           0 :         ret = KRB5KDC_ERR_BADOPTION;
     524           0 :         kdc_log(context, config, 0,
     525             :             "Bad request for constrained delegation");
     526           0 :         return ret;
     527             :     }
     528             : 
     529          18 :     if (clientdb->hdb_check_constrained_delegation) {
     530          18 :         ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
     531          18 :         if (ret == 0)
     532          18 :             return 0;
     533             :     } else {
     534             :         /* if client delegates to itself, that ok */
     535           0 :         if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
     536           0 :             return 0;
     537             : 
     538           0 :         ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
     539           0 :         if (ret) {
     540           0 :             krb5_clear_error_message(context);
     541           0 :             return ret;
     542             :         }
     543             : 
     544           0 :         if (acl) {
     545           0 :             for (i = 0; i < acl->len; i++) {
     546           0 :                 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
     547           0 :                     return 0;
     548             :             }
     549             :         }
     550           0 :         ret = KRB5KDC_ERR_BADOPTION;
     551             :     }
     552           0 :     kdc_log(context, config, 0,
     553             :             "Bad request for constrained delegation");
     554           0 :     return ret;
     555             : }
     556             : 
     557             : /*
     558             :  * Determine if s4u2self is allowed from this client to this server
     559             :  *
     560             :  * For example, regardless of the principal being impersonated, if the
     561             :  * 'client' and 'server' are the same, then it's safe.
     562             :  */
     563             : 
     564             : static krb5_error_code
     565         622 : check_s4u2self(krb5_context context,
     566             :                krb5_kdc_configuration *config,
     567             :                HDB *clientdb,
     568             :                hdb_entry_ex *client,
     569             :                krb5_const_principal server)
     570             : {
     571             :     krb5_error_code ret;
     572             : 
     573             :     /* if client does a s4u2self to itself, that ok */
     574         622 :     if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
     575         309 :         return 0;
     576             : 
     577         313 :     if (clientdb->hdb_check_s4u2self) {
     578         313 :         ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
     579         313 :         if (ret == 0)
     580         313 :             return 0;
     581             :     } else {
     582           0 :         ret = KRB5KDC_ERR_BADOPTION;
     583             :     }
     584           0 :     return ret;
     585             : }
     586             : 
     587             : /*
     588             :  *
     589             :  */
     590             : 
     591             : static krb5_error_code
     592          18 : verify_flags (krb5_context context,
     593             :               krb5_kdc_configuration *config,
     594             :               const EncTicketPart *et,
     595             :               const char *pstr)
     596             : {
     597          18 :     if(et->endtime < kdc_time){
     598           0 :         kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
     599           0 :         return KRB5KRB_AP_ERR_TKT_EXPIRED;
     600             :     }
     601          18 :     if(et->flags.invalid){
     602           0 :         kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
     603           0 :         return KRB5KRB_AP_ERR_TKT_NYV;
     604             :     }
     605          18 :     return 0;
     606             : }
     607             : 
     608             : /*
     609             :  *
     610             :  */
     611             : 
     612             : static krb5_error_code
     613       39673 : fix_transited_encoding(krb5_context context,
     614             :                        krb5_kdc_configuration *config,
     615             :                        krb5_boolean check_policy,
     616             :                        const TransitedEncoding *tr,
     617             :                        EncTicketPart *et,
     618             :                        const char *client_realm,
     619             :                        const char *server_realm,
     620             :                        const char *tgt_realm)
     621             : {
     622       39673 :     krb5_error_code ret = 0;
     623             :     char **realms, **tmp;
     624             :     unsigned int num_realms;
     625             :     size_t i;
     626             : 
     627       39673 :     switch (tr->tr_type) {
     628       38584 :     case DOMAIN_X500_COMPRESS:
     629       38584 :         break;
     630           0 :     case 0:
     631             :         /*
     632             :          * Allow empty content of type 0 because that is was Microsoft
     633             :          * generates in their TGT.
     634             :          */
     635           0 :         if (tr->contents.length == 0)
     636           0 :             break;
     637           0 :         kdc_log(context, config, 0,
     638             :                 "Transited type 0 with non empty content");
     639           0 :         return KRB5KDC_ERR_TRTYPE_NOSUPP;
     640           0 :     default:
     641           0 :         kdc_log(context, config, 0,
     642             :                 "Unknown transited type: %u", tr->tr_type);
     643           0 :         return KRB5KDC_ERR_TRTYPE_NOSUPP;
     644             :     }
     645             : 
     646       38584 :     ret = krb5_domain_x500_decode(context,
     647             :                                   tr->contents,
     648             :                                   &realms,
     649             :                                   &num_realms,
     650             :                                   client_realm,
     651             :                                   server_realm);
     652       39673 :     if(ret){
     653           0 :         krb5_warn(context, ret,
     654             :                   "Decoding transited encoding");
     655           0 :         return ret;
     656             :     }
     657       39673 :     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
     658             :         /* not us, so add the previous realm to transited set */
     659           0 :         if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
     660           0 :             ret = ERANGE;
     661           0 :             goto free_realms;
     662             :         }
     663           0 :         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
     664           0 :         if(tmp == NULL){
     665           0 :             ret = ENOMEM;
     666           0 :             goto free_realms;
     667             :         }
     668           0 :         realms = tmp;
     669           0 :         realms[num_realms] = strdup(tgt_realm);
     670           0 :         if(realms[num_realms] == NULL){
     671           0 :             ret = ENOMEM;
     672           0 :             goto free_realms;
     673             :         }
     674           0 :         num_realms++;
     675             :     }
     676       39673 :     if(num_realms == 0) {
     677       39673 :         if(strcmp(client_realm, server_realm))
     678          57 :             kdc_log(context, config, 0,
     679             :                     "cross-realm %s -> %s", client_realm, server_realm);
     680             :     } else {
     681           0 :         size_t l = 0;
     682             :         char *rs;
     683           0 :         for(i = 0; i < num_realms; i++)
     684           0 :             l += strlen(realms[i]) + 2;
     685           0 :         rs = malloc(l);
     686           0 :         if(rs != NULL) {
     687           0 :             *rs = '\0';
     688           0 :             for(i = 0; i < num_realms; i++) {
     689           0 :                 if(i > 0)
     690           0 :                     strlcat(rs, ", ", l);
     691           0 :                 strlcat(rs, realms[i], l);
     692             :             }
     693           0 :             kdc_log(context, config, 0,
     694             :                     "cross-realm %s -> %s via [%s]",
     695             :                     client_realm, server_realm, rs);
     696           0 :             free(rs);
     697             :         }
     698             :     }
     699       39673 :     if(check_policy) {
     700       39673 :         ret = krb5_check_transited(context, client_realm,
     701             :                                    server_realm,
     702             :                                    realms, num_realms, NULL);
     703       39673 :         if(ret) {
     704           0 :             krb5_warn(context, ret, "cross-realm %s -> %s",
     705             :                       client_realm, server_realm);
     706           0 :             goto free_realms;
     707             :         }
     708       39673 :         et->flags.transited_policy_checked = 1;
     709             :     }
     710       39673 :     et->transited.tr_type = DOMAIN_X500_COMPRESS;
     711       39673 :     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
     712       39673 :     if(ret)
     713           0 :         krb5_warn(context, ret, "Encoding transited encoding");
     714       79346 :   free_realms:
     715       39673 :     for(i = 0; i < num_realms; i++)
     716           0 :         free(realms[i]);
     717       39673 :     free(realms);
     718       39673 :     return ret;
     719             : }
     720             : 
     721             : 
     722             : static krb5_error_code
     723       39871 : tgs_make_reply(krb5_context context,
     724             :                krb5_kdc_configuration *config,
     725             :                KDC_REQ_BODY *b,
     726             :                krb5_const_principal tgt_name,
     727             :                const EncTicketPart *tgt,
     728             :                const krb5_keyblock *replykey,
     729             :                int rk_is_subkey,
     730             :                const EncryptionKey *serverkey,
     731             :                const krb5_keyblock *sessionkey,
     732             :                krb5_kvno kvno,
     733             :                AuthorizationData *auth_data,
     734             :                hdb_entry_ex *server,
     735             :                krb5_principal server_principal,
     736             :                const char *server_name,
     737             :                hdb_entry_ex *client,
     738             :                krb5_principal client_principal,
     739             :                hdb_entry_ex *krbtgt,
     740             :                krb5_enctype krbtgt_etype,
     741             :                krb5_principals spp,
     742             :                const krb5_data *rspac,
     743             :                const METHOD_DATA *enc_pa_data,
     744             :                const char **e_text,
     745             :                krb5_data *reply)
     746             : {
     747             :     KDC_REP rep;
     748             :     EncKDCRepPart ek;
     749             :     EncTicketPart et;
     750       39871 :     KDCOptions f = b->kdc_options;
     751             :     krb5_error_code ret;
     752       39871 :     int is_weak = 0;
     753             : 
     754       39871 :     memset(&rep, 0, sizeof(rep));
     755       39871 :     memset(&et, 0, sizeof(et));
     756       39871 :     memset(&ek, 0, sizeof(ek));
     757             : 
     758       39871 :     rep.pvno = 5;
     759       39871 :     rep.msg_type = krb_tgs_rep;
     760             : 
     761       39871 :     et.authtime = tgt->authtime;
     762       39871 :     _kdc_fix_time(&b->till);
     763       39871 :     et.endtime = min(tgt->endtime, *b->till);
     764       39871 :     ALLOC(et.starttime);
     765       39871 :     *et.starttime = kdc_time;
     766             : 
     767       39871 :     ret = check_tgs_flags(context, config, b, tgt, &et);
     768       39871 :     if(ret)
     769         198 :         goto out;
     770             : 
     771             :     /* We should check the transited encoding if:
     772             :        1) the request doesn't ask not to be checked
     773             :        2) globally enforcing a check
     774             :        3) principal requires checking
     775             :        4) we allow non-check per-principal, but principal isn't marked as allowing this
     776             :        5) we don't globally allow this
     777             :     */
     778             : 
     779             : #define GLOBAL_FORCE_TRANSITED_CHECK            \
     780             :     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
     781             : #define GLOBAL_ALLOW_PER_PRINCIPAL                      \
     782             :     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
     783             : #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK                    \
     784             :     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
     785             : 
     786             : /* these will consult the database in future release */
     787             : #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)              0
     788             : #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)      0
     789             : 
     790      119019 :     ret = fix_transited_encoding(context, config,
     791       39673 :                                  !f.disable_transited_check ||
     792           0 :                                  GLOBAL_FORCE_TRANSITED_CHECK ||
     793             :                                  PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
     794             :                                  !((GLOBAL_ALLOW_PER_PRINCIPAL &&
     795             :                                     PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
     796           0 :                                    GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
     797             :                                  &tgt->transited, &et,
     798             :                                  krb5_principal_get_realm(context, client_principal),
     799       39673 :                                  krb5_principal_get_realm(context, server->entry.principal),
     800       39673 :                                  krb5_principal_get_realm(context, krbtgt->entry.principal));
     801       39673 :     if(ret)
     802           0 :         goto out;
     803             : 
     804       39673 :     copy_Realm(&server_principal->realm, &rep.ticket.realm);
     805       39673 :     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
     806       39673 :     copy_Realm(&tgt_name->realm, &rep.crealm);
     807             : /*
     808             :     if (f.request_anonymous)
     809             :         _kdc_make_anonymous_principalname (&rep.cname);
     810             :     else */
     811             : 
     812       39673 :     copy_PrincipalName(&tgt_name->name, &rep.cname);
     813       39673 :     rep.ticket.tkt_vno = 5;
     814             : 
     815       39673 :     ek.caddr = et.caddr;
     816       39673 :     if(et.caddr == NULL)
     817       39673 :         et.caddr = tgt->caddr;
     818             : 
     819             :     {
     820             :         time_t life;
     821       39673 :         life = et.endtime - *et.starttime;
     822       39673 :         if(client && client->entry.max_life)
     823       39616 :             life = min(life, *client->entry.max_life);
     824       39673 :         if(server->entry.max_life)
     825       38823 :             life = min(life, *server->entry.max_life);
     826       39673 :         et.endtime = *et.starttime + life;
     827             :     }
     828       39673 :     if(f.renewable_ok && tgt->flags.renewable &&
     829           0 :        et.renew_till == NULL && et.endtime < *b->till &&
     830           0 :        tgt->renew_till != NULL)
     831             :     {
     832           0 :         et.flags.renewable = 1;
     833           0 :         ALLOC(et.renew_till);
     834           0 :         *et.renew_till = *b->till;
     835             :     }
     836       39673 :     if(et.renew_till){
     837             :         time_t renew;
     838          30 :         renew = *et.renew_till - et.authtime;
     839          30 :         if(client && client->entry.max_renew)
     840          30 :             renew = min(renew, *client->entry.max_renew);
     841          30 :         if(server->entry.max_renew)
     842          30 :             renew = min(renew, *server->entry.max_renew);
     843          30 :         *et.renew_till = et.authtime + renew;
     844             :     }
     845             : 
     846       39673 :     if(et.renew_till){
     847          30 :         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
     848          30 :         *et.starttime = min(*et.starttime, *et.renew_till);
     849          30 :         et.endtime = min(et.endtime, *et.renew_till);
     850             :     }
     851             : 
     852       39673 :     *et.starttime = min(*et.starttime, et.endtime);
     853             : 
     854       39673 :     if(*et.starttime == et.endtime){
     855           0 :         ret = KRB5KDC_ERR_NEVER_VALID;
     856           0 :         goto out;
     857             :     }
     858       39673 :     if(et.renew_till && et.endtime == *et.renew_till){
     859           0 :         free(et.renew_till);
     860           0 :         et.renew_till = NULL;
     861           0 :         et.flags.renewable = 0;
     862             :     }
     863             : 
     864       39673 :     et.flags.pre_authent = tgt->flags.pre_authent;
     865       39673 :     et.flags.hw_authent  = tgt->flags.hw_authent;
     866       39673 :     et.flags.anonymous   = tgt->flags.anonymous;
     867       39673 :     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
     868             : 
     869             :     /* See MS-KILE 3.3.5.1 */
     870       39673 :     if (!server->entry.flags.forwardable)
     871           1 :         et.flags.forwardable = 0;
     872       39673 :     if (!server->entry.flags.proxiable)
     873         851 :         et.flags.proxiable = 0;
     874             : 
     875       39673 :     if(rspac->length) {
     876             :         /*
     877             :          * No not need to filter out the any PAC from the
     878             :          * auth_data since it's signed by the KDC.
     879             :          */
     880       39673 :         ret = _kdc_tkt_add_if_relevant_ad(context, &et,
     881             :                                           KRB5_AUTHDATA_WIN2K_PAC, rspac);
     882       39673 :         if (ret)
     883           0 :             goto out;
     884             :     }
     885             : 
     886       39673 :     if (auth_data) {
     887           0 :         unsigned int i = 0;
     888             : 
     889             :         /* XXX check authdata */
     890             : 
     891           0 :         if (et.authorization_data == NULL) {
     892           0 :             et.authorization_data = calloc(1, sizeof(*et.authorization_data));
     893           0 :             if (et.authorization_data == NULL) {
     894           0 :                 ret = ENOMEM;
     895           0 :                 krb5_set_error_message(context, ret, "malloc: out of memory");
     896           0 :                 goto out;
     897             :             }
     898             :         }
     899           0 :         for(i = 0; i < auth_data->len ; i++) {
     900           0 :             ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
     901           0 :             if (ret) {
     902           0 :                 krb5_set_error_message(context, ret, "malloc: out of memory");
     903           0 :                 goto out;
     904             :             }
     905             :         }
     906             : 
     907             :         /* Filter out type KRB5SignedPath */
     908           0 :         ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
     909           0 :         if (ret == 0) {
     910           0 :             if (et.authorization_data->len == 1) {
     911           0 :                 free_AuthorizationData(et.authorization_data);
     912           0 :                 free(et.authorization_data);
     913           0 :                 et.authorization_data = NULL;
     914             :             } else {
     915           0 :                 AuthorizationData *ad = et.authorization_data;
     916           0 :                 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
     917           0 :                 ad->len--;
     918             :             }
     919             :         }
     920             :     }
     921             : 
     922       39673 :     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
     923       39673 :     if (ret)
     924           0 :         goto out;
     925       39673 :     et.crealm = tgt_name->realm;
     926       39673 :     et.cname = tgt_name->name;
     927             : 
     928       39673 :     ek.key = et.key;
     929             :     /* MIT must have at least one last_req */
     930       39673 :     ek.last_req.len = 1;
     931       39673 :     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
     932       39673 :     if (ek.last_req.val == NULL) {
     933           0 :         ret = ENOMEM;
     934           0 :         goto out;
     935             :     }
     936       39673 :     ek.nonce = b->nonce;
     937       39673 :     ek.flags = et.flags;
     938       39673 :     ek.authtime = et.authtime;
     939       39673 :     ek.starttime = et.starttime;
     940       39673 :     ek.endtime = et.endtime;
     941       39673 :     ek.renew_till = et.renew_till;
     942       39673 :     ek.srealm = rep.ticket.realm;
     943       39673 :     ek.sname = rep.ticket.sname;
     944             : 
     945       39673 :     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
     946             :                        et.endtime, et.renew_till);
     947             : 
     948             :     /* Don't sign cross realm tickets, they can't be checked anyway */
     949             :     {
     950       40423 :         char *r = get_krbtgt_realm(&ek.sname);
     951             : 
     952       39334 :         if (r == NULL || strcmp(r, ek.srealm) == 0) {
     953       38527 :             ret = _kdc_add_KRB5SignedPath(context,
     954             :                                           config,
     955             :                                           krbtgt,
     956             :                                           krbtgt_etype,
     957             :                                           client_principal,
     958             :                                           NULL,
     959             :                                           spp,
     960             :                                           &et);
     961       38527 :             if (ret)
     962           0 :                 goto out;
     963             :         }
     964             :     }
     965             : 
     966       39673 :     if (enc_pa_data->len) {
     967         302 :         rep.padata = calloc(1, sizeof(*rep.padata));
     968         302 :         if (rep.padata == NULL) {
     969           0 :             ret = ENOMEM;
     970           0 :             goto out;
     971             :         }
     972         302 :         ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
     973         302 :         if (ret)
     974           0 :             goto out;
     975             :     }
     976             : 
     977       39673 :     if (krb5_enctype_valid(context, et.key.keytype) != 0
     978           0 :         && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
     979             :     {
     980           0 :         krb5_enctype_enable(context, et.key.keytype);
     981           0 :         is_weak = 1;
     982             :     }
     983             : 
     984             : 
     985             :     /* It is somewhat unclear where the etype in the following
     986             :        encryption should come from. What we have is a session
     987             :        key in the passed tgt, and a list of preferred etypes
     988             :        *for the new ticket*. Should we pick the best possible
     989             :        etype, given the keytype in the tgt, or should we look
     990             :        at the etype list here as well?  What if the tgt
     991             :        session key is DES3 and we want a ticket with a (say)
     992             :        CAST session key. Should the DES3 etype be added to the
     993             :        etype list, even if we don't want a session key with
     994             :        DES3? */
     995       39673 :     ret = _kdc_encode_reply(context, config,
     996       39673 :                             &rep, &et, &ek, et.key.keytype,
     997             :                             kvno,
     998             :                             serverkey, 0, replykey, rk_is_subkey,
     999             :                             e_text, reply);
    1000       39673 :     if (is_weak)
    1001           0 :         krb5_enctype_disable(context, et.key.keytype);
    1002             : 
    1003       78455 : out:
    1004       39871 :     free_TGS_REP(&rep);
    1005       39871 :     free_TransitedEncoding(&et.transited);
    1006       39871 :     if(et.starttime)
    1007       39871 :         free(et.starttime);
    1008       39871 :     if(et.renew_till)
    1009          30 :         free(et.renew_till);
    1010       39871 :     if(et.authorization_data) {
    1011       39673 :         free_AuthorizationData(et.authorization_data);
    1012       39673 :         free(et.authorization_data);
    1013             :     }
    1014       39871 :     free_LastReq(&ek.last_req);
    1015       40960 :     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
    1016       39871 :     free_EncryptionKey(&et.key);
    1017       39871 :     return ret;
    1018             : }
    1019             : 
    1020             : static krb5_error_code
    1021       40652 : tgs_check_authenticator(krb5_context context,
    1022             :                         krb5_kdc_configuration *config,
    1023             :                         krb5_auth_context ac,
    1024             :                         KDC_REQ_BODY *b,
    1025             :                         const char **e_text,
    1026             :                         krb5_keyblock *key)
    1027             : {
    1028             :     krb5_authenticator auth;
    1029       40652 :     size_t len = 0;
    1030             :     unsigned char *buf;
    1031             :     size_t buf_size;
    1032             :     krb5_error_code ret;
    1033             :     krb5_crypto crypto;
    1034             : 
    1035       40652 :     krb5_auth_con_getauthenticator(context, ac, &auth);
    1036       40652 :     if(auth->cksum == NULL){
    1037           0 :         kdc_log(context, config, 0, "No authenticator in request");
    1038           0 :         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
    1039           0 :         goto out;
    1040             :     }
    1041             :     /*
    1042             :      * according to RFC1510 it doesn't need to be keyed,
    1043             :      * but according to the latest draft it needs to.
    1044             :      */
    1045       40652 :     if (
    1046             : #if 0
    1047             : !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
    1048             :         ||
    1049             : #endif
    1050       40652 :  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
    1051           0 :         kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
    1052           0 :                 auth->cksum->cksumtype);
    1053           0 :         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
    1054           0 :         goto out;
    1055             :     }
    1056             : 
    1057             :     /* XXX should not re-encode this */
    1058       40652 :     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
    1059       40652 :     if(ret){
    1060           0 :         const char *msg = krb5_get_error_message(context, ret);
    1061           0 :         kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
    1062           0 :         krb5_free_error_message(context, msg);
    1063           0 :         goto out;
    1064             :     }
    1065       40652 :     if(buf_size != len) {
    1066           0 :         free(buf);
    1067           0 :         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
    1068           0 :         *e_text = "KDC internal error";
    1069           0 :         ret = KRB5KRB_ERR_GENERIC;
    1070           0 :         goto out;
    1071             :     }
    1072       40652 :     ret = krb5_crypto_init(context, key, 0, &crypto);
    1073       40652 :     if (ret) {
    1074           0 :         const char *msg = krb5_get_error_message(context, ret);
    1075           0 :         free(buf);
    1076           0 :         kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
    1077           0 :         krb5_free_error_message(context, msg);
    1078           0 :         goto out;
    1079             :     }
    1080       40652 :     ret = krb5_verify_checksum(context,
    1081             :                                crypto,
    1082             :                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
    1083             :                                buf,
    1084             :                                len,
    1085       40652 :                                auth->cksum);
    1086       40652 :     free(buf);
    1087       40652 :     krb5_crypto_destroy(context, crypto);
    1088       40652 :     if(ret){
    1089           2 :         const char *msg = krb5_get_error_message(context, ret);
    1090           2 :         kdc_log(context, config, 0,
    1091             :                 "Failed to verify authenticator checksum: %s", msg);
    1092           2 :         krb5_free_error_message(context, msg);
    1093             :     }
    1094       81302 : out:
    1095       40652 :     free_Authenticator(auth);
    1096       40652 :     free(auth);
    1097       40652 :     return ret;
    1098             : }
    1099             : 
    1100             : /*
    1101             :  *
    1102             :  */
    1103             : 
    1104             : static const char *
    1105           0 : find_rpath(krb5_context context, Realm crealm, Realm srealm)
    1106             : {
    1107           0 :     const char *new_realm = krb5_config_get_string(context,
    1108             :                                                    NULL,
    1109             :                                                    "capaths",
    1110             :                                                    crealm,
    1111             :                                                    srealm,
    1112             :                                                    NULL);
    1113           0 :     return new_realm;
    1114             : }
    1115             : 
    1116             : 
    1117             : static krb5_boolean
    1118           0 : need_referral(krb5_context context, krb5_kdc_configuration *config,
    1119             :               const KDCOptions * const options, krb5_principal server,
    1120             :               krb5_realm **realms)
    1121             : {
    1122             :     const char *name;
    1123             : 
    1124           0 :     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
    1125           0 :         return FALSE;
    1126             : 
    1127           0 :     if (server->name.name_string.len == 1)
    1128           0 :         name = server->name.name_string.val[0];
    1129           0 :     else if (server->name.name_string.len == 3) {
    1130             :         /*
    1131             :           This is used to give referrals for the
    1132             :           E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
    1133             :           SPN form, which is used for inter-domain communication in AD
    1134             :          */
    1135           0 :         name = server->name.name_string.val[2];
    1136           0 :         kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
    1137           0 :         *realms = malloc(sizeof(char *)*2);
    1138           0 :         if (*realms == NULL) {
    1139           0 :             krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
    1140           0 :             return FALSE;
    1141             :         }
    1142           0 :         (*realms)[0] = strdup(name);
    1143           0 :         (*realms)[1] = NULL;
    1144           0 :         return TRUE;
    1145           0 :     } else if (server->name.name_string.len > 1)
    1146           0 :         name = server->name.name_string.val[1];
    1147             :     else
    1148           0 :         return FALSE;
    1149             : 
    1150           0 :     kdc_log(context, config, 0, "Searching referral for %s", name);
    1151             : 
    1152           0 :     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
    1153             : }
    1154             : 
    1155             : static krb5_error_code
    1156       41890 : tgs_parse_request(krb5_context context,
    1157             :                   krb5_kdc_configuration *config,
    1158             :                   KDC_REQ_BODY *b,
    1159             :                   const PA_DATA *tgs_req,
    1160             :                   hdb_entry_ex **krbtgt,
    1161             :                   krb5_enctype *krbtgt_etype,
    1162             :                   krb5_ticket **ticket,
    1163             :                   const char **e_text,
    1164             :                   const char *from,
    1165             :                   const struct sockaddr *from_addr,
    1166             :                   time_t **csec,
    1167             :                   int **cusec,
    1168             :                   AuthorizationData **auth_data,
    1169             :                   krb5_keyblock **replykey,
    1170             :                   int *rk_is_subkey)
    1171             : {
    1172             :     static char failed[] = "<unparse_name failed>";
    1173             :     krb5_ap_req ap_req;
    1174             :     krb5_error_code ret;
    1175             :     krb5_principal princ;
    1176       41890 :     krb5_auth_context ac = NULL;
    1177             :     krb5_flags ap_req_options;
    1178             :     krb5_flags verify_ap_req_flags;
    1179             :     krb5_crypto crypto;
    1180             :     Key *tkey;
    1181       41890 :     krb5_keyblock *subkey = NULL;
    1182             :     unsigned usage;
    1183       41890 :     krb5uint32 kvno = 0;
    1184       41890 :     krb5uint32 *kvno_ptr = NULL;
    1185             : 
    1186       41890 :     *auth_data = NULL;
    1187       41890 :     *csec  = NULL;
    1188       41890 :     *cusec = NULL;
    1189       41890 :     *replykey = NULL;
    1190             : 
    1191       41890 :     memset(&ap_req, 0, sizeof(ap_req));
    1192       41890 :     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
    1193       41890 :     if(ret){
    1194           0 :         const char *msg = krb5_get_error_message(context, ret);
    1195           0 :         kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
    1196           0 :         krb5_free_error_message(context, msg);
    1197           0 :         goto out;
    1198             :     }
    1199             : 
    1200       42979 :     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
    1201             :         /* XXX check for ticket.sname == req.sname */
    1202           2 :         kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
    1203           2 :         ret = KRB5KDC_ERR_POLICY; /* ? */
    1204           2 :         goto out;
    1205             :     }
    1206             : 
    1207       41888 :     _krb5_principalname2krb5_principal(context,
    1208             :                                        &princ,
    1209             :                                        ap_req.ticket.sname,
    1210             :                                        ap_req.ticket.realm);
    1211             : 
    1212       41888 :     if (ap_req.ticket.enc_part.kvno) {
    1213       41831 :             kvno = *ap_req.ticket.enc_part.kvno;
    1214       41831 :             kvno_ptr = &kvno;
    1215             :     }
    1216       41888 :     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, kvno_ptr,
    1217             :                         NULL, krbtgt);
    1218             : 
    1219       41888 :     if(ret == HDB_ERR_NOT_FOUND_HERE) {
    1220             :         char *p;
    1221        1232 :         ret = krb5_unparse_name(context, princ, &p);
    1222        1232 :         if (ret != 0)
    1223           0 :             p = failed;
    1224        1232 :         krb5_free_principal(context, princ);
    1225        1232 :         kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
    1226        1232 :         if (ret == 0)
    1227        1232 :             free(p);
    1228        1232 :         ret = HDB_ERR_NOT_FOUND_HERE;
    1229        1232 :         goto out;
    1230       40656 :     } else if(ret){
    1231           0 :         const char *msg = krb5_get_error_message(context, ret);
    1232             :         char *p;
    1233           0 :         ret = krb5_unparse_name(context, princ, &p);
    1234           0 :         if (ret != 0)
    1235           0 :             p = failed;
    1236           0 :         krb5_free_principal(context, princ);
    1237           0 :         kdc_log(context, config, 0,
    1238             :                 "Ticket-granting ticket not found in database: %s", msg);
    1239           0 :         krb5_free_error_message(context, msg);
    1240           0 :         if (ret == 0)
    1241           0 :             free(p);
    1242           0 :         ret = KRB5KRB_AP_ERR_NOT_US;
    1243           0 :         goto out;
    1244             :     }
    1245             : 
    1246       81255 :     if(ap_req.ticket.enc_part.kvno &&
    1247       40599 :        *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
    1248             :         char *p;
    1249             : 
    1250           0 :         ret = krb5_unparse_name (context, princ, &p);
    1251           0 :         krb5_free_principal(context, princ);
    1252           0 :         if (ret != 0)
    1253           0 :             p = failed;
    1254           0 :         kdc_log(context, config, 0,
    1255             :                 "Ticket kvno = %d, DB kvno = %d (%s)",
    1256           0 :                 *ap_req.ticket.enc_part.kvno,
    1257           0 :                 (*krbtgt)->entry.kvno,
    1258             :                 p);
    1259           0 :         if (ret == 0)
    1260           0 :             free (p);
    1261           0 :         ret = KRB5KRB_AP_ERR_BADKEYVER;
    1262           0 :         goto out;
    1263             :     }
    1264             : 
    1265       40656 :     *krbtgt_etype = ap_req.ticket.enc_part.etype;
    1266             : 
    1267       40656 :     ret = hdb_enctype2key(context, &(*krbtgt)->entry,
    1268             :                           ap_req.ticket.enc_part.etype, &tkey);
    1269       40656 :     if(ret){
    1270           0 :         char *str = NULL, *p = NULL;
    1271             : 
    1272           0 :         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
    1273           0 :         krb5_unparse_name(context, princ, &p);
    1274           0 :         kdc_log(context, config, 0,
    1275             :                 "No server key with enctype %s found for %s",
    1276           0 :                 str ? str : "<unknown enctype>",
    1277           0 :                 p ? p : "<unparse_name failed>");
    1278           0 :         free(str);
    1279           0 :         free(p);
    1280           0 :         ret = KRB5KRB_AP_ERR_BADKEYVER;
    1281           0 :         goto out;
    1282             :     }
    1283             : 
    1284       40656 :     if (b->kdc_options.validate)
    1285           0 :         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
    1286             :     else
    1287       40656 :         verify_ap_req_flags = 0;
    1288             : 
    1289       40656 :     ret = krb5_verify_ap_req2(context,
    1290             :                               &ac,
    1291             :                               &ap_req,
    1292             :                               princ,
    1293       40656 :                               &tkey->key,
    1294             :                               verify_ap_req_flags,
    1295             :                               &ap_req_options,
    1296             :                               ticket,
    1297             :                               KRB5_KU_TGS_REQ_AUTH);
    1298             : 
    1299       40656 :     krb5_free_principal(context, princ);
    1300       40656 :     if(ret) {
    1301           4 :         const char *msg = krb5_get_error_message(context, ret);
    1302           4 :         kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
    1303           4 :         krb5_free_error_message(context, msg);
    1304           4 :         goto out;
    1305             :     }
    1306             : 
    1307             :     {
    1308             :         krb5_authenticator auth;
    1309             : 
    1310       40652 :         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
    1311       40652 :         if (ret == 0) {
    1312       40652 :             *csec   = malloc(sizeof(**csec));
    1313       40652 :             if (*csec == NULL) {
    1314           0 :                 krb5_free_authenticator(context, &auth);
    1315           0 :                 kdc_log(context, config, 0, "malloc failed");
    1316           0 :                 goto out;
    1317             :             }
    1318       40652 :             **csec  = auth->ctime;
    1319       40652 :             *cusec  = malloc(sizeof(**cusec));
    1320       40652 :             if (*cusec == NULL) {
    1321           0 :                 krb5_free_authenticator(context, &auth);
    1322           0 :                 kdc_log(context, config, 0, "malloc failed");
    1323           0 :                 goto out;
    1324             :             }
    1325       40652 :             **cusec  = auth->cusec;
    1326       40652 :             krb5_free_authenticator(context, &auth);
    1327             :         }
    1328             :     }
    1329             : 
    1330       40652 :     ret = tgs_check_authenticator(context, config,
    1331       40652 :                                   ac, b, e_text, &(*ticket)->ticket.key);
    1332       40652 :     if (ret) {
    1333           2 :         krb5_auth_con_free(context, ac);
    1334           2 :         goto out;
    1335             :     }
    1336             : 
    1337       40650 :     usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
    1338       40650 :     *rk_is_subkey = 1;
    1339             : 
    1340       40650 :     ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
    1341       40650 :     if(ret){
    1342           0 :         const char *msg = krb5_get_error_message(context, ret);
    1343           0 :         krb5_auth_con_free(context, ac);
    1344           0 :         kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
    1345           0 :         krb5_free_error_message(context, msg);
    1346           0 :         goto out;
    1347             :     }
    1348       40650 :     if(subkey == NULL){
    1349           2 :         usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
    1350           2 :         *rk_is_subkey = 0;
    1351             : 
    1352           2 :         ret = krb5_auth_con_getkey(context, ac, &subkey);
    1353           2 :         if(ret) {
    1354           0 :             const char *msg = krb5_get_error_message(context, ret);
    1355           0 :             krb5_auth_con_free(context, ac);
    1356           0 :             kdc_log(context, config, 0, "Failed to get session key: %s", msg);
    1357           0 :             krb5_free_error_message(context, msg);
    1358           0 :             goto out;
    1359             :         }
    1360             :     }
    1361       40650 :     if(subkey == NULL){
    1362           0 :         krb5_auth_con_free(context, ac);
    1363           0 :         kdc_log(context, config, 0,
    1364             :                 "Failed to get key for enc-authorization-data");
    1365           0 :         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
    1366           0 :         goto out;
    1367             :     }
    1368             : 
    1369       40650 :     *replykey = subkey;
    1370             : 
    1371       40650 :     if (b->enc_authorization_data) {
    1372             :         krb5_data ad;
    1373             : 
    1374           0 :         ret = krb5_crypto_init(context, subkey, 0, &crypto);
    1375           0 :         if (ret) {
    1376           0 :             const char *msg = krb5_get_error_message(context, ret);
    1377           0 :             krb5_auth_con_free(context, ac);
    1378           0 :             kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
    1379           0 :             krb5_free_error_message(context, msg);
    1380           0 :             goto out;
    1381             :         }
    1382           0 :         ret = krb5_decrypt_EncryptedData (context,
    1383             :                                           crypto,
    1384             :                                           usage,
    1385           0 :                                           b->enc_authorization_data,
    1386             :                                           &ad);
    1387           0 :         krb5_crypto_destroy(context, crypto);
    1388           0 :         if(ret){
    1389           0 :             krb5_auth_con_free(context, ac);
    1390           0 :             kdc_log(context, config, 0,
    1391             :                     "Failed to decrypt enc-authorization-data");
    1392           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
    1393           0 :             goto out;
    1394             :         }
    1395           0 :         ALLOC(*auth_data);
    1396           0 :         if (*auth_data == NULL) {
    1397           0 :             krb5_auth_con_free(context, ac);
    1398           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
    1399           0 :             goto out;
    1400             :         }
    1401           0 :         ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
    1402           0 :         if(ret){
    1403           0 :             krb5_auth_con_free(context, ac);
    1404           0 :             free(*auth_data);
    1405           0 :             *auth_data = NULL;
    1406           0 :             kdc_log(context, config, 0, "Failed to decode authorization data");
    1407           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
    1408           0 :             goto out;
    1409             :         }
    1410             :     }
    1411             : 
    1412       40650 :     krb5_auth_con_free(context, ac);
    1413             : 
    1414       41890 : out:
    1415       41890 :     free_AP_REQ(&ap_req);
    1416             : 
    1417       41890 :     return ret;
    1418             : }
    1419             : 
    1420             : static krb5_error_code
    1421         302 : build_server_referral(krb5_context context,
    1422             :                       krb5_kdc_configuration *config,
    1423             :                       krb5_crypto session,
    1424             :                       krb5_const_realm referred_realm,
    1425             :                       const PrincipalName *true_principal_name,
    1426             :                       const PrincipalName *requested_principal,
    1427             :                       krb5_data *outdata)
    1428             : {
    1429             :     PA_ServerReferralData ref;
    1430             :     krb5_error_code ret;
    1431             :     EncryptedData ed;
    1432             :     krb5_data data;
    1433         302 :     size_t size = 0;
    1434             : 
    1435         302 :     memset(&ref, 0, sizeof(ref));
    1436             : 
    1437         302 :     if (referred_realm) {
    1438         302 :         ALLOC(ref.referred_realm);
    1439         302 :         if (ref.referred_realm == NULL)
    1440           0 :             goto eout;
    1441         302 :         *ref.referred_realm = strdup(referred_realm);
    1442         302 :         if (*ref.referred_realm == NULL)
    1443           0 :             goto eout;
    1444             :     }
    1445         302 :     if (true_principal_name) {
    1446           0 :         ALLOC(ref.true_principal_name);
    1447           0 :         if (ref.true_principal_name == NULL)
    1448           0 :             goto eout;
    1449           0 :         ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
    1450           0 :         if (ret)
    1451           0 :             goto eout;
    1452             :     }
    1453         302 :     if (requested_principal) {
    1454         302 :         ALLOC(ref.requested_principal_name);
    1455         302 :         if (ref.requested_principal_name == NULL)
    1456           0 :             goto eout;
    1457         302 :         ret = copy_PrincipalName(requested_principal,
    1458             :                                  ref.requested_principal_name);
    1459         302 :         if (ret)
    1460           0 :             goto eout;
    1461             :     }
    1462             : 
    1463         302 :     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
    1464             :                        data.data, data.length,
    1465             :                        &ref, &size, ret);
    1466         302 :     free_PA_ServerReferralData(&ref);
    1467         302 :     if (ret)
    1468           0 :         return ret;
    1469         302 :     if (data.length != size)
    1470           0 :         krb5_abortx(context, "internal asn.1 encoder error");
    1471             : 
    1472         302 :     ret = krb5_encrypt_EncryptedData(context, session,
    1473             :                                      KRB5_KU_PA_SERVER_REFERRAL,
    1474             :                                      data.data, data.length,
    1475             :                                      0 /* kvno */, &ed);
    1476         302 :     free(data.data);
    1477         302 :     if (ret)
    1478           0 :         return ret;
    1479             : 
    1480         302 :     ASN1_MALLOC_ENCODE(EncryptedData,
    1481             :                        outdata->data, outdata->length,
    1482             :                        &ed, &size, ret);
    1483         302 :     free_EncryptedData(&ed);
    1484         302 :     if (ret)
    1485           0 :         return ret;
    1486         302 :     if (outdata->length != size)
    1487           0 :         krb5_abortx(context, "internal asn.1 encoder error");
    1488             : 
    1489         302 :     return 0;
    1490           0 : eout:
    1491           0 :     free_PA_ServerReferralData(&ref);
    1492           0 :     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
    1493           0 :     return ENOMEM;
    1494             : }
    1495             : 
    1496             : static krb5_error_code
    1497       40650 : tgs_build_reply(krb5_context context,
    1498             :                 krb5_kdc_configuration *config,
    1499             :                 KDC_REQ *req,
    1500             :                 KDC_REQ_BODY *b,
    1501             :                 hdb_entry_ex *krbtgt,
    1502             :                 krb5_enctype krbtgt_etype,
    1503             :                 const krb5_keyblock *replykey,
    1504             :                 int rk_is_subkey,
    1505             :                 krb5_ticket *ticket,
    1506             :                 krb5_data *reply,
    1507             :                 const char *from,
    1508             :                 const char **e_text,
    1509             :                 AuthorizationData **auth_data,
    1510             :                 const struct sockaddr *from_addr)
    1511             : {
    1512             :     krb5_error_code ret;
    1513       40650 :     krb5_principal cp = NULL, sp = NULL, tp = NULL, dp = NULL;
    1514       40650 :     krb5_principal krbtgt_principal = NULL;
    1515       40650 :     char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
    1516       40650 :     hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
    1517             :     HDB *clientdb, *s4u2self_impersonated_clientdb;
    1518       40650 :     krb5_realm ref_realm = NULL;
    1519       40650 :     EncTicketPart *tgt = &ticket->ticket;
    1520       40650 :     krb5_principals spp = NULL;
    1521             :     const EncryptionKey *ekey;
    1522             :     krb5_keyblock sessionkey;
    1523             :     krb5_kvno kvno;
    1524             :     krb5_data rspac;
    1525             : 
    1526       40650 :     hdb_entry_ex *krbtgt_out = NULL;
    1527             : 
    1528             :     METHOD_DATA enc_pa_data;
    1529             : 
    1530             :     PrincipalName *s;
    1531             :     Realm r;
    1532       40650 :     int nloop = 0;
    1533             :     EncTicketPart adtkt;
    1534             :     char opt_str[128];
    1535       40650 :     int signedpath = 0;
    1536             : 
    1537             :     Key *tkey_check;
    1538             :     Key *tkey_sign;
    1539       40650 :     int flags = HDB_F_FOR_TGS_REQ;
    1540             : 
    1541       40650 :     memset(&sessionkey, 0, sizeof(sessionkey));
    1542       40650 :     memset(&adtkt, 0, sizeof(adtkt));
    1543       40650 :     krb5_data_zero(&rspac);
    1544       40650 :     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
    1545             : 
    1546       40650 :     s = b->sname;
    1547       40650 :     r = b->realm;
    1548             : 
    1549       40650 :     if (b->kdc_options.canonicalize)
    1550       19576 :         flags |= HDB_F_CANON;
    1551             : 
    1552       40650 :     if(b->kdc_options.enc_tkt_in_skey){
    1553             :         Ticket *t;
    1554             :         hdb_entry_ex *uu;
    1555             :         krb5_principal p;
    1556             :         Key *uukey;
    1557           0 :         krb5uint32 second_kvno = 0;
    1558           0 :         krb5uint32 *kvno_ptr = NULL;
    1559             : 
    1560           0 :         if(b->additional_tickets == NULL ||
    1561           0 :            b->additional_tickets->len == 0){
    1562           0 :             ret = KRB5KDC_ERR_BADOPTION; /* ? */
    1563           0 :             kdc_log(context, config, 0,
    1564             :                     "No second ticket present in request");
    1565           0 :             goto out;
    1566             :         }
    1567           0 :         t = &b->additional_tickets->val[0];
    1568           0 :         if(!get_krbtgt_realm(&t->sname)){
    1569           0 :             kdc_log(context, config, 0,
    1570             :                     "Additional ticket is not a ticket-granting ticket");
    1571           0 :             ret = KRB5KDC_ERR_POLICY;
    1572           0 :             goto out;
    1573             :         }
    1574           0 :         _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
    1575           0 :         if(t->enc_part.kvno){
    1576           0 :             second_kvno = *t->enc_part.kvno;
    1577           0 :             kvno_ptr = &second_kvno;
    1578             :         }
    1579           0 :         ret = _kdc_db_fetch(context, config, p,
    1580             :                             HDB_F_GET_KRBTGT, kvno_ptr,
    1581             :                             NULL, &uu);
    1582           0 :         krb5_free_principal(context, p);
    1583           0 :         if(ret){
    1584           0 :             if (ret == HDB_ERR_NOENTRY)
    1585           0 :                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
    1586           0 :             goto out;
    1587             :         }
    1588           0 :         ret = hdb_enctype2key(context, &uu->entry,
    1589             :                               t->enc_part.etype, &uukey);
    1590           0 :         if(ret){
    1591           0 :             _kdc_free_ent(context, uu);
    1592           0 :             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
    1593           0 :             goto out;
    1594             :         }
    1595           0 :         ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
    1596           0 :         _kdc_free_ent(context, uu);
    1597           0 :         if(ret)
    1598           0 :             goto out;
    1599             : 
    1600           0 :         ret = verify_flags(context, config, &adtkt, spn);
    1601           0 :         if (ret)
    1602           0 :             goto out;
    1603             : 
    1604           0 :         s = &adtkt.cname;
    1605           0 :         r = adtkt.crealm;
    1606       40650 :     } else if (s == NULL) {
    1607           3 :         ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
    1608           3 :         krb5_set_error_message(context, ret, "No server in request");
    1609           3 :         goto out;
    1610             :     }
    1611             : 
    1612       40647 :     _krb5_principalname2krb5_principal(context, &sp, *s, r);
    1613       40647 :     ret = krb5_unparse_name(context, sp, &spn);
    1614       40647 :     if (ret)
    1615           0 :         goto out;
    1616       40647 :     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
    1617       40647 :     ret = krb5_unparse_name(context, cp, &cpn);
    1618       40647 :     if (ret)
    1619           0 :         goto out;
    1620       40647 :     unparse_flags (KDCOptions2int(b->kdc_options),
    1621             :                    asn1_KDCOptions_units(),
    1622             :                    opt_str, sizeof(opt_str));
    1623       40647 :     if(*opt_str)
    1624       39046 :         kdc_log(context, config, 0,
    1625             :                 "TGS-REQ %s from %s for %s [%s]",
    1626             :                 cpn, from, spn, opt_str);
    1627             :     else
    1628        1601 :         kdc_log(context, config, 0,
    1629             :                 "TGS-REQ %s from %s for %s", cpn, from, spn);
    1630             : 
    1631             :     /*
    1632             :      * Fetch server
    1633             :      */
    1634             : 
    1635       39558 : server_lookup:
    1636       40949 :     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
    1637             :                         NULL, NULL, &server);
    1638             : 
    1639       40949 :     if(ret == HDB_ERR_NOT_FOUND_HERE) {
    1640          47 :         kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
    1641          47 :         goto out;
    1642       40902 :     } else if (ret == HDB_ERR_WRONG_REALM) {
    1643         302 :         if (ref_realm)
    1644           0 :             free(ref_realm);
    1645         302 :         ref_realm = strdup(server->entry.principal->realm);
    1646         302 :         if (ref_realm == NULL) {
    1647           0 :             ret = ENOMEM;
    1648           0 :             goto out;
    1649             :         }
    1650             : 
    1651         302 :         kdc_log(context, config, 5,
    1652             :                 "Returning a referral to realm %s for "
    1653             :                 "server %s.",
    1654             :                 ref_realm, spn);
    1655         302 :         krb5_free_principal(context, sp);
    1656         302 :         sp = NULL;
    1657         302 :         free(spn);
    1658         302 :         spn = NULL;
    1659         302 :         ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
    1660             :                                   ref_realm, NULL);
    1661         302 :         if (ret)
    1662           0 :             goto out;
    1663         302 :         ret = krb5_unparse_name(context, sp, &spn);
    1664         302 :         if (ret)
    1665           0 :             goto out;
    1666             : 
    1667         302 :         goto server_lookup;
    1668       40600 :     } else if(ret){
    1669             :         const char *new_rlm, *msg;
    1670             :         Realm req_rlm;
    1671             :         krb5_realm *realms;
    1672             : 
    1673         722 :         if (!config->autodetect_referrals) {
    1674             :                 /* noop */
    1675           0 :         } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
    1676           0 :             if(nloop++ < 2) {
    1677           0 :                 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
    1678           0 :                 if(new_rlm) {
    1679           0 :                     kdc_log(context, config, 5, "krbtgt for realm %s "
    1680             :                             "not found, trying %s",
    1681             :                             req_rlm, new_rlm);
    1682           0 :                     krb5_free_principal(context, sp);
    1683           0 :                     free(spn);
    1684           0 :                     krb5_make_principal(context, &sp, r,
    1685             :                                         KRB5_TGS_NAME, new_rlm, NULL);
    1686           0 :                     ret = krb5_unparse_name(context, sp, &spn);
    1687           0 :                     if (ret)
    1688         722 :                         goto out;
    1689             : 
    1690           0 :                     if (ref_realm)
    1691           0 :                         free(ref_realm);
    1692           0 :                     ref_realm = strdup(new_rlm);
    1693           0 :                     goto server_lookup;
    1694             :                 }
    1695             :             }
    1696           0 :         } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
    1697           0 :             if (strcmp(realms[0], sp->realm) != 0) {
    1698           0 :                 kdc_log(context, config, 5,
    1699             :                         "Returning a referral to realm %s for "
    1700             :                         "server %s that was not found",
    1701             :                         realms[0], spn);
    1702           0 :                 krb5_free_principal(context, sp);
    1703           0 :                 free(spn);
    1704           0 :                 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
    1705             :                                     realms[0], NULL);
    1706           0 :                 ret = krb5_unparse_name(context, sp, &spn);
    1707           0 :                 if (ret)
    1708           0 :                     goto out;
    1709             : 
    1710           0 :                 if (ref_realm)
    1711           0 :                     free(ref_realm);
    1712           0 :                 ref_realm = strdup(realms[0]);
    1713             : 
    1714           0 :                 krb5_free_host_realm(context, realms);
    1715           0 :                 goto server_lookup;
    1716             :             }
    1717           0 :             krb5_free_host_realm(context, realms);
    1718             :         }
    1719         722 :         msg = krb5_get_error_message(context, ret);
    1720         722 :         kdc_log(context, config, 0,
    1721             :                 "Server not found in database: %s: %s", spn, msg);
    1722         722 :         krb5_free_error_message(context, msg);
    1723         722 :         if (ret == HDB_ERR_NOENTRY)
    1724         722 :             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
    1725         722 :         goto out;
    1726             :     }
    1727             : 
    1728             :     /*
    1729             :      * Select enctype, return key and kvno.
    1730             :      */
    1731             : 
    1732             :     {
    1733             :         krb5_enctype etype;
    1734             : 
    1735       39878 :         if(b->kdc_options.enc_tkt_in_skey) {
    1736             :             size_t i;
    1737           0 :             ekey = &adtkt.key;
    1738           0 :             for(i = 0; i < b->etype.len; i++)
    1739           0 :                 if (b->etype.val[i] == adtkt.key.keytype)
    1740           0 :                     break;
    1741           0 :             if(i == b->etype.len) {
    1742           0 :                 kdc_log(context, config, 0,
    1743             :                         "Addition ticket have not matching etypes");
    1744           0 :                 krb5_clear_error_message(context);
    1745           0 :                 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
    1746           0 :                 goto out;
    1747             :             }
    1748           0 :             etype = b->etype.val[i];
    1749           0 :             kvno = 0;
    1750             :         } else {
    1751             :             Key *skey;
    1752             : 
    1753       79756 :             ret = _kdc_find_etype(context,
    1754             :                                   config->tgs_use_strongest_session_key, FALSE,
    1755       39878 :                                   server, b->etype.val, b->etype.len, NULL,
    1756             :                                   &skey);
    1757       39878 :             if(ret) {
    1758           0 :                 kdc_log(context, config, 0,
    1759             :                         "Server (%s) has no support for etypes", spn);
    1760           0 :                 goto out;
    1761             :             }
    1762       39878 :             ekey = &skey->key;
    1763       39878 :             etype = skey->key.keytype;
    1764       39878 :             kvno = server->entry.kvno;
    1765             :         }
    1766             : 
    1767       39878 :         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
    1768       39878 :         if (ret)
    1769           0 :             goto out;
    1770             :     }
    1771             : 
    1772             :     /*
    1773             :      * Check that service is in the same realm as the krbtgt. If it's
    1774             :      * not the same, it's someone that is using a uni-directional trust
    1775             :      * backward.
    1776             :      */
    1777             : 
    1778             :     /*
    1779             :      * Validate authoriation data
    1780             :      */
    1781             : 
    1782       39878 :     ret = hdb_enctype2key(context, &krbtgt->entry,
    1783             :                           krbtgt_etype, &tkey_check);
    1784       39878 :     if(ret) {
    1785           0 :         kdc_log(context, config, 0,
    1786             :                     "Failed to find key for krbtgt PAC check");
    1787           0 :         goto out;
    1788             :     }
    1789             : 
    1790             :     /* Now refetch the primary krbtgt, and get the current kvno (the
    1791             :      * sign check may have been on an old kvno, and the server may
    1792             :      * have been an incoming trust) */
    1793       79756 :     ret = krb5_make_principal(context, &krbtgt_principal,
    1794             :                               krb5_principal_get_comp_string(context,
    1795       39878 :                                                              krbtgt->entry.principal,
    1796             :                                                              1),
    1797             :                               KRB5_TGS_NAME,
    1798             :                               krb5_principal_get_comp_string(context,
    1799       39878 :                                                              krbtgt->entry.principal,
    1800             :                                                              1), NULL);
    1801       39878 :     if(ret) {
    1802           0 :         kdc_log(context, config, 0,
    1803             :                     "Failed to generate krbtgt principal");
    1804           0 :         goto out;
    1805             :     }
    1806             : 
    1807       39878 :     ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
    1808       39878 :     krb5_free_principal(context, krbtgt_principal);
    1809       39878 :     if (ret) {
    1810             :         krb5_error_code ret2;
    1811             :         char *ktpn, *ktpn2;
    1812           0 :         ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
    1813           0 :         ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
    1814           0 :         kdc_log(context, config, 0,
    1815             :                 "Request with wrong krbtgt: %s, %s not found in our database",
    1816             :                 (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
    1817           0 :         if(ret == 0)
    1818           0 :             free(ktpn);
    1819           0 :         if(ret2 == 0)
    1820           0 :             free(ktpn2);
    1821           0 :         ret = KRB5KRB_AP_ERR_NOT_US;
    1822           0 :         goto out;
    1823             :     }
    1824             : 
    1825             :     /* The first realm is the realm of the service, the second is
    1826             :      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
    1827             :      * encrypted to.  The redirection via the krbtgt_out entry allows
    1828             :      * the DB to possibly correct the case of the realm (Samba4 does
    1829             :      * this) before the strcmp() */
    1830       39878 :     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
    1831       39878 :                krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
    1832             :         char *ktpn;
    1833           0 :         ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
    1834           0 :         kdc_log(context, config, 0,
    1835             :                 "Request with wrong krbtgt: %s",
    1836             :                 (ret == 0) ? ktpn : "<unknown>");
    1837           0 :         if(ret == 0)
    1838           0 :             free(ktpn);
    1839           0 :         ret = KRB5KRB_AP_ERR_NOT_US;
    1840             :     }
    1841             : 
    1842       39878 :     ret = hdb_enctype2key(context, &krbtgt_out->entry,
    1843             :                           krbtgt_etype, &tkey_sign);
    1844       39878 :     if(ret) {
    1845           0 :         kdc_log(context, config, 0,
    1846             :                     "Failed to find key for krbtgt PAC signature");
    1847           0 :         goto out;
    1848             :     }
    1849             : 
    1850       39878 :     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
    1851             :                         NULL, &clientdb, &client);
    1852       39878 :     if(ret == HDB_ERR_NOT_FOUND_HERE) {
    1853             :         /* This is OK, we are just trying to find out if they have
    1854             :          * been disabled or deleted in the meantime, missing secrets
    1855             :          * is OK */
    1856       39878 :     } else if(ret){
    1857             :         const char *krbtgt_realm, *msg;
    1858             : 
    1859             :         /*
    1860             :          * If the client belongs to the same realm as our krbtgt, it
    1861             :          * should exist in the local database.
    1862             :          *
    1863             :          */
    1864             : 
    1865          57 :         krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
    1866             : 
    1867          57 :         if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
    1868           0 :             if (ret == HDB_ERR_NOENTRY)
    1869           0 :                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    1870           0 :             kdc_log(context, config, 1, "Client no longer in database: %s",
    1871             :                     cpn);
    1872           0 :             goto out;
    1873             :         }
    1874             : 
    1875          57 :         msg = krb5_get_error_message(context, ret);
    1876          57 :         kdc_log(context, config, 1, "Client not found in database: %s", msg);
    1877          57 :         krb5_free_error_message(context, msg);
    1878             :     }
    1879             : 
    1880       39878 :     ret = check_PAC(context, config, cp, NULL,
    1881             :                     client, server, krbtgt,
    1882       39878 :                     &tkey_check->key,
    1883       39878 :                     ekey, &tkey_sign->key,
    1884             :                     tgt, &rspac, &signedpath);
    1885       39878 :     if (ret) {
    1886           0 :         const char *msg = krb5_get_error_message(context, ret);
    1887           0 :         kdc_log(context, config, 0,
    1888             :                 "Verify PAC failed for %s (%s) from %s with %s",
    1889             :                 spn, cpn, from, msg);
    1890           0 :         krb5_free_error_message(context, msg);
    1891           0 :         goto out;
    1892             :     }
    1893             : 
    1894             :     /* also check the krbtgt for signature */
    1895       39878 :     ret = check_KRB5SignedPath(context,
    1896             :                                config,
    1897             :                                krbtgt,
    1898             :                                cp,
    1899             :                                tgt,
    1900             :                                &spp,
    1901             :                                &signedpath);
    1902       39878 :     if (ret) {
    1903           0 :         const char *msg = krb5_get_error_message(context, ret);
    1904           0 :         kdc_log(context, config, 0,
    1905             :                 "KRB5SignedPath check failed for %s (%s) from %s with %s",
    1906             :                 spn, cpn, from, msg);
    1907           0 :         krb5_free_error_message(context, msg);
    1908           0 :         goto out;
    1909             :     }
    1910             : 
    1911             :     /*
    1912             :      * Process request
    1913             :      */
    1914             : 
    1915             :     /* by default the tgt principal matches the client principal */
    1916       39878 :     tp = cp;
    1917       39878 :     tpn = cpn;
    1918             : 
    1919       39878 :     if (client) {
    1920             :         const PA_DATA *sdata;
    1921       39821 :         int i = 0;
    1922             : 
    1923       39821 :         sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
    1924       39821 :         if (sdata) {
    1925             :             krb5_crypto crypto;
    1926             :             krb5_data datack;
    1927             :             PA_S4U2Self self;
    1928             :             const char *str;
    1929             : 
    1930         625 :             ret = decode_PA_S4U2Self(sdata->padata_value.data,
    1931             :                                      sdata->padata_value.length,
    1932             :                                      &self, NULL);
    1933         625 :             if (ret) {
    1934           0 :                 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
    1935           0 :                 goto out;
    1936             :             }
    1937             : 
    1938         625 :             if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
    1939           1 :                 free_PA_S4U2Self(&self);
    1940           1 :                 kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
    1941           1 :                 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
    1942           1 :                 goto out;
    1943             :             }
    1944             : 
    1945         624 :             ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
    1946         624 :             if (ret)
    1947           0 :                 goto out;
    1948             : 
    1949         624 :             ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
    1950         624 :             if (ret) {
    1951           0 :                 const char *msg = krb5_get_error_message(context, ret);
    1952           0 :                 free_PA_S4U2Self(&self);
    1953           0 :                 krb5_data_free(&datack);
    1954           0 :                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
    1955           0 :                 krb5_free_error_message(context, msg);
    1956           0 :                 goto out;
    1957             :             }
    1958             : 
    1959             :             /* Allow HMAC_MD5 checksum with any key type */
    1960         624 :             if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
    1961             :                 unsigned char csdata[16];
    1962             :                 Checksum cs;
    1963             : 
    1964         117 :                 cs.checksum.length = sizeof(csdata);
    1965         117 :                 cs.checksum.data = &csdata;
    1966             : 
    1967         234 :                 ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
    1968         117 :                                               datack.data, datack.length,
    1969             :                                               KRB5_KU_OTHER_CKSUM, &cs);
    1970         234 :                 if (ret == 0 &&
    1971         117 :                     krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
    1972           0 :                     ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
    1973             :             }
    1974             :             else {
    1975         507 :                 ret = krb5_verify_checksum(context,
    1976             :                                            crypto,
    1977             :                                            KRB5_KU_OTHER_CKSUM,
    1978             :                                            datack.data,
    1979             :                                            datack.length,
    1980             :                                            &self.cksum);
    1981             :             }
    1982         624 :             krb5_data_free(&datack);
    1983         624 :             krb5_crypto_destroy(context, crypto);
    1984         624 :             if (ret) {
    1985           2 :                 const char *msg = krb5_get_error_message(context, ret);
    1986           2 :                 free_PA_S4U2Self(&self);
    1987           2 :                 kdc_log(context, config, 0,
    1988             :                         "krb5_verify_checksum failed for S4U2Self: %s", msg);
    1989           2 :                 krb5_free_error_message(context, msg);
    1990           2 :                 goto out;
    1991             :             }
    1992             : 
    1993         622 :             ret = _krb5_principalname2krb5_principal(context,
    1994             :                                                      &tp,
    1995             :                                                      self.name,
    1996             :                                                      self.realm);
    1997         622 :             free_PA_S4U2Self(&self);
    1998         622 :             if (ret)
    1999           0 :                 goto out;
    2000             : 
    2001         622 :             ret = krb5_unparse_name(context, tp, &tpn);
    2002         622 :             if (ret)
    2003           0 :                 goto out;
    2004             : 
    2005         622 :             ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
    2006             :                                 NULL, &s4u2self_impersonated_clientdb,
    2007             :                                 &s4u2self_impersonated_client);
    2008         622 :             if (ret) {
    2009             :                 const char *msg;
    2010             : 
    2011             :                 /*
    2012             :                  * If the client belongs to the same realm as our krbtgt, it
    2013             :                  * should exist in the local database.
    2014             :                  *
    2015             :                  */
    2016             : 
    2017           0 :                 if (ret == HDB_ERR_NOENTRY)
    2018           0 :                     ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    2019           0 :                 msg = krb5_get_error_message(context, ret);
    2020           0 :                 kdc_log(context, config, 1,
    2021             :                         "S2U4Self principal to impersonate %s not found in database: %s",
    2022             :                         tpn, msg);
    2023           0 :                 krb5_free_error_message(context, msg);
    2024           0 :                 goto out;
    2025             :             }
    2026             : 
    2027             :             /* Ignore pw_end attributes (as Windows does),
    2028             :              * since S4U2Self is not password authentication. */
    2029         622 :             free(s4u2self_impersonated_client->entry.pw_end);
    2030         622 :             s4u2self_impersonated_client->entry.pw_end = NULL;
    2031             : 
    2032         622 :             ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
    2033             :                                   NULL, NULL, FALSE);
    2034         622 :             if (ret)
    2035           0 :                 goto out;
    2036             : 
    2037             :             /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
    2038         622 :             if(rspac.data) {
    2039         622 :                 krb5_pac p = NULL;
    2040         622 :                 krb5_data_free(&rspac);
    2041         622 :                 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &p);
    2042         622 :                 if (ret) {
    2043           0 :                     kdc_log(context, config, 0, "PAC generation failed for -- %s",
    2044             :                             tpn);
    2045           0 :                     goto out;
    2046             :                 }
    2047         622 :                 if (p != NULL) {
    2048         622 :                     ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
    2049         622 :                                          s4u2self_impersonated_client->entry.principal,
    2050         622 :                                          ekey, &tkey_sign->key,
    2051             :                                          &rspac);
    2052         622 :                     krb5_pac_free(context, p);
    2053         622 :                     if (ret) {
    2054           0 :                         kdc_log(context, config, 0, "PAC signing failed for -- %s",
    2055             :                                 tpn);
    2056           0 :                         goto out;
    2057             :                     }
    2058             :                 }
    2059             :             }
    2060             : 
    2061             :             /*
    2062             :              * Check that service doing the impersonating is
    2063             :              * requesting a ticket to it-self.
    2064             :              */
    2065         622 :             ret = check_s4u2self(context, config, clientdb, client, sp);
    2066         622 :             if (ret) {
    2067           0 :                 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
    2068             :                         "to impersonate to service "
    2069             :                         "(tried for user %s to service %s)",
    2070             :                         cpn, tpn, spn);
    2071           0 :                 goto out;
    2072             :             }
    2073             : 
    2074             :             /*
    2075             :              * If the service isn't trusted for authentication to
    2076             :              * delegation or if the impersonate client is disallowed
    2077             :              * forwardable, remove the forwardable flag.
    2078             :              */
    2079             : 
    2080         743 :             if (client->entry.flags.trusted_for_delegation &&
    2081         121 :                 s4u2self_impersonated_client->entry.flags.forwardable) {
    2082         120 :                 str = "[forwardable]";
    2083             :             } else {
    2084         502 :                 b->kdc_options.forwardable = 0;
    2085         502 :                 str = "";
    2086             :             }
    2087         622 :             kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
    2088             :                     "service %s %s", cpn, tpn, spn, str);
    2089             :         }
    2090             :     }
    2091             : 
    2092             :     /*
    2093             :      * Constrained delegation
    2094             :      */
    2095             : 
    2096       39875 :     if (client != NULL
    2097       39818 :         && b->additional_tickets != NULL
    2098          22 :         && b->additional_tickets->len != 0
    2099          22 :         && b->kdc_options.enc_tkt_in_skey == 0)
    2100             :     {
    2101          22 :         int ad_signedpath = 0;
    2102             :         Key *clientkey;
    2103             :         Ticket *t;
    2104             : 
    2105             :         /*
    2106             :          * Require that the KDC have issued the service's krbtgt (not
    2107             :          * self-issued ticket with kimpersonate(1).
    2108             :          */
    2109          22 :         if (!signedpath) {
    2110           0 :             ret = KRB5KDC_ERR_BADOPTION;
    2111           0 :             kdc_log(context, config, 0,
    2112             :                     "Constrained delegation done on service ticket %s/%s",
    2113             :                     cpn, spn);
    2114           0 :             goto out;
    2115             :         }
    2116             : 
    2117          22 :         t = &b->additional_tickets->val[0];
    2118             : 
    2119          22 :         ret = hdb_enctype2key(context, &client->entry,
    2120             :                               t->enc_part.etype, &clientkey);
    2121          22 :         if(ret){
    2122           0 :             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
    2123           0 :             goto out;
    2124             :         }
    2125             : 
    2126          22 :         ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
    2127          22 :         if (ret) {
    2128           0 :             kdc_log(context, config, 0,
    2129             :                     "failed to decrypt ticket for "
    2130             :                     "constrained delegation from %s to %s ", cpn, spn);
    2131           0 :             goto out;
    2132             :         }
    2133             : 
    2134          22 :         ret = _krb5_principalname2krb5_principal(context,
    2135             :                                                  &tp,
    2136             :                                                  adtkt.cname,
    2137             :                                                  adtkt.crealm);
    2138          22 :         if (ret)
    2139           0 :             goto out;
    2140             : 
    2141          22 :         ret = krb5_unparse_name(context, tp, &tpn);
    2142          22 :         if (ret)
    2143           0 :             goto out;
    2144             : 
    2145          22 :         ret = _krb5_principalname2krb5_principal(context,
    2146             :                                                  &dp,
    2147             :                                                  t->sname,
    2148             :                                                  t->realm);
    2149          22 :         if (ret)
    2150           0 :             goto out;
    2151             : 
    2152          22 :         ret = krb5_unparse_name(context, dp, &dpn);
    2153          22 :         if (ret)
    2154           0 :             goto out;
    2155             : 
    2156             :         /* check that ticket is valid */
    2157          22 :         if (adtkt.flags.forwardable == 0) {
    2158           4 :             kdc_log(context, config, 0,
    2159             :                     "Missing forwardable flag on ticket for "
    2160             :                     "constrained delegation from %s (%s) as %s to %s ",
    2161             :                     cpn, dpn, tpn, spn);
    2162           4 :             ret = KRB5KDC_ERR_BADOPTION;
    2163           4 :             goto out;
    2164             :         }
    2165             : 
    2166          18 :         ret = check_constrained_delegation(context, config, clientdb,
    2167             :                                            client, server, sp);
    2168          18 :         if (ret) {
    2169           0 :             kdc_log(context, config, 0,
    2170             :                     "constrained delegation from %s (%s) as %s to %s not allowed",
    2171             :                     cpn, dpn, tpn, spn);
    2172           0 :             goto out;
    2173             :         }
    2174             : 
    2175          18 :         ret = verify_flags(context, config, &adtkt, tpn);
    2176          18 :         if (ret) {
    2177           0 :             goto out;
    2178             :         }
    2179             : 
    2180          18 :         krb5_data_free(&rspac);
    2181             : 
    2182             :         /*
    2183             :          * generate the PAC for the user.
    2184             :          *
    2185             :          * TODO: pass in t->sname and t->realm and build
    2186             :          * a S4U_DELEGATION_INFO blob to the PAC.
    2187             :          */
    2188          18 :         ret = check_PAC(context, config, tp, dp,
    2189             :                         client, server, krbtgt,
    2190          18 :                         &clientkey->key,
    2191          18 :                         ekey, &tkey_sign->key,
    2192             :                         &adtkt, &rspac, &ad_signedpath);
    2193          18 :         if (ret) {
    2194           0 :             const char *msg = krb5_get_error_message(context, ret);
    2195           0 :             kdc_log(context, config, 0,
    2196             :                     "Verify delegated PAC failed to %s for client"
    2197             :                     "%s (%s) as %s from %s with %s",
    2198             :                     spn, cpn, dpn, tpn, from, msg);
    2199           0 :             krb5_free_error_message(context, msg);
    2200           0 :             goto out;
    2201             :         }
    2202             : 
    2203             :         /*
    2204             :          * Check that the KDC issued the user's ticket.
    2205             :          */
    2206          18 :         ret = check_KRB5SignedPath(context,
    2207             :                                    config,
    2208             :                                    krbtgt,
    2209             :                                    cp,
    2210             :                                    &adtkt,
    2211             :                                    NULL,
    2212             :                                    &ad_signedpath);
    2213          18 :         if (ret) {
    2214           0 :             const char *msg = krb5_get_error_message(context, ret);
    2215           0 :             kdc_log(context, config, 0,
    2216             :                     "KRB5SignedPath check from service %s failed "
    2217             :                     "for delegation to %s for client %s (%s)"
    2218             :                     "from %s failed with %s",
    2219             :                     spn, tpn, dpn, cpn, from, msg);
    2220           0 :             krb5_free_error_message(context, msg);
    2221           0 :             goto out;
    2222             :         }
    2223             : 
    2224          18 :         if (!ad_signedpath) {
    2225           0 :             ret = KRB5KDC_ERR_BADOPTION;
    2226           0 :             kdc_log(context, config, 0,
    2227             :                     "Ticket not signed with PAC nor SignedPath service %s failed "
    2228             :                     "for delegation to %s for client %s (%s)"
    2229             :                     "from %s",
    2230             :                     spn, tpn, dpn, cpn, from);
    2231           0 :             goto out;
    2232             :         }
    2233             : 
    2234          18 :         kdc_log(context, config, 0, "constrained delegation for %s "
    2235             :                 "from %s (%s) to %s", tpn, cpn, dpn, spn);
    2236             :     }
    2237             : 
    2238             :     /*
    2239             :      * Check flags
    2240             :      */
    2241             : 
    2242       39871 :     ret = kdc_check_flags(context, config,
    2243             :                           client, cpn,
    2244             :                           server, spn,
    2245             :                           FALSE);
    2246       39871 :     if(ret)
    2247           0 :         goto out;
    2248             : 
    2249       39901 :     if((b->kdc_options.validate || b->kdc_options.renew) &&
    2250          30 :        !krb5_principal_compare(context,
    2251          30 :                                krbtgt->entry.principal,
    2252          30 :                                server->entry.principal)){
    2253           0 :         kdc_log(context, config, 0, "Inconsistent request.");
    2254           0 :         ret = KRB5KDC_ERR_SERVER_NOMATCH;
    2255           0 :         goto out;
    2256             :     }
    2257             : 
    2258             :     /* check for valid set of addresses */
    2259       39871 :     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
    2260           0 :         ret = KRB5KRB_AP_ERR_BADADDR;
    2261           0 :         kdc_log(context, config, 0, "Request from wrong address");
    2262           0 :         goto out;
    2263             :     }
    2264             : 
    2265             :     /*
    2266             :      * If this is an referral, add server referral data to the
    2267             :      * auth_data reply .
    2268             :      */
    2269       39871 :     if (ref_realm) {
    2270             :         PA_DATA pa;
    2271             :         krb5_crypto crypto;
    2272             : 
    2273         302 :         kdc_log(context, config, 0,
    2274             :                 "Adding server referral to %s", ref_realm);
    2275             : 
    2276         302 :         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
    2277         302 :         if (ret)
    2278           0 :             goto out;
    2279             : 
    2280         302 :         ret = build_server_referral(context, config, crypto, ref_realm,
    2281             :                                     NULL, s, &pa.padata_value);
    2282         302 :         krb5_crypto_destroy(context, crypto);
    2283         302 :         if (ret) {
    2284           0 :             kdc_log(context, config, 0,
    2285             :                     "Failed building server referral");
    2286           0 :             goto out;
    2287             :         }
    2288         302 :         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
    2289             : 
    2290         302 :         ret = add_METHOD_DATA(&enc_pa_data, &pa);
    2291         302 :         krb5_data_free(&pa.padata_value);
    2292         302 :         if (ret) {
    2293           0 :             kdc_log(context, config, 0,
    2294             :                     "Add server referral METHOD-DATA failed");
    2295           0 :             goto out;
    2296             :         }
    2297             :     }
    2298             : 
    2299             :     /*
    2300             :      *
    2301             :      */
    2302             : 
    2303       79742 :     ret = tgs_make_reply(context,
    2304             :                          config,
    2305             :                          b,
    2306             :                          tp,
    2307             :                          tgt,
    2308             :                          replykey,
    2309             :                          rk_is_subkey,
    2310             :                          ekey,
    2311             :                          &sessionkey,
    2312             :                          kvno,
    2313             :                          *auth_data,
    2314             :                          server,
    2315       39871 :                          server->entry.principal,
    2316             :                          spn,
    2317             :                          client,
    2318             :                          cp,
    2319             :                          krbtgt_out,
    2320             :                          krbtgt_etype,
    2321             :                          spp,
    2322             :                          &rspac,
    2323             :                          &enc_pa_data,
    2324             :                          e_text,
    2325             :                          reply);
    2326             : 
    2327       40650 : out:
    2328       40650 :     if (tpn != cpn)
    2329        1413 :             free(tpn);
    2330       40650 :     free(spn);
    2331       40650 :     free(cpn);
    2332       40650 :     if (dpn)
    2333          22 :         free(dpn);
    2334             : 
    2335       40650 :     krb5_data_free(&rspac);
    2336       40650 :     krb5_free_keyblock_contents(context, &sessionkey);
    2337       40650 :     if(krbtgt_out)
    2338       39878 :         _kdc_free_ent(context, krbtgt_out);
    2339       40650 :     if(server)
    2340       39878 :         _kdc_free_ent(context, server);
    2341       40650 :     if(client)
    2342       39821 :         _kdc_free_ent(context, client);
    2343       40650 :     if(s4u2self_impersonated_client)
    2344         622 :         _kdc_free_ent(context, s4u2self_impersonated_client);
    2345             : 
    2346       40650 :     if (tp && tp != cp)
    2347         644 :         krb5_free_principal(context, tp);
    2348       40650 :     if (cp)
    2349       40647 :         krb5_free_principal(context, cp);
    2350       40650 :     if (dp)
    2351          22 :         krb5_free_principal(context, dp);
    2352       40650 :     if (sp)
    2353       40647 :         krb5_free_principal(context, sp);
    2354       40650 :     if (ref_realm)
    2355         302 :         free(ref_realm);
    2356       40650 :     free_METHOD_DATA(&enc_pa_data);
    2357             : 
    2358       40650 :     free_EncTicketPart(&adtkt);
    2359             : 
    2360       40650 :     return ret;
    2361             : }
    2362             : 
    2363             : /*
    2364             :  *
    2365             :  */
    2366             : 
    2367             : krb5_error_code
    2368       41890 : _kdc_tgs_rep(krb5_context context,
    2369             :              krb5_kdc_configuration *config,
    2370             :              KDC_REQ *req,
    2371             :              krb5_data *data,
    2372             :              const char *from,
    2373             :              struct sockaddr *from_addr,
    2374             :              int datagram_reply)
    2375             : {
    2376       41890 :     AuthorizationData *auth_data = NULL;
    2377             :     krb5_error_code ret;
    2378       41890 :     int i = 0;
    2379             :     const PA_DATA *tgs_req;
    2380             : 
    2381       41890 :     hdb_entry_ex *krbtgt = NULL;
    2382       41890 :     krb5_ticket *ticket = NULL;
    2383       41890 :     const char *e_text = NULL;
    2384       41890 :     krb5_enctype krbtgt_etype = ETYPE_NULL;
    2385             : 
    2386       41890 :     krb5_keyblock *replykey = NULL;
    2387       41890 :     int rk_is_subkey = 0;
    2388       41890 :     time_t *csec = NULL;
    2389       41890 :     int *cusec = NULL;
    2390             : 
    2391       41890 :     if(req->padata == NULL){
    2392           0 :         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
    2393           0 :         kdc_log(context, config, 0,
    2394             :                 "TGS-REQ from %s without PA-DATA", from);
    2395           0 :         goto out;
    2396             :     }
    2397             : 
    2398       41890 :     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
    2399             : 
    2400       41890 :     if(tgs_req == NULL){
    2401           0 :         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
    2402             : 
    2403           0 :         kdc_log(context, config, 0,
    2404             :                 "TGS-REQ from %s without PA-TGS-REQ", from);
    2405           0 :         goto out;
    2406             :     }
    2407       41890 :     ret = tgs_parse_request(context, config,
    2408             :                             &req->req_body, tgs_req,
    2409             :                             &krbtgt,
    2410             :                             &krbtgt_etype,
    2411             :                             &ticket,
    2412             :                             &e_text,
    2413             :                             from, from_addr,
    2414             :                             &csec, &cusec,
    2415             :                             &auth_data,
    2416             :                             &replykey,
    2417             :                             &rk_is_subkey);
    2418       41890 :     if (ret == HDB_ERR_NOT_FOUND_HERE) {
    2419             :         /* kdc_log() is called in tgs_parse_request() */
    2420        1232 :         goto out;
    2421             :     }
    2422       40658 :     if (ret) {
    2423           8 :         kdc_log(context, config, 0,
    2424             :                 "Failed parsing TGS-REQ from %s", from);
    2425           8 :         goto out;
    2426             :     }
    2427             : 
    2428       40650 :     ret = tgs_build_reply(context,
    2429             :                           config,
    2430             :                           req,
    2431             :                           &req->req_body,
    2432             :                           krbtgt,
    2433             :                           krbtgt_etype,
    2434             :                           replykey,
    2435             :                           rk_is_subkey,
    2436             :                           ticket,
    2437             :                           data,
    2438             :                           from,
    2439             :                           &e_text,
    2440             :                           &auth_data,
    2441             :                           from_addr);
    2442       40650 :     if (ret) {
    2443         977 :         kdc_log(context, config, 0,
    2444             :                 "Failed building TGS-REP to %s", from);
    2445         977 :         goto out;
    2446             :     }
    2447             : 
    2448             :     /* */
    2449       39706 :     if (datagram_reply && data->length > config->max_datagram_reply_length) {
    2450           0 :         krb5_data_free(data);
    2451           0 :         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
    2452           0 :         e_text = "Reply packet too large";
    2453             :     }
    2454             : 
    2455       81563 : out:
    2456       41890 :     if (replykey)
    2457       40650 :         krb5_free_keyblock(context, replykey);
    2458       41890 :     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
    2459         938 :         krb5_mk_error(context,
    2460             :                       ret,
    2461             :                       NULL,
    2462             :                       NULL,
    2463             :                       NULL,
    2464             :                       NULL,
    2465             :                       csec,
    2466             :                       cusec,
    2467             :                       data);
    2468         938 :         ret = 0;
    2469             :     }
    2470       41890 :     free(csec);
    2471       41890 :     free(cusec);
    2472       41890 :     if (ticket)
    2473       40652 :         krb5_free_ticket(context, ticket);
    2474       41890 :     if(krbtgt)
    2475       40656 :         _kdc_free_ent(context, krbtgt);
    2476             : 
    2477       41890 :     if (auth_data) {
    2478           0 :         free_AuthorizationData(auth_data);
    2479           0 :         free(auth_data);
    2480             :     }
    2481             : 
    2482       41890 :     return ret;
    2483             : }

Generated by: LCOV version 1.13