LCOV - code coverage report
Current view: top level - third_party/heimdal/kdc - krb5tgs.c (source / functions) Hit Total Coverage
Test: coverage report for master 469b22b8 Lines: 847 1294 65.5 %
Date: 2024-06-10 12:05:21 Functions: 15 17 88.2 %

          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           0 : get_krbtgt_realm(const PrincipalName *p)
      42             : {
      43           0 :     if(p->name_string.len == 2
      44           0 :        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
      45           0 :         return p->name_string.val[1];
      46             :     else
      47           0 :         return NULL;
      48             : }
      49             : 
      50             : /*
      51             :  * return TRUE if client was a synthetic principal, as indicated by
      52             :  * authorization data
      53             :  */
      54             : krb5_boolean
      55       50422 : _kdc_synthetic_princ_used_p(krb5_context context, krb5_ticket *ticket)
      56             : {
      57        1672 :     krb5_data synthetic_princ_used;
      58        1672 :     krb5_error_code ret;
      59             : 
      60       50422 :     ret = krb5_ticket_get_authorization_data_type(context, ticket,
      61             :                                                   KRB5_AUTHDATA_SYNTHETIC_PRINC_USED,
      62             :                                                   &synthetic_princ_used);
      63       50422 :     if (ret == ENOENT)
      64       50422 :         ret = krb5_ticket_get_authorization_data_type(context, ticket,
      65             :                                                       KRB5_AUTHDATA_INITIAL_VERIFIED_CAS,
      66             :                                                       &synthetic_princ_used);
      67             : 
      68       50422 :     if (ret == 0)
      69          16 :         krb5_data_free(&synthetic_princ_used);
      70             : 
      71       50422 :     return ret == 0;
      72             : }
      73             : 
      74             : /*
      75             :  *
      76             :  */
      77             : 
      78             : krb5_error_code
      79       50666 : _kdc_check_pac(astgs_request_t r,
      80             :                const krb5_principal client_principal,
      81             :                hdb_entry *delegated_proxy,
      82             :                hdb_entry *client,
      83             :                hdb_entry *server,
      84             :                hdb_entry *krbtgt,
      85             :                hdb_entry *ticket_server,
      86             :                const EncryptionKey *server_check_key,
      87             :                const EncryptionKey *krbtgt_check_key,
      88             :                EncTicketPart *tkt,
      89             :                krb5_boolean *kdc_issued,
      90             :                krb5_pac *ppac,
      91             :                krb5_principal *pac_canon_name,
      92             :                uint64_t *pac_attributes)
      93             : {
      94       50666 :     krb5_context context = r->context;
      95       50666 :     krb5_kdc_configuration *config = r->config;
      96       50666 :     krb5_pac pac = NULL;
      97        1672 :     krb5_error_code ret;
      98        1672 :     krb5_boolean signedticket;
      99             : 
     100       50666 :     *kdc_issued = FALSE;
     101       50666 :     *ppac = NULL;
     102       50666 :     if (pac_canon_name)
     103       49842 :         *pac_canon_name = NULL;
     104       50666 :     if (pac_attributes)
     105       49842 :         *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
     106             : 
     107       50666 :     ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
     108       50666 :     if (ret)
     109           0 :         return ret;
     110             : 
     111       50666 :     if (pac == NULL) {
     112          33 :         if (config->require_pac)
     113          33 :             ret = KRB5KDC_ERR_TGT_REVOKED;
     114          33 :         return ret;
     115             :     }
     116             : 
     117             :     /* Verify the server signature. */
     118       50633 :     ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
     119             :                           server_check_key, NULL);
     120       50633 :     if (ret) {
     121          36 :         krb5_pac_free(context, pac);
     122          36 :         return ret;
     123             :     }
     124             : 
     125             :     /* Verify the KDC signatures. */
     126       50597 :     ret = _kdc_pac_verify(r,
     127             :                           client_principal, delegated_proxy,
     128             :                           client, server, krbtgt, tkt, pac);
     129       50597 :     if (ret == 0) {
     130       50469 :         if (pac_canon_name) {
     131       49673 :             ret = _krb5_pac_get_canon_principal(context, pac, pac_canon_name);
     132       49673 :             if (ret && ret != ENOENT) {
     133           0 :                 krb5_pac_free(context, pac);
     134           0 :                 return ret;
     135             :             }
     136             :         }
     137      100142 :         if (pac_attributes &&
     138       49673 :             _krb5_pac_get_attributes_info(context, pac, pac_attributes) != 0)
     139         170 :             *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
     140         128 :     } else if (ret == KRB5_PLUGIN_NO_HANDLE) {
     141             :         /*
     142             :          * We can't verify the KDC signatures if the ticket was issued by
     143             :          * another realm's KDC.
     144             :          */
     145           0 :         if (krb5_realm_compare(context, server->principal,
     146           0 :                                ticket_server->principal)) {
     147           0 :             ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
     148             :                                   krbtgt_check_key);
     149           0 :             if (ret) {
     150           0 :                 krb5_pac_free(context, pac);
     151           0 :                 return ret;
     152             :             }
     153             :         }
     154             : 
     155           0 :         if (pac_canon_name) {
     156           0 :             ret = _krb5_pac_get_canon_principal(context, pac, pac_canon_name);
     157           0 :             if (ret && ret != ENOENT) {
     158           0 :                 krb5_pac_free(context, pac);
     159           0 :                 return ret;
     160             :             }
     161             :         }
     162           0 :         if (pac_attributes &&
     163           0 :             _krb5_pac_get_attributes_info(context, pac, pac_attributes) != 0)
     164           0 :             *pac_attributes = KRB5_PAC_WAS_GIVEN_IMPLICITLY;
     165             : 
     166             :         /* Discard the PAC if the plugin didn't handle it */
     167           0 :         krb5_pac_free(context, pac);
     168           0 :         ret = krb5_pac_init(context, &pac);
     169           0 :         if (ret)
     170           0 :             return ret;
     171             :     } else {
     172         128 :         krb5_pac_free(context, pac);
     173         128 :         return ret;
     174             :     }
     175             : 
     176      100773 :     *kdc_issued = signedticket ||
     177       50304 :                   krb5_principal_is_krbtgt(context,
     178       50304 :                                            ticket_server->principal);
     179       50469 :     *ppac = pac;
     180             : 
     181       50469 :     return 0;
     182             : }
     183             : 
     184             : static krb5_boolean
     185       98668 : is_anon_tgs_request_p(const KDC_REQ_BODY *b,
     186             :                       const EncTicketPart *tgt)
     187             : {
     188       98668 :     KDCOptions f = b->kdc_options;
     189             : 
     190             :     /*
     191             :      * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
     192             :      * request-anonymous and cname-in-addl-tkt flags for constrained
     193             :      * delegation requests. A true anonymous TGS request will only
     194             :      * have the request-anonymous flag set. (A corollary of this is
     195             :      * that it is not possible to support anonymous constrained
     196             :      * delegation requests, although they would be of limited utility.)
     197             :      */
     198      197336 :     return tgt->flags.anonymous ||
     199       98668 :         (f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
     200             : }
     201             : 
     202             : /*
     203             :  *
     204             :  */
     205             : 
     206             : static krb5_error_code
     207       49335 : check_tgs_flags(astgs_request_t r, KDC_REQ_BODY *b,
     208             :                 krb5_const_principal tgt_name,
     209             :                 const EncTicketPart *tgt, EncTicketPart *et)
     210             : {
     211       49335 :     KDCOptions f = b->kdc_options;
     212             : 
     213       49335 :     if(f.validate){
     214          12 :         if (!tgt->flags.invalid || tgt->starttime == NULL) {
     215           0 :             kdc_audit_addreason((kdc_request_t)r,
     216             :                                 "Bad request to validate ticket");
     217           0 :             return KRB5KDC_ERR_BADOPTION;
     218             :         }
     219          12 :         if(*tgt->starttime > kdc_time){
     220           0 :             kdc_audit_addreason((kdc_request_t)r,
     221             :                                 "Early request to validate ticket");
     222           0 :             return KRB5KRB_AP_ERR_TKT_NYV;
     223             :         }
     224             :         /* XXX  tkt = tgt */
     225          12 :         et->flags.invalid = 0;
     226       49323 :     } else if (tgt->flags.invalid) {
     227           0 :         kdc_audit_addreason((kdc_request_t)r,
     228             :                             "Ticket-granting ticket has INVALID flag set");
     229           0 :         return KRB5KRB_AP_ERR_TKT_INVALID;
     230             :     }
     231             : 
     232       49335 :     if(f.forwardable){
     233       36723 :         if (!tgt->flags.forwardable) {
     234           0 :             kdc_audit_addreason((kdc_request_t)r,
     235             :                                 "Bad request for forwardable ticket");
     236           0 :             return KRB5KDC_ERR_BADOPTION;
     237             :         }
     238       36723 :         et->flags.forwardable = 1;
     239             :     }
     240       49335 :     if(f.forwarded){
     241       23163 :         if (!tgt->flags.forwardable) {
     242           2 :             kdc_audit_addreason((kdc_request_t)r,
     243             :                                 "Request to forward non-forwardable ticket");
     244           2 :             return KRB5KDC_ERR_BADOPTION;
     245             :         }
     246       23161 :         et->flags.forwarded = 1;
     247       23161 :         et->caddr = b->addresses;
     248             :     }
     249       49333 :     if(tgt->flags.forwarded)
     250         299 :         et->flags.forwarded = 1;
     251             : 
     252       49333 :     if(f.proxiable){
     253           2 :         if (!tgt->flags.proxiable) {
     254           0 :             kdc_audit_addreason((kdc_request_t)r,
     255             :                                 "Bad request for proxiable ticket");
     256           0 :             return KRB5KDC_ERR_BADOPTION;
     257             :         }
     258           2 :         et->flags.proxiable = 1;
     259             :     }
     260       49333 :     if(f.proxy){
     261           0 :         if (!tgt->flags.proxiable) {
     262           0 :             kdc_audit_addreason((kdc_request_t)r,
     263             :                                 "Request to proxy non-proxiable ticket");
     264           0 :             return KRB5KDC_ERR_BADOPTION;
     265             :         }
     266           0 :         et->flags.proxy = 1;
     267           0 :         et->caddr = b->addresses;
     268             :     }
     269       49333 :     if(tgt->flags.proxy)
     270           0 :         et->flags.proxy = 1;
     271             : 
     272       49333 :     if(f.allow_postdate){
     273           0 :         if (!tgt->flags.may_postdate) {
     274           0 :             kdc_audit_addreason((kdc_request_t)r,
     275             :                                 "Bad request for post-datable ticket");
     276           0 :             return KRB5KDC_ERR_BADOPTION;
     277             :         }
     278           0 :         et->flags.may_postdate = 1;
     279             :     }
     280       49333 :     if(f.postdated){
     281           0 :         if (!tgt->flags.may_postdate) {
     282           0 :             kdc_audit_addreason((kdc_request_t)r,
     283             :                                 "Bad request for postdated ticket");
     284           0 :             return KRB5KDC_ERR_BADOPTION;
     285             :         }
     286           0 :         if(b->from)
     287           0 :             *et->starttime = *b->from;
     288           0 :         et->flags.postdated = 1;
     289           0 :         et->flags.invalid = 1;
     290       49333 :     } else if (b->from && *b->from > kdc_time + r->context->max_skew) {
     291           0 :         kdc_audit_addreason((kdc_request_t)r,
     292             :                             "Ticket cannot be postdated");
     293           0 :         return KRB5KDC_ERR_CANNOT_POSTDATE;
     294             :     }
     295             : 
     296       49333 :     if(f.renewable){
     297        3182 :         if (!tgt->flags.renewable || tgt->renew_till == NULL) {
     298           0 :             kdc_audit_addreason((kdc_request_t)r,
     299             :                                 "Bad request for renewable ticket");
     300           0 :             return KRB5KDC_ERR_BADOPTION;
     301             :         }
     302        3182 :         et->flags.renewable = 1;
     303        3182 :         ALLOC(et->renew_till);
     304        3182 :         _kdc_fix_time(&b->rtime);
     305        3182 :         *et->renew_till = *b->rtime;
     306             :     }
     307       49333 :     if(f.renew){
     308           0 :         time_t old_life;
     309          48 :         if (!tgt->flags.renewable || tgt->renew_till == NULL) {
     310           0 :             kdc_audit_addreason((kdc_request_t)r,
     311             :                                 "Request to renew non-renewable ticket");
     312           0 :             return KRB5KDC_ERR_BADOPTION;
     313             :         }
     314          48 :         old_life = tgt->endtime;
     315          48 :         if(tgt->starttime)
     316           0 :             old_life -= *tgt->starttime;
     317             :         else
     318          48 :             old_life -= tgt->authtime;
     319          48 :         et->endtime = *et->starttime + old_life;
     320          48 :         if (et->renew_till != NULL)
     321          24 :             et->endtime = min(*et->renew_till, et->endtime);
     322             :     }
     323             : 
     324             :     /*
     325             :      * RFC 8062 section 3 defines an anonymous ticket as one containing
     326             :      * the anonymous principal and the anonymous ticket flag.
     327             :      */
     328       49333 :     if (tgt->flags.anonymous &&
     329           0 :         !_kdc_is_anonymous(r->context, tgt_name)) {
     330           0 :         kdc_audit_addreason((kdc_request_t)r,
     331             :                             "Anonymous ticket flag set without "
     332             :                          "anonymous principal");
     333           0 :         return KRB5KDC_ERR_BADOPTION;
     334             :     }
     335             : 
     336             :     /*
     337             :      * RFC 8062 section 4.2 states that if the TGT is anonymous, the
     338             :      * anonymous KDC option SHOULD be set, but it is not required.
     339             :      * Treat an anonymous TGT as if the anonymous flag was set.
     340             :      */
     341       51005 :     if (is_anon_tgs_request_p(b, tgt))
     342           0 :         et->flags.anonymous = 1;
     343             : 
     344       47661 :     return 0;
     345             : }
     346             : 
     347             : /*
     348             :  * Determine if s4u2self is allowed from this client to this server
     349             :  *
     350             :  * also:
     351             :  *
     352             :  * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
     353             :  * service given by the client.
     354             :  *
     355             :  * For example, regardless of the principal being impersonated, if the
     356             :  * 'client' and 'server' (target) are the same, or server is an SPN
     357             :  * alias of client, then it's safe.
     358             :  */
     359             : 
     360             : krb5_error_code
     361         950 : _kdc_check_client_matches_target_service(krb5_context context,
     362             :                                          krb5_kdc_configuration *config,
     363             :                                          HDB *clientdb,
     364             :                                          hdb_entry *client,
     365             :                                          hdb_entry *target_server,
     366             :                                          krb5_const_principal target_server_principal)
     367             : {
     368           0 :     krb5_error_code ret;
     369             : 
     370             :     /*
     371             :      * Always allow the plugin to check, this might be faster, allow a
     372             :      * policy or audit check and can look into the DB records
     373             :      * directly
     374             :      */
     375         950 :     if (clientdb->hdb_check_client_matches_target_service) {
     376         950 :         ret = clientdb->hdb_check_client_matches_target_service(context,
     377             :                                                                 clientdb,
     378             :                                                                 client,
     379             :                                                                 target_server);
     380         950 :         if (ret == 0)
     381         944 :             return 0;
     382           0 :     } else if (krb5_principal_compare(context,
     383           0 :                                       client->principal,
     384             :                                       target_server_principal) == TRUE) {
     385             :         /* if client does a s4u2self to itself, and there is no plugin, that is ok */
     386           0 :         return 0;
     387             :     } else {
     388           0 :         ret = KRB5KDC_ERR_BADOPTION;
     389             :     }
     390           6 :     return ret;
     391             : }
     392             : 
     393             : /*
     394             :  *
     395             :  */
     396             : 
     397             : krb5_error_code
     398        1054 : _kdc_verify_flags(krb5_context context,
     399             :                   krb5_kdc_configuration *config,
     400             :                   const EncTicketPart *et,
     401             :                   const char *pstr)
     402             : {
     403        1054 :     if(et->endtime < kdc_time){
     404           0 :         kdc_log(context, config, 4, "Ticket expired (%s)", pstr);
     405           0 :         return KRB5KRB_AP_ERR_TKT_EXPIRED;
     406             :     }
     407        1054 :     if(et->flags.invalid){
     408           0 :         kdc_log(context, config, 4, "Ticket not valid (%s)", pstr);
     409           0 :         return KRB5KRB_AP_ERR_TKT_NYV;
     410             :     }
     411        1054 :     return 0;
     412             : }
     413             : 
     414             : /*
     415             :  *
     416             :  */
     417             : 
     418             : static krb5_error_code
     419       49333 : fix_transited_encoding(krb5_context context,
     420             :                        krb5_kdc_configuration *config,
     421             :                        krb5_boolean check_policy,
     422             :                        const TransitedEncoding *tr,
     423             :                        EncTicketPart *et,
     424             :                        const char *client_realm,
     425             :                        const char *server_realm,
     426             :                        const char *tgt_realm)
     427             : {
     428       49333 :     krb5_error_code ret = 0;
     429        1672 :     char **realms, **tmp;
     430        1672 :     unsigned int num_realms;
     431        1672 :     size_t i;
     432             : 
     433       49333 :     switch (tr->tr_type) {
     434       47661 :     case domain_X500_Compress:
     435       47661 :         break;
     436           0 :     case 0:
     437             :         /*
     438             :          * Allow empty content of type 0 because that is was Microsoft
     439             :          * generates in their TGT.
     440             :          */
     441           0 :         if (tr->contents.length == 0)
     442           0 :             break;
     443           0 :         kdc_log(context, config, 4,
     444             :                 "Transited type 0 with non empty content");
     445           0 :         return KRB5KDC_ERR_TRTYPE_NOSUPP;
     446           0 :     default:
     447           0 :         kdc_log(context, config, 4,
     448           0 :                 "Unknown transited type: %u", tr->tr_type);
     449           0 :         return KRB5KDC_ERR_TRTYPE_NOSUPP;
     450             :     }
     451             : 
     452       49333 :     ret = krb5_domain_x500_decode(context,
     453             :                                   tr->contents,
     454             :                                   &realms,
     455             :                                   &num_realms,
     456             :                                   client_realm,
     457             :                                   server_realm);
     458       49333 :     if(ret){
     459           0 :         krb5_warn(context, ret,
     460             :                   "Decoding transited encoding");
     461           0 :         return ret;
     462             :     }
     463             : 
     464             :     /*
     465             :      * If the realm of the presented tgt is neither the client nor the server
     466             :      * realm, it is a transit realm and must be added to transited set.
     467             :      */
     468       49333 :     if (strcmp(client_realm, tgt_realm) != 0 &&
     469           8 :         strcmp(server_realm, tgt_realm) != 0) {
     470           0 :         if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
     471           0 :             ret = ERANGE;
     472           0 :             goto free_realms;
     473             :         }
     474           0 :         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
     475           0 :         if(tmp == NULL){
     476           0 :             ret = ENOMEM;
     477           0 :             goto free_realms;
     478             :         }
     479           0 :         realms = tmp;
     480           0 :         realms[num_realms] = strdup(tgt_realm);
     481           0 :         if(realms[num_realms] == NULL){
     482           0 :             ret = ENOMEM;
     483           0 :             goto free_realms;
     484             :         }
     485           0 :         num_realms++;
     486             :     }
     487       49333 :     if(num_realms == 0) {
     488       49333 :         if (strcmp(client_realm, server_realm) != 0)
     489          67 :             kdc_log(context, config, 4,
     490             :                     "cross-realm %s -> %s", client_realm, server_realm);
     491             :     } else {
     492           0 :         size_t l = 0;
     493             :         char *rs;
     494           0 :         for(i = 0; i < num_realms; i++)
     495           0 :             l += strlen(realms[i]) + 2;
     496           0 :         rs = malloc(l);
     497           0 :         if(rs != NULL) {
     498           0 :             *rs = '\0';
     499           0 :             for(i = 0; i < num_realms; i++) {
     500           0 :                 if(i > 0)
     501           0 :                     strlcat(rs, ", ", l);
     502           0 :                 strlcat(rs, realms[i], l);
     503             :             }
     504           0 :             kdc_log(context, config, 4,
     505             :                     "cross-realm %s -> %s via [%s]",
     506             :                     client_realm, server_realm, rs);
     507           0 :             free(rs);
     508             :         }
     509             :     }
     510       49333 :     if(check_policy) {
     511       49333 :         ret = krb5_check_transited(context, client_realm,
     512             :                                    server_realm,
     513             :                                    realms, num_realms, NULL);
     514       49333 :         if(ret) {
     515           0 :             krb5_warn(context, ret, "cross-realm %s -> %s",
     516             :                       client_realm, server_realm);
     517           0 :             goto free_realms;
     518             :         }
     519       49333 :         et->flags.transited_policy_checked = 1;
     520             :     }
     521       49333 :     et->transited.tr_type = domain_X500_Compress;
     522       49333 :     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
     523       49333 :     if(ret)
     524           0 :         krb5_warn(context, ret, "Encoding transited encoding");
     525       49333 :   free_realms:
     526       49333 :     for(i = 0; i < num_realms; i++)
     527           0 :         free(realms[i]);
     528       49333 :     free(realms);
     529       49333 :     return ret;
     530             : }
     531             : 
     532             : 
     533             : static krb5_error_code
     534       49335 : tgs_make_reply(astgs_request_t r,
     535             :                const EncTicketPart *tgt,
     536             :                const EncryptionKey *serverkey,
     537             :                const EncryptionKey *krbtgtkey,
     538             :                const krb5_keyblock *sessionkey,
     539             :                krb5_kvno kvno,
     540             :                AuthorizationData *auth_data,
     541             :                const char *tgt_realm,
     542             :                uint16_t rodc_id,
     543             :                krb5_boolean add_ticket_sig)
     544             : {
     545       49335 :     KDC_REQ_BODY *b = &r->req.req_body;
     546       49335 :     krb5_data *reply = r->reply;
     547       49335 :     KDC_REP *rep = &r->rep;
     548       49335 :     EncTicketPart *et = &r->et;
     549       49335 :     EncKDCRepPart *ek = &r->ek;
     550       49335 :     KDCOptions f = b->kdc_options;
     551        1672 :     krb5_error_code ret;
     552       49335 :     int is_weak = 0;
     553             : 
     554       49335 :     heim_assert(r->client_princ != NULL, "invalid client name passed to tgs_make_reply");
     555             : 
     556       49335 :     rep->pvno = 5;
     557       49335 :     rep->msg_type = krb_tgs_rep;
     558             : 
     559       49335 :     if (et->authtime == 0)
     560       49195 :         et->authtime = tgt->authtime;
     561       49335 :     _kdc_fix_time(&b->till);
     562       49335 :     et->endtime = min(tgt->endtime, *b->till);
     563       49335 :     ALLOC(et->starttime);
     564       49335 :     *et->starttime = kdc_time;
     565             : 
     566       49335 :     ret = check_tgs_flags(r, b, r->client_princ, tgt, et);
     567       49335 :     if(ret)
     568           2 :         goto out;
     569             : 
     570             :     /* We should check the transited encoding if:
     571             :        1) the request doesn't ask not to be checked
     572             :        2) globally enforcing a check
     573             :        3) principal requires checking
     574             :        4) we allow non-check per-principal, but principal isn't marked as allowing this
     575             :        5) we don't globally allow this
     576             :     */
     577             : 
     578             : #define GLOBAL_FORCE_TRANSITED_CHECK            \
     579             :     (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
     580             : #define GLOBAL_ALLOW_PER_PRINCIPAL                      \
     581             :     (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
     582             : #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK                    \
     583             :     (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
     584             : 
     585             : /* these will consult the database in future release */
     586             : #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)              0
     587             : #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)      0
     588             : 
     589       49333 :     ret = fix_transited_encoding(r->context, r->config,
     590       49333 :                                  !f.disable_transited_check ||
     591           0 :                                  GLOBAL_FORCE_TRANSITED_CHECK ||
     592             :                                  PRINCIPAL_FORCE_TRANSITED_CHECK(r->server) ||
     593             :                                  !((GLOBAL_ALLOW_PER_PRINCIPAL &&
     594             :                                     PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(r->server)) ||
     595           0 :                                    GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
     596             :                                  &tgt->transited, et,
     597       49333 :                                  krb5_principal_get_realm(r->context, r->client_princ),
     598       49333 :                                  krb5_principal_get_realm(r->context, r->server->principal),
     599             :                                  tgt_realm);
     600             : 
     601             :     {
     602             :         /*
     603             :          * RFC 6806 notes that names MUST NOT be changed in the response to a
     604             :          * TGS request. Hence we ignore the setting of the canonicalize KDC
     605             :          * option. However, for legacy interoperability we do allow the backend
     606             :          * to override this by setting the force-canonicalize HDB flag in the
     607             :          * server entry.
     608             :          */
     609        1672 :         krb5_const_principal rsp;
     610             : 
     611       49333 :         if (r->server->flags.force_canonicalize)
     612       47356 :             rsp = r->server->principal;
     613             :         else
     614        1977 :             rsp = r->server_princ;
     615       49333 :         if (ret == 0)
     616       49333 :             ret = copy_Realm(&rsp->realm, &rep->ticket.realm);
     617       49333 :         if (ret == 0)
     618       49333 :             ret = _krb5_principal2principalname(&rep->ticket.sname, rsp);
     619             :     }
     620             : 
     621       49333 :     if (ret == 0)
     622       49333 :         ret = copy_Realm(&r->client_princ->realm, &rep->crealm);
     623       49333 :     if (ret)
     624           0 :         goto out;
     625             : 
     626             :     /*
     627             :      * RFC 8062 states "if the ticket in the TGS request is an anonymous
     628             :      * one, the client and client realm are copied from that ticket". So
     629             :      * whilst the TGT flag check below is superfluous, it is included in
     630             :      * order to follow the specification to its letter.
     631             :      */
     632       49333 :     if (et->flags.anonymous && !tgt->flags.anonymous)
     633           0 :         _kdc_make_anonymous_principalname(&rep->cname);
     634             :     else
     635       49333 :         ret = copy_PrincipalName(&r->client_princ->name, &rep->cname);
     636       49333 :     if (ret)
     637           0 :         goto out;
     638       49333 :     rep->ticket.tkt_vno = 5;
     639             : 
     640       49333 :     ek->caddr = et->caddr;
     641             : 
     642             :     {
     643        1672 :         time_t life;
     644       49333 :         life = et->endtime - *et->starttime;
     645       49333 :         if(r->client && r->client->max_life)
     646       49273 :             life = min(life, *r->client->max_life);
     647       49333 :         if(r->server->max_life)
     648       47356 :             life = min(life, *r->server->max_life);
     649       49333 :         et->endtime = *et->starttime + life;
     650             :     }
     651       49333 :     if(f.renewable_ok && tgt->flags.renewable &&
     652           0 :        et->renew_till == NULL && et->endtime < *b->till &&
     653           0 :        tgt->renew_till != NULL)
     654             :     {
     655           0 :         et->flags.renewable = 1;
     656           0 :         ALLOC(et->renew_till);
     657           0 :         *et->renew_till = *b->till;
     658             :     }
     659       49333 :     if(et->renew_till){
     660           0 :         time_t renew;
     661        3182 :         renew = *et->renew_till - *et->starttime;
     662        3182 :         if(r->client && r->client->max_renew)
     663        3139 :             renew = min(renew, *r->client->max_renew);
     664        3182 :         if(r->server->max_renew)
     665        3139 :             renew = min(renew, *r->server->max_renew);
     666        3182 :         *et->renew_till = *et->starttime + renew;
     667             :     }
     668             : 
     669       49333 :     if(et->renew_till){
     670        3182 :         *et->renew_till = min(*et->renew_till, *tgt->renew_till);
     671        3182 :         *et->starttime = min(*et->starttime, *et->renew_till);
     672        3182 :         et->endtime = min(et->endtime, *et->renew_till);
     673             :     }
     674             : 
     675       49333 :     *et->starttime = min(*et->starttime, et->endtime);
     676             : 
     677       49333 :     if(*et->starttime == et->endtime){
     678           0 :         ret = KRB5KDC_ERR_NEVER_VALID;
     679           0 :         goto out;
     680             :     }
     681       49333 :     if(et->renew_till && et->endtime == *et->renew_till){
     682           0 :         free(et->renew_till);
     683           0 :         et->renew_till = NULL;
     684           0 :         et->flags.renewable = 0;
     685             :     }
     686             : 
     687       49333 :     et->flags.pre_authent = tgt->flags.pre_authent;
     688       49333 :     et->flags.hw_authent  = tgt->flags.hw_authent;
     689       49333 :     et->flags.ok_as_delegate = r->server->flags.ok_as_delegate;
     690             : 
     691             :     /* See MS-KILE 3.3.5.1 */
     692       49333 :     if (!r->server->flags.forwardable)
     693           1 :         et->flags.forwardable = 0;
     694       49333 :     if (!r->server->flags.proxiable)
     695        1978 :         et->flags.proxiable = 0;
     696             : 
     697       49333 :     if (auth_data) {
     698           5 :         unsigned int i = 0;
     699             : 
     700             :         /* XXX check authdata */
     701             : 
     702           5 :         if (et->authorization_data == NULL) {
     703           5 :             et->authorization_data = calloc(1, sizeof(*et->authorization_data));
     704           5 :             if (et->authorization_data == NULL) {
     705           0 :                 ret = ENOMEM;
     706           0 :                 krb5_set_error_message(r->context, ret, "malloc: out of memory");
     707           0 :                 goto out;
     708             :             }
     709             :         }
     710          10 :         for(i = 0; i < auth_data->len ; i++) {
     711           5 :             ret = add_AuthorizationData(et->authorization_data, &auth_data->val[i]);
     712           5 :             if (ret) {
     713           0 :                 krb5_set_error_message(r->context, ret, "malloc: out of memory");
     714           0 :                 goto out;
     715             :             }
     716             :         }
     717             :     }
     718             : 
     719       49333 :     ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et->key);
     720       49333 :     if (ret)
     721           0 :         goto out;
     722       49333 :     et->crealm = rep->crealm;
     723       49333 :     et->cname = rep->cname;
     724             : 
     725       49333 :     ek->key = et->key;
     726             :     /* MIT must have at least one last_req */
     727       49333 :     ek->last_req.val = calloc(1, sizeof(*ek->last_req.val));
     728       49333 :     if (ek->last_req.val == NULL) {
     729           0 :         ret = ENOMEM;
     730           0 :         goto out;
     731             :     }
     732       49333 :     ek->last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
     733       49333 :     ek->nonce = b->nonce;
     734       49333 :     ek->flags = et->flags;
     735       49333 :     ek->authtime = et->authtime;
     736       49333 :     ek->starttime = et->starttime;
     737       49333 :     ek->endtime = et->endtime;
     738       49333 :     ek->renew_till = et->renew_till;
     739       49333 :     ek->srealm = rep->ticket.realm;
     740       49333 :     ek->sname = rep->ticket.sname;
     741             : 
     742       49333 :     _kdc_log_timestamp(r, "TGS-REQ", et->authtime, et->starttime,
     743             :                        et->endtime, et->renew_till);
     744             : 
     745       49333 :     if (krb5_enctype_valid(r->context, serverkey->keytype) != 0
     746           0 :         && _kdc_is_weak_exception(r->server->principal, serverkey->keytype))
     747             :     {
     748           0 :         krb5_enctype_enable(r->context, serverkey->keytype);
     749           0 :         is_weak = 1;
     750             :     }
     751             : 
     752       49333 :     if (r->canon_client_princ) {
     753        1672 :         char *cpn;
     754             : 
     755       49333 :         (void) krb5_unparse_name(r->context, r->canon_client_princ, &cpn);
     756       49333 :         kdc_audit_addkv((kdc_request_t)r, 0, "canon_client_name", "%s",
     757       49333 :                         cpn ? cpn : "<unknown>");
     758       49333 :         krb5_xfree(cpn);
     759             :     }
     760             : 
     761             :     /*
     762             :      * For anonymous tickets, we should filter out positive authorization data
     763             :      * that could reveal the client's identity, and return a policy error for
     764             :      * restrictive authorization data. Policy for unknown authorization types
     765             :      * is implementation dependent.
     766             :      */
     767       49333 :     if (r->pac && !et->flags.anonymous) {
     768       49322 :         kdc_audit_setkv_number((kdc_request_t)r, "pac_attributes",
     769       49322 :                                r->pac_attributes);
     770             : 
     771             :         /*
     772             :          * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES
     773             :          * buffer (legacy behavior) or if the attributes buffer indicates the
     774             :          * AS client requested one.
     775             :          */
     776       49322 :         if (_kdc_include_pac_p(r)) {
     777        1672 :             krb5_boolean is_tgs =
     778       49322 :                 krb5_principal_is_krbtgt(r->context, r->server->principal);
     779             : 
     780       49322 :             ret = _krb5_kdc_pac_sign_ticket(r->context, r->pac, r->client_princ, serverkey,
     781       49322 :                                             krbtgtkey, rodc_id, NULL, r->canon_client_princ,
     782             :                                             add_ticket_sig, add_ticket_sig, et,
     783             :                                             is_tgs ? &r->pac_attributes : NULL);
     784       49322 :             if (ret)
     785           0 :                 goto out;
     786             :         }
     787             :     }
     788             : 
     789       49333 :     ret = _kdc_finalize_reply(r);
     790       49333 :     if (ret)
     791           0 :         goto out;
     792             : 
     793             :     /* It is somewhat unclear where the etype in the following
     794             :        encryption should come from. What we have is a session
     795             :        key in the passed tgt, and a list of preferred etypes
     796             :        *for the new ticket*. Should we pick the best possible
     797             :        etype, given the keytype in the tgt, or should we look
     798             :        at the etype list here as well?  What if the tgt
     799             :        session key is DES3 and we want a ticket with a (say)
     800             :        CAST session key. Should the DES3 etype be added to the
     801             :        etype list, even if we don't want a session key with
     802             :        DES3? */
     803       51005 :     ret = _kdc_encode_reply(r->context, r->config, r, b->nonce,
     804       49333 :                             serverkey->keytype, kvno,
     805       49333 :                             serverkey, 0, r->rk_is_subkey, reply);
     806       49333 :     if (is_weak)
     807           0 :         krb5_enctype_disable(r->context, serverkey->keytype);
     808             : 
     809       49333 :     _log_astgs_req(r, serverkey->keytype);
     810             : 
     811       49335 : out:
     812       49335 :     return ret;
     813             : }
     814             : 
     815             : static krb5_error_code
     816       51198 : tgs_check_authenticator(krb5_context context,
     817             :                         krb5_kdc_configuration *config,
     818             :                         krb5_auth_context ac,
     819             :                         KDC_REQ_BODY *b,
     820             :                         krb5_keyblock *key)
     821             : {
     822        1672 :     krb5_authenticator auth;
     823        1672 :     krb5_error_code ret;
     824        1672 :     krb5_crypto crypto;
     825             : 
     826       51198 :     ret = krb5_auth_con_getauthenticator(context, ac, &auth);
     827       51198 :     if (ret) {
     828           0 :         kdc_log(context, config, 2,
     829             :                 "Out of memory checking PA-TGS Authenticator");
     830           0 :         goto out;
     831             :     }
     832       51198 :     if(auth->cksum == NULL){
     833           0 :         kdc_log(context, config, 4, "No authenticator in request");
     834           0 :         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
     835           0 :         goto out;
     836             :     }
     837             : 
     838       51198 :     if (!krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
     839           0 :         kdc_log(context, config, 4, "Bad checksum type in authenticator: %d",
     840           0 :                 auth->cksum->cksumtype);
     841           0 :         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
     842           0 :         goto out;
     843             :     }
     844             : 
     845       51198 :     ret = krb5_crypto_init(context, key, 0, &crypto);
     846       51198 :     if (ret) {
     847           0 :         const char *msg = krb5_get_error_message(context, ret);
     848           0 :         kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
     849           0 :         krb5_free_error_message(context, msg);
     850           0 :         goto out;
     851             :     }
     852             : 
     853             :     /*
     854             :      * RFC4120 says the checksum must be collision-proof, but it does
     855             :      * not require it to be keyed (as the authenticator is encrypted).
     856             :      */
     857       51198 :     _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM);
     858       52870 :     ret = _kdc_verify_checksum(context,
     859             :                                crypto,
     860             :                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
     861       51198 :                                &b->_save,
     862       51198 :                                auth->cksum);
     863       51198 :     krb5_crypto_destroy(context, crypto);
     864       51198 :     if(ret){
     865           0 :         const char *msg = krb5_get_error_message(context, ret);
     866           0 :         kdc_log(context, config, 4,
     867             :                 "Failed to verify authenticator checksum: %s", msg);
     868           0 :         krb5_free_error_message(context, msg);
     869             :     }
     870       51198 : out:
     871       51198 :     free_Authenticator(auth);
     872       51198 :     free(auth);
     873       51198 :     return ret;
     874             : }
     875             : 
     876             : static krb5_boolean
     877           0 : need_referral(krb5_context context, krb5_kdc_configuration *config,
     878             :               const KDCOptions * const options, krb5_principal server,
     879             :               krb5_realm **realms)
     880             : {
     881           0 :     const char *name;
     882             : 
     883           0 :     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
     884           0 :         return FALSE;
     885             : 
     886           0 :     if (server->name.name_string.len == 1)
     887           0 :         name = server->name.name_string.val[0];
     888           0 :     else if (server->name.name_string.len > 1)
     889           0 :         name = server->name.name_string.val[1];
     890             :     else
     891           0 :         return FALSE;
     892             : 
     893           0 :     kdc_log(context, config, 5, "Searching referral for %s", name);
     894             : 
     895           0 :     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
     896             : }
     897             : 
     898             : static krb5_error_code
     899      102397 : validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data)
     900             : {
     901        3344 :     krb5_error_code ret;
     902        3344 :     krb5_data data;
     903             : 
     904      102397 :     krb5_data_zero(&data);
     905             : 
     906      102397 :     if (!r->config->enable_fast)
     907        7530 :         return 0;
     908             : 
     909       94867 :     ret = _krb5_get_ad(r->context, auth_data, NULL,
     910             :                        KRB5_AUTHDATA_FX_FAST_USED, &data);
     911       94867 :     if (ret == 0) {
     912       44051 :         r->fast_asserted = 1;
     913       44051 :         krb5_data_free(&data);
     914             :     }
     915             : 
     916       94867 :     ret = _krb5_get_ad(r->context, auth_data, NULL,
     917             :                        KRB5_AUTHDATA_FX_FAST_ARMOR, &data);
     918       94867 :     if (ret == 0) {
     919           2 :         kdc_log(r->context, r->config, 2,
     920             :                 "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
     921           2 :         krb5_data_free(&data);
     922           2 :         return KRB5KRB_AP_ERR_BAD_INTEGRITY;
     923             :     }
     924             : 
     925       91521 :     return 0;
     926             : }
     927             : 
     928             : static krb5_error_code
     929       52565 : tgs_parse_request(astgs_request_t r,
     930             :                   const PA_DATA *tgs_req,
     931             :                   krb5_enctype *krbtgt_etype,
     932             :                   const char *from,
     933             :                   const struct sockaddr *from_addr,
     934             :                   time_t **csec,
     935             :                   int **cusec)
     936             : {
     937       52565 :     krb5_kdc_configuration *config = r->config;
     938       52565 :     KDC_REQ_BODY *b = &r->req.req_body;
     939        1672 :     static char failed[] = "<unparse_name failed>";
     940        1672 :     krb5_ap_req ap_req;
     941        1672 :     krb5_error_code ret;
     942        1672 :     krb5_principal princ;
     943       52565 :     krb5_auth_context ac = NULL;
     944        1672 :     krb5_flags ap_req_options;
     945       52565 :     krb5_flags verify_ap_req_flags = 0;
     946        1672 :     krb5uint32 krbtgt_kvno;     /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
     947        1672 :     krb5uint32 krbtgt_kvno_try;
     948       52565 :     int kvno_search_tries = 4;  /* number of kvnos to try when tkt_vno == 0 */
     949        1672 :     const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
     950        1672 :     Key *tkey;
     951       52565 :     krb5_keyblock *subkey = NULL;
     952             : 
     953       52565 :     *csec  = NULL;
     954       52565 :     *cusec = NULL;
     955             : 
     956       52565 :     memset(&ap_req, 0, sizeof(ap_req));
     957       52565 :     ret = krb5_decode_ap_req(r->context, &tgs_req->padata_value, &ap_req);
     958       52565 :     if(ret){
     959           0 :         const char *msg = krb5_get_error_message(r->context, ret);
     960           0 :         kdc_log(r->context, config, 4, "Failed to decode AP-REQ: %s", msg);
     961           0 :         krb5_free_error_message(r->context, msg);
     962           0 :         goto out;
     963             :     }
     964             : 
     965       52565 :     if(!krb5_principalname_is_krbtgt(r->context, &ap_req.ticket.sname)){
     966             :         /*
     967             :          * Note: this check is not to be depended upon for security. Nothing
     968             :          * prevents a client modifying the sname, as it is located in the
     969             :          * unencrypted part of the ticket.
     970             :          */
     971             : 
     972             :         /* XXX check for ticket.sname == req.sname */
     973           8 :         kdc_log(r->context, config, 4, "PA-DATA is not a ticket-granting ticket");
     974           8 :         ret = KRB5KDC_ERR_POLICY; /* ? */
     975           8 :         goto out;
     976             :     }
     977             : 
     978       52557 :     _krb5_principalname2krb5_principal(r->context,
     979             :                                        &princ,
     980             :                                        ap_req.ticket.sname,
     981             :                                        ap_req.ticket.realm);
     982             : 
     983       52557 :     krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
     984       52557 :     ret = _kdc_db_fetch(r->context, config, princ, HDB_F_GET_KRBTGT,
     985             :                         &krbtgt_kvno, &r->krbtgtdb, &r->krbtgt);
     986             : 
     987       52557 :     if (ret == HDB_ERR_NOT_FOUND_HERE) {
     988             :         /* XXX Factor out this unparsing of the same princ all over */
     989           0 :         char *p;
     990        1351 :         ret = krb5_unparse_name(r->context, princ, &p);
     991        1351 :         if (ret != 0)
     992           0 :             p = failed;
     993        1351 :         krb5_free_principal(r->context, princ);
     994        1351 :         kdc_log(r->context, config, 5,
     995             :                 "Ticket-granting ticket account %s does not have secrets at "
     996             :                 "this KDC, need to proxy", p);
     997        1351 :         if (ret == 0)
     998        1351 :             free(p);
     999        1351 :         ret = HDB_ERR_NOT_FOUND_HERE;
    1000        1351 :         goto out;
    1001       51206 :     } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
    1002           0 :         char *p;
    1003           0 :         ret = krb5_unparse_name(r->context, princ, &p);
    1004           0 :         if (ret != 0)
    1005           0 :             p = failed;
    1006           0 :         krb5_free_principal(r->context, princ);
    1007           0 :         kdc_log(r->context, config, 5,
    1008             :                 "Ticket-granting ticket account %s does not have keys for "
    1009             :                 "kvno %d at this KDC", p, krbtgt_kvno);
    1010           0 :         if (ret == 0)
    1011           0 :             free(p);
    1012           0 :         ret = HDB_ERR_KVNO_NOT_FOUND;
    1013           0 :         goto out;
    1014       51206 :     } else if (ret == HDB_ERR_NO_MKEY) {
    1015           0 :         char *p;
    1016           0 :         ret = krb5_unparse_name(r->context, princ, &p);
    1017           0 :         if (ret != 0)
    1018           0 :             p = failed;
    1019           0 :         krb5_free_principal(r->context, princ);
    1020           0 :         kdc_log(r->context, config, 5,
    1021             :                 "Missing master key for decrypting keys for ticket-granting "
    1022             :                 "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
    1023           0 :         if (ret == 0)
    1024           0 :             free(p);
    1025           0 :         ret = HDB_ERR_KVNO_NOT_FOUND;
    1026           0 :         goto out;
    1027       51206 :     } else if (ret) {
    1028           0 :         const char *msg = krb5_get_error_message(r->context, ret);
    1029           0 :         char *p;
    1030           0 :         ret = krb5_unparse_name(r->context, princ, &p);
    1031           0 :         if (ret != 0)
    1032           0 :             p = failed;
    1033           0 :         kdc_log(r->context, config, 4,
    1034             :                 "Ticket-granting ticket %s not found in database: %s", p, msg);
    1035           0 :         krb5_free_principal(r->context, princ);
    1036           0 :         krb5_free_error_message(r->context, msg);
    1037           0 :         if (ret == 0)
    1038           0 :             free(p);
    1039           0 :         ret = KRB5KRB_AP_ERR_NOT_US;
    1040           0 :         goto out;
    1041             :     }
    1042             : 
    1043       51206 :     krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : r->krbtgt->kvno;
    1044       51206 :     *krbtgt_etype = ap_req.ticket.enc_part.etype;
    1045             : 
    1046       49534 : next_kvno:
    1047       51206 :     krbtgt_keys = hdb_kvno2keys(r->context, r->krbtgt, krbtgt_kvno_try);
    1048       51206 :     ret = hdb_enctype2key(r->context, r->krbtgt, krbtgt_keys,
    1049             :                           ap_req.ticket.enc_part.etype, &tkey);
    1050       51206 :     if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
    1051           0 :         kvno_search_tries--;
    1052           0 :         krbtgt_kvno_try--;
    1053           0 :         goto next_kvno;
    1054       51206 :     } else if (ret) {
    1055           4 :         char *str = NULL, *p = NULL;
    1056             : 
    1057             :         /* We should implement the MIT `trace_format()' concept */
    1058           4 :         (void) krb5_enctype_to_string(r->context, ap_req.ticket.enc_part.etype, &str);
    1059           4 :         (void) krb5_unparse_name(r->context, princ, &p);
    1060           8 :         kdc_log(r->context, config, 4,
    1061             :                 "No server key with enctype %s found for %s",
    1062           4 :                 str ? str : "<unknown enctype>",
    1063           4 :                 p ? p : "<unparse_name failed>");
    1064           4 :         free(str);
    1065           4 :         free(p);
    1066           4 :         ret = KRB5KRB_AP_ERR_BADKEYVER;
    1067           4 :         goto out;
    1068             :     }
    1069             : 
    1070       51202 :     if (b->kdc_options.validate)
    1071          26 :         verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
    1072             : 
    1073       51202 :     if (r->config->warn_ticket_addresses)
    1074           0 :         verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS;
    1075             : 
    1076       52874 :     ret = krb5_verify_ap_req2(r->context,
    1077             :                               &ac,
    1078             :                               &ap_req,
    1079             :                               princ,
    1080       51202 :                               &tkey->key,
    1081             :                               verify_ap_req_flags,
    1082             :                               &ap_req_options,
    1083             :                               &r->ticket,
    1084             :                               KRB5_KU_TGS_REQ_AUTH);
    1085       51202 :     if (r->ticket && r->ticket->ticket.caddr)
    1086         319 :         kdc_audit_addaddrs((kdc_request_t)r, r->ticket->ticket.caddr, "tixaddrs");
    1087       51202 :     if (r->config->warn_ticket_addresses && ret == KRB5KRB_AP_ERR_BADADDR &&
    1088           0 :         r->ticket != NULL) {
    1089           0 :         kdc_audit_setkv_bool((kdc_request_t)r, "wrongaddr", TRUE);
    1090           0 :         ret = 0;
    1091             :     }
    1092       51202 :     if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
    1093           0 :         kvno_search_tries--;
    1094           0 :         krbtgt_kvno_try--;
    1095           0 :         goto next_kvno;
    1096             :     }
    1097             : 
    1098       51202 :     krb5_free_principal(r->context, princ);
    1099       51202 :     if(ret) {
    1100           3 :         const char *msg = krb5_get_error_message(r->context, ret);
    1101           3 :         kdc_log(r->context, config, 4, "Failed to verify AP-REQ: %s", msg);
    1102           3 :         krb5_free_error_message(r->context, msg);
    1103           3 :         goto out;
    1104             :     }
    1105             : 
    1106       51199 :     r->ticket_key = tkey;
    1107             : 
    1108             :     {
    1109        1672 :         krb5_authenticator auth;
    1110             : 
    1111       51199 :         ret = krb5_auth_con_getauthenticator(r->context, ac, &auth);
    1112       51199 :         if (ret == 0) {
    1113       51199 :             *csec   = malloc(sizeof(**csec));
    1114       51199 :             if (*csec == NULL) {
    1115           0 :                 krb5_free_authenticator(r->context, &auth);
    1116           0 :                 kdc_log(r->context, config, 4, "malloc failed");
    1117           1 :                 goto out;
    1118             :             }
    1119       51199 :             **csec  = auth->ctime;
    1120       51199 :             *cusec  = malloc(sizeof(**cusec));
    1121       51199 :             if (*cusec == NULL) {
    1122           0 :                 krb5_free_authenticator(r->context, &auth);
    1123           0 :                 kdc_log(r->context, config, 4, "malloc failed");
    1124           0 :                 goto out;
    1125             :             }
    1126       51199 :             **cusec  = auth->cusec;
    1127             : 
    1128       51199 :             ret = validate_fast_ad(r, auth->authorization_data);
    1129       51199 :             krb5_free_authenticator(r->context, &auth);
    1130       51199 :             if (ret)
    1131           1 :                 goto out;
    1132             :         }
    1133             :     }
    1134             : 
    1135       51198 :     ret = tgs_check_authenticator(r->context, config, ac, b, &r->ticket->ticket.key);
    1136       51198 :     if (ret) {
    1137           0 :         krb5_auth_con_free(r->context, ac);
    1138           0 :         goto out;
    1139             :     }
    1140             : 
    1141       51198 :     r->rk_is_subkey = 1;
    1142             : 
    1143       51198 :     ret = krb5_auth_con_getremotesubkey(r->context, ac, &subkey);
    1144       51198 :     if(ret){
    1145           0 :         const char *msg = krb5_get_error_message(r->context, ret);
    1146           0 :         krb5_auth_con_free(r->context, ac);
    1147           0 :         kdc_log(r->context, config, 4, "Failed to get remote subkey: %s", msg);
    1148           0 :         krb5_free_error_message(r->context, msg);
    1149           0 :         goto out;
    1150             :     }
    1151       51198 :     if(subkey == NULL){
    1152           4 :         r->rk_is_subkey = 0;
    1153             : 
    1154           4 :         ret = krb5_auth_con_getkey(r->context, ac, &subkey);
    1155           4 :         if(ret) {
    1156           0 :             const char *msg = krb5_get_error_message(r->context, ret);
    1157           0 :             krb5_auth_con_free(r->context, ac);
    1158           0 :             kdc_log(r->context, config, 4, "Failed to get session key: %s", msg);
    1159           0 :             krb5_free_error_message(r->context, msg);
    1160           0 :             goto out;
    1161             :         }
    1162             :     }
    1163       51198 :     if(subkey == NULL){
    1164           0 :         krb5_auth_con_free(r->context, ac);
    1165           0 :         kdc_log(r->context, config, 4,
    1166             :                 "Failed to get key for enc-authorization-data");
    1167           0 :         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
    1168           0 :         goto out;
    1169             :     }
    1170             : 
    1171       51198 :     krb5_free_keyblock_contents(r->context,  &r->reply_key);
    1172       51198 :     ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key);
    1173       51198 :     krb5_free_keyblock(r->context, subkey);
    1174       51198 :     if (ret)
    1175           0 :         goto out;
    1176             : 
    1177       51198 :     krb5_free_keyblock_contents(r->context,  &r->enc_ad_key);
    1178       51198 :     if (b->enc_authorization_data) {
    1179           5 :         ret = krb5_copy_keyblock_contents(r->context,
    1180           5 :                                           &r->reply_key,
    1181             :                                           &r->enc_ad_key);
    1182           5 :         if (ret)
    1183           0 :             goto out;
    1184             :     }
    1185             : 
    1186       51198 :     ret = validate_fast_ad(r, r->ticket->ticket.authorization_data);
    1187       51198 :     if (ret)
    1188           1 :         goto out;
    1189             : 
    1190             :     
    1191             :     /*
    1192             :      * Check for FAST request
    1193             :      */
    1194             : 
    1195       51197 :     ret = _kdc_fast_unwrap_request(r, r->ticket, ac);
    1196       51197 :     if (ret)
    1197           5 :         goto out;
    1198             : 
    1199       51192 :     krb5_auth_con_free(r->context, ac);
    1200             : 
    1201       52565 : out:
    1202       52565 :     free_AP_REQ(&ap_req);
    1203             : 
    1204       52565 :     return ret;
    1205             : }
    1206             : 
    1207             : static krb5_error_code
    1208        1152 : build_server_referral(krb5_context context,
    1209             :                       krb5_kdc_configuration *config,
    1210             :                       krb5_crypto session,
    1211             :                       krb5_const_realm referred_realm,
    1212             :                       const PrincipalName *true_principal_name,
    1213             :                       const PrincipalName *requested_principal,
    1214             :                       krb5_data *outdata)
    1215             : {
    1216           0 :     PA_ServerReferralData ref;
    1217           0 :     krb5_error_code ret;
    1218           0 :     EncryptedData ed;
    1219           0 :     krb5_data data;
    1220        1152 :     size_t size = 0;
    1221             : 
    1222        1152 :     memset(&ref, 0, sizeof(ref));
    1223             : 
    1224        1152 :     if (referred_realm) {
    1225        1152 :         ALLOC(ref.referred_realm);
    1226        1152 :         if (ref.referred_realm == NULL)
    1227           0 :             goto eout;
    1228        1152 :         *ref.referred_realm = strdup(referred_realm);
    1229        1152 :         if (*ref.referred_realm == NULL)
    1230           0 :             goto eout;
    1231             :     }
    1232        1152 :     if (true_principal_name) {
    1233           0 :         ALLOC(ref.true_principal_name);
    1234           0 :         if (ref.true_principal_name == NULL)
    1235           0 :             goto eout;
    1236           0 :         ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
    1237           0 :         if (ret)
    1238           0 :             goto eout;
    1239             :     }
    1240        1152 :     if (requested_principal) {
    1241        1152 :         ALLOC(ref.requested_principal_name);
    1242        1152 :         if (ref.requested_principal_name == NULL)
    1243           0 :             goto eout;
    1244        1152 :         ret = copy_PrincipalName(requested_principal,
    1245             :                                  ref.requested_principal_name);
    1246        1152 :         if (ret)
    1247           0 :             goto eout;
    1248             :     }
    1249             : 
    1250        1152 :     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
    1251             :                        data.data, data.length,
    1252             :                        &ref, &size, ret);
    1253        1152 :     free_PA_ServerReferralData(&ref);
    1254        1152 :     if (ret)
    1255           0 :         return ret;
    1256        1152 :     if (data.length != size)
    1257           0 :         krb5_abortx(context, "internal asn.1 encoder error");
    1258             : 
    1259        1152 :     ret = krb5_encrypt_EncryptedData(context, session,
    1260             :                                      KRB5_KU_PA_SERVER_REFERRAL,
    1261             :                                      data.data, data.length,
    1262             :                                      0 /* kvno */, &ed);
    1263        1152 :     free(data.data);
    1264        1152 :     if (ret)
    1265           0 :         return ret;
    1266             : 
    1267        1152 :     ASN1_MALLOC_ENCODE(EncryptedData,
    1268             :                        outdata->data, outdata->length,
    1269             :                        &ed, &size, ret);
    1270        1152 :     free_EncryptedData(&ed);
    1271        1152 :     if (ret)
    1272           0 :         return ret;
    1273        1152 :     if (outdata->length != size)
    1274           0 :         krb5_abortx(context, "internal asn.1 encoder error");
    1275             : 
    1276        1152 :     return 0;
    1277           0 : eout:
    1278           0 :     free_PA_ServerReferralData(&ref);
    1279           0 :     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
    1280           0 :     return ENOMEM;
    1281             : }
    1282             : 
    1283             : /*
    1284             :  * This function is intended to be used when failure to find the client is
    1285             :  * acceptable.
    1286             :  */
    1287             : krb5_error_code
    1288       50647 : _kdc_db_fetch_client(krb5_context context,
    1289             :                      krb5_kdc_configuration *config,
    1290             :                      int flags,
    1291             :                      krb5_principal cp,
    1292             :                      const char *cpn,
    1293             :                      const char *krbtgt_realm,
    1294             :                      HDB **clientdb,
    1295             :                      hdb_entry **client_out)
    1296             : {
    1297        1672 :     krb5_error_code ret;
    1298       50647 :     hdb_entry *client = NULL;
    1299             : 
    1300       50647 :     *clientdb = NULL;
    1301       50647 :     *client_out = NULL;
    1302             : 
    1303       50647 :     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
    1304             :                         NULL, clientdb, &client);
    1305       50647 :     if (ret == HDB_ERR_NOT_FOUND_HERE) {
    1306             :         /*
    1307             :          * This is OK, we are just trying to find out if they have
    1308             :          * been disabled or deleted in the meantime; missing secrets
    1309             :          * are OK.
    1310             :          */
    1311       50647 :     } else if (ret) {
    1312             :         /*
    1313             :          * If the client belongs to the same realm as our TGS, it
    1314             :          * should exist in the local database.
    1315             :          */
    1316           0 :         const char *msg;
    1317             : 
    1318          61 :         if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
    1319           1 :             if (ret == HDB_ERR_NOENTRY)
    1320           1 :                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    1321           1 :             kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
    1322           1 :             return ret;
    1323             :         }
    1324             : 
    1325          60 :         msg = krb5_get_error_message(context, ret);
    1326          60 :         kdc_log(context, config, 4, "Client not found in database: %s", msg);
    1327          60 :         krb5_free_error_message(context, msg);
    1328       50586 :     } else if (client->flags.invalid || !client->flags.client) {
    1329           0 :         kdc_log(context, config, 4, "Client has invalid bit set");
    1330           0 :         _kdc_free_ent(context, *clientdb, client);
    1331           0 :         return KRB5KDC_ERR_POLICY;
    1332             :     }
    1333             : 
    1334       50646 :     *client_out = client;
    1335             : 
    1336       50646 :     return 0;
    1337             : }
    1338             : 
    1339             : static krb5_error_code
    1340       51192 : tgs_build_reply(astgs_request_t priv,
    1341             :                 krb5_enctype krbtgt_etype,
    1342             :                 const struct sockaddr *from_addr)
    1343             : {
    1344       51192 :     krb5_context context = priv->context;
    1345       51192 :     krb5_kdc_configuration *config = priv->config;
    1346       51192 :     KDC_REQ_BODY *b = &priv->req.req_body;
    1347       51192 :     const char *from = priv->from;
    1348        1672 :     krb5_error_code ret, ret2;
    1349       51192 :     krb5_principal krbtgt_out_principal = NULL;
    1350       51192 :     krb5_principal user2user_princ = NULL;
    1351       51192 :     char *spn = NULL, *cpn = NULL, *krbtgt_out_n = NULL;
    1352       51192 :     char *user2user_name = NULL;
    1353        1672 :     HDB *user2user_krbtgtdb;
    1354       51192 :     hdb_entry *user2user_krbtgt = NULL;
    1355       51192 :     HDB *clientdb = NULL;
    1356       51192 :     HDB *serverdb = NULL;
    1357       51192 :     krb5_realm ref_realm = NULL;
    1358       51192 :     EncTicketPart *tgt = &priv->ticket->ticket;
    1359        1672 :     const EncryptionKey *ekey;
    1360        1672 :     krb5_keyblock sessionkey;
    1361        1672 :     krb5_kvno kvno;
    1362       51192 :     krb5_pac user2user_pac = NULL;
    1363        1672 :     uint16_t rodc_id;
    1364       51192 :     krb5_boolean add_ticket_sig = FALSE;
    1365        1672 :     const char *tgt_realm = /* Realm of TGT issuer */
    1366       51192 :         krb5_principal_get_realm(context, priv->krbtgt->principal);
    1367        1672 :     const char *our_realm = /* Realm of this KDC */
    1368       51192 :         krb5_principal_get_comp_string(context, priv->krbtgt->principal, 1);
    1369       51192 :     char **capath = NULL;
    1370       51192 :     size_t num_capath = 0;
    1371       51192 :     AuthorizationData *auth_data = NULL;
    1372             : 
    1373        1672 :     HDB *krbtgt_outdb;
    1374       51192 :     hdb_entry *krbtgt_out = NULL;
    1375             : 
    1376        1672 :     PrincipalName *s;
    1377        1672 :     Realm r;
    1378        1672 :     EncTicketPart adtkt;
    1379        1672 :     char opt_str[128];
    1380       51192 :     krb5_boolean kdc_issued = FALSE;
    1381             : 
    1382        1672 :     Key *tkey_sign;
    1383       51192 :     int flags = HDB_F_FOR_TGS_REQ;
    1384        1672 :     int server_flags;
    1385             : 
    1386        1672 :     int result;
    1387             : 
    1388       51192 :     const PA_DATA *for_user = NULL;
    1389       51192 :     int for_user_idx = 0;
    1390             : 
    1391       51192 :     memset(&sessionkey, 0, sizeof(sessionkey));
    1392       51192 :     memset(&adtkt, 0, sizeof(adtkt));
    1393             : 
    1394       51192 :     s = b->sname;
    1395       51192 :     r = b->realm;
    1396             : 
    1397             :     /*
    1398             :      * The canonicalize KDC option is passed as a hint to the backend, but
    1399             :      * can typically be ignored. Per RFC 6806, names are not canonicalized
    1400             :      * in response to a TGS request (although we make an exception, see
    1401             :      * force-canonicalize below).
    1402             :      */
    1403       51192 :     if (b->kdc_options.canonicalize)
    1404        8985 :         flags |= HDB_F_CANON;
    1405             : 
    1406       51192 :     server_flags = HDB_F_GET_SERVER | HDB_F_DELAY_NEW_KEYS | flags;
    1407       51192 :     if (b->kdc_options.enc_tkt_in_skey)
    1408          43 :         server_flags |= HDB_F_USER2USER_PRINCIPAL;
    1409             : 
    1410       51192 :     if (s == NULL) {
    1411           4 :         ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
    1412           4 :         _kdc_set_const_e_text(priv, "No server in request");
    1413           4 :         goto out;
    1414             :     }
    1415             : 
    1416       51188 :     _krb5_principalname2krb5_principal(context, &priv->server_princ, *s, r);
    1417       51188 :     ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
    1418       51188 :     if (ret)
    1419           0 :         goto out;
    1420       51188 :     spn = priv->sname;
    1421       51188 :     _krb5_principalname2krb5_principal(context, &priv->client_princ,
    1422             :                                        tgt->cname, tgt->crealm);
    1423       51188 :     ret = krb5_unparse_name(context, priv->client_princ, &priv->cname);
    1424       51188 :     if (ret)
    1425           0 :         goto out;
    1426       51188 :     cpn = priv->cname;
    1427       51188 :     result = unparse_flags(KDCOptions2int(b->kdc_options),
    1428             :                            asn1_KDCOptions_units(),
    1429             :                            opt_str, sizeof(opt_str));
    1430       51188 :     if (result > 0)
    1431       46163 :         kdc_log(context, config, 4,
    1432             :                 "TGS-REQ %s from %s for %s [%s]",
    1433             :                 cpn, from, spn, opt_str);
    1434             :     else
    1435        5025 :         kdc_log(context, config, 4,
    1436             :                 "TGS-REQ %s from %s for %s", cpn, from, spn);
    1437             : 
    1438             :     /*
    1439             :      * Fetch server
    1440             :      */
    1441             : 
    1442       49516 : server_lookup:
    1443       52340 :     if (priv->server)
    1444        1152 :         _kdc_free_ent(context, serverdb, priv->server);
    1445       52340 :     priv->server = NULL;
    1446       52340 :     ret = _kdc_db_fetch(context, config, priv->server_princ,
    1447             :                         server_flags,
    1448             :                         NULL, &serverdb, &priv->server);
    1449       52340 :     priv->serverdb = serverdb;
    1450       52340 :     if (ret == HDB_ERR_NOT_FOUND_HERE) {
    1451          42 :         kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn);
    1452          42 :         kdc_audit_addreason((kdc_request_t)priv, "Target not found here");
    1453          42 :         goto out;
    1454       52298 :     } else if (ret == HDB_ERR_WRONG_REALM) {
    1455        1152 :         free(ref_realm);
    1456        1152 :         ref_realm = strdup(priv->server->principal->realm);
    1457        1152 :         if (ref_realm == NULL) {
    1458           0 :             ret = krb5_enomem(context);
    1459           0 :             goto out;
    1460             :         }
    1461             : 
    1462        1152 :         kdc_log(context, config, 4,
    1463             :                 "Returning a referral to realm %s for "
    1464             :                 "server %s.",
    1465             :                 ref_realm, spn);
    1466        1152 :         krb5_free_principal(context, priv->server_princ);
    1467        1152 :         priv->server_princ = NULL;
    1468        1152 :         ret = krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME,
    1469             :                                   ref_realm, NULL);
    1470        1152 :         if (ret)
    1471           0 :             goto out;
    1472        1152 :         free(priv->sname);
    1473        1152 :         priv->sname = NULL;
    1474        1152 :         ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
    1475        1152 :         if (ret)
    1476           0 :             goto out;
    1477        1152 :         spn = priv->sname;
    1478             : 
    1479        1152 :         goto server_lookup;
    1480       51146 :     } else if (ret) {
    1481           0 :         const char *new_rlm, *msg;
    1482           0 :         Realm req_rlm;
    1483           0 :         krb5_realm *realms;
    1484             : 
    1485        1246 :         priv->error_code = ret; /* advise policy plugin of failure reason */
    1486        1246 :         ret2 = _kdc_referral_policy(priv);
    1487        1246 :         if (ret2 == 0) {
    1488           0 :             krb5_xfree(priv->sname);
    1489           0 :             priv->sname = NULL;
    1490           0 :             ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
    1491           0 :             if (ret)
    1492        1246 :                 goto out;
    1493           0 :             goto server_lookup;
    1494        1246 :         } else if (ret2 != KRB5_PLUGIN_NO_HANDLE) {
    1495        1246 :             ret = ret2;
    1496           0 :         } else if ((req_rlm = get_krbtgt_realm(&priv->server_princ->name)) != NULL) {
    1497           0 :             if (capath == NULL) {
    1498             :                 /* With referalls, hierarchical capaths are always enabled */
    1499           0 :                 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
    1500             :                                          req_rlm, TRUE, &capath, &num_capath);
    1501           0 :                 if (ret2) {
    1502           0 :                     ret = ret2;
    1503           0 :                     kdc_audit_addreason((kdc_request_t)priv,
    1504             :                                         "No trusted path from client realm to ours");
    1505           0 :                     goto out;
    1506             :                 }
    1507             :             }
    1508           0 :             new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
    1509           0 :             if (new_rlm) {
    1510           0 :                 kdc_log(context, config, 5, "krbtgt from %s via %s for "
    1511             :                         "realm %s not found, trying %s", tgt->crealm,
    1512             :                         our_realm, req_rlm, new_rlm);
    1513             : 
    1514           0 :                 free(ref_realm);
    1515           0 :                 ref_realm = strdup(new_rlm);
    1516           0 :                 if (ref_realm == NULL) {
    1517           0 :                     ret = krb5_enomem(context);
    1518           0 :                     goto out;
    1519             :                 }
    1520             : 
    1521           0 :                 krb5_free_principal(context, priv->server_princ);
    1522           0 :                 priv->server_princ = NULL;
    1523           0 :                 krb5_make_principal(context, &priv->server_princ, r,
    1524             :                                     KRB5_TGS_NAME, ref_realm, NULL);
    1525           0 :                 free(priv->sname);
    1526           0 :                 priv->sname = NULL;
    1527           0 :                 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
    1528           0 :                 if (ret)
    1529           0 :                     goto out;
    1530           0 :                 spn = priv->sname;
    1531           0 :                 goto server_lookup;
    1532             :             }
    1533           0 :         } else if (need_referral(context, config, &b->kdc_options, priv->server_princ, &realms)) {
    1534           0 :             if (strcmp(realms[0], priv->server_princ->realm) != 0) {
    1535           0 :                 kdc_log(context, config, 4,
    1536             :                         "Returning a referral to realm %s for "
    1537             :                         "server %s that was not found",
    1538             :                         realms[0], spn);
    1539           0 :                 krb5_free_principal(context, priv->server_princ);
    1540           0 :                 priv->server_princ = NULL;
    1541           0 :                 krb5_make_principal(context, &priv->server_princ, r, KRB5_TGS_NAME,
    1542             :                                     realms[0], NULL);
    1543           0 :                 free(priv->sname);
    1544           0 :                 priv->sname = NULL;
    1545           0 :                 ret = krb5_unparse_name(context, priv->server_princ, &priv->sname);
    1546           0 :                 if (ret) {
    1547           0 :                     krb5_free_host_realm(context, realms);
    1548           0 :                     goto out;
    1549             :                 }
    1550           0 :                 spn = priv->sname;
    1551             : 
    1552           0 :                 free(ref_realm);
    1553           0 :                 ref_realm = strdup(realms[0]);
    1554             : 
    1555           0 :                 krb5_free_host_realm(context, realms);
    1556           0 :                 goto server_lookup;
    1557             :             }
    1558           0 :             krb5_free_host_realm(context, realms);
    1559             :         }
    1560        1246 :         msg = krb5_get_error_message(context, ret);
    1561        1246 :         kdc_log(context, config, 3,
    1562             :                 "Server not found in database: %s: %s", spn, msg);
    1563        1246 :         krb5_free_error_message(context, msg);
    1564        1246 :         if (ret == HDB_ERR_NOENTRY)
    1565        1246 :             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
    1566        1246 :         kdc_audit_addreason((kdc_request_t)priv,
    1567             :                             "Service principal unknown");
    1568        1246 :         goto out;
    1569             :     }
    1570             : 
    1571             :     /*
    1572             :      * Now refetch the primary krbtgt, and get the current kvno (the
    1573             :      * sign check may have been on an old kvno, and the server may
    1574             :      * have been an incoming trust)
    1575             :      */
    1576             : 
    1577       49900 :     ret = krb5_make_principal(context,
    1578             :                               &krbtgt_out_principal,
    1579             :                               our_realm,
    1580             :                               KRB5_TGS_NAME,
    1581             :                               our_realm,
    1582             :                               NULL);
    1583       49900 :     if (ret) {
    1584           0 :         kdc_log(context, config, 4,
    1585             :                 "Failed to make krbtgt principal name object for "
    1586             :                 "authz-data signatures");
    1587           0 :         goto out;
    1588             :     }
    1589       49900 :     ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
    1590       49900 :     if (ret) {
    1591           0 :         kdc_log(context, config, 4,
    1592             :                 "Failed to make krbtgt principal name object for "
    1593             :                 "authz-data signatures");
    1594           0 :         goto out;
    1595             :     }
    1596             : 
    1597       49900 :     ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
    1598             :                         HDB_F_GET_KRBTGT, NULL, &krbtgt_outdb, &krbtgt_out);
    1599       49900 :     if (ret) {
    1600           0 :         char *ktpn = NULL;
    1601           0 :         ret = krb5_unparse_name(context, priv->krbtgt->principal, &ktpn);
    1602           0 :         kdc_log(context, config, 4,
    1603             :                 "No such principal %s (needed for authz-data signature keys) "
    1604             :                 "while processing TGS-REQ for service %s with krbtgt %s",
    1605             :                 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
    1606           0 :         free(ktpn);
    1607           0 :         ret = KRB5KRB_AP_ERR_NOT_US;
    1608           0 :         goto out;
    1609             :     }
    1610             : 
    1611             :     /*
    1612             :      * Select enctype, return key and kvno.
    1613             :      */
    1614             : 
    1615             :     {
    1616        1672 :         krb5_enctype etype;
    1617             : 
    1618       49900 :         if(b->kdc_options.enc_tkt_in_skey) {
    1619           0 :             Ticket *t;
    1620           0 :             krb5_principal p;
    1621           0 :             Key *uukey;
    1622          39 :             krb5uint32 second_kvno = 0;
    1623          39 :             krb5uint32 *kvno_ptr = NULL;
    1624           0 :             size_t i;
    1625           0 :             HDB *user2user_db;
    1626          39 :             hdb_entry *user2user_client = NULL;
    1627          39 :             krb5_boolean user2user_kdc_issued = FALSE;
    1628           0 :             char *tpn;
    1629             : 
    1630          39 :             if(b->additional_tickets == NULL ||
    1631          39 :                b->additional_tickets->len == 0){
    1632           0 :                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
    1633           0 :                 kdc_log(context, config, 4,
    1634             :                         "No second ticket present in user-to-user request");
    1635           0 :                 kdc_audit_addreason((kdc_request_t)priv,
    1636             :                                     "No second ticket present in user-to-user request");
    1637          19 :                 goto out;
    1638             :             }
    1639          39 :             t = &b->additional_tickets->val[0];
    1640          39 :             if(!krb5_principalname_is_krbtgt(context, &t->sname)){
    1641             :                 /*
    1642             :                  * Note: this check is not to be depended upon for
    1643             :                  * security. Nothing prevents a client modifying the sname, as
    1644             :                  * it is located in the unencrypted part of the ticket.
    1645             :                  */
    1646             : 
    1647           1 :                 kdc_log(context, config, 4,
    1648             :                         "Additional ticket is not a ticket-granting ticket");
    1649           1 :                 kdc_audit_addreason((kdc_request_t)priv,
    1650             :                                     "Additional ticket is not a ticket-granting ticket");
    1651           1 :                 ret = KRB5KDC_ERR_POLICY;
    1652           1 :                 goto out;
    1653             :             }
    1654          38 :             ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
    1655          38 :             if (ret)
    1656           0 :                 goto out;
    1657             : 
    1658          38 :             ret = krb5_unparse_name(context, p, &tpn);
    1659          38 :             if (ret)
    1660           0 :                 goto out;
    1661          38 :             if(t->enc_part.kvno){
    1662          38 :                 second_kvno = *t->enc_part.kvno;
    1663          38 :                 kvno_ptr = &second_kvno;
    1664             :             }
    1665          38 :             ret = _kdc_db_fetch(context, config, p,
    1666             :                                 HDB_F_GET_KRBTGT, kvno_ptr,
    1667             :                                 &user2user_krbtgtdb, &user2user_krbtgt);
    1668          38 :             krb5_free_principal(context, p);
    1669          38 :             if(ret){
    1670           0 :                 if (ret == HDB_ERR_NOENTRY)
    1671           0 :                     ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
    1672           0 :                 kdc_audit_addreason((kdc_request_t)priv,
    1673             :                                     "User-to-user service principal (TGS) unknown");
    1674           0 :                 krb5_xfree(tpn);
    1675           0 :                 goto out;
    1676             :             }
    1677          38 :             ret = hdb_enctype2key(context, user2user_krbtgt, NULL,
    1678             :                                   t->enc_part.etype, &uukey);
    1679          38 :             if(ret){
    1680           1 :                 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
    1681           1 :                 kdc_audit_addreason((kdc_request_t)priv,
    1682             :                                     "User-to-user enctype not supported");
    1683           1 :                 krb5_xfree(tpn);
    1684           1 :                 goto out;
    1685             :             }
    1686          37 :             ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
    1687          37 :             if(ret) {
    1688           1 :                 kdc_audit_addreason((kdc_request_t)priv,
    1689             :                                     "User-to-user TGT decrypt failure");
    1690           1 :                 krb5_xfree(tpn);
    1691           1 :                 goto out;
    1692             :             }
    1693             : 
    1694          36 :             ret = _kdc_verify_flags(context, config, &adtkt, tpn);
    1695          36 :             if (ret) {
    1696           0 :                 kdc_audit_addreason((kdc_request_t)priv,
    1697             :                                     "User-to-user TGT expired or invalid");
    1698           0 :                 krb5_xfree(tpn);
    1699           0 :                 goto out;
    1700             :             }
    1701          36 :             krb5_xfree(tpn);
    1702             : 
    1703             :             /* Fetch the name from the TGT. */
    1704          36 :             ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
    1705             :                                                      adtkt.cname, adtkt.crealm);
    1706          36 :             if (ret)
    1707           0 :                 goto out;
    1708             : 
    1709          36 :             ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
    1710          36 :             if (ret)
    1711           0 :                 goto out;
    1712             : 
    1713             :             /*
    1714             :              * Look up the name given in the TGT in the database. The user
    1715             :              * claims to have a ticket-granting-ticket to our KDC, so we should
    1716             :              * fail hard if we can't find the user - otherwise we can't do
    1717             :              * proper checks.
    1718             :              */
    1719          36 :             ret = _kdc_db_fetch(context, config, user2user_princ,
    1720          36 :                                 HDB_F_GET_CLIENT | flags,
    1721             :                                 NULL, &user2user_db, &user2user_client);
    1722          36 :             if (ret == HDB_ERR_NOENTRY)
    1723           2 :                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
    1724          36 :             if (ret)
    1725           2 :                 goto out;
    1726             : 
    1727             :             /*
    1728             :              * The account is present in the database, now check the
    1729             :              * account flags.
    1730             :              *
    1731             :              * We check this as a client (because the purpose of
    1732             :              * user2user is that the server flag is not set, because
    1733             :              * the long-term key is not strong, but this does mean
    1734             :              * that a client with an expired password can't get accept
    1735             :              * a user2user ticket.
    1736             :              */
    1737          34 :             ret = kdc_check_flags(priv,
    1738             :                                   FALSE,
    1739             :                                   user2user_client,
    1740             :                                   NULL);
    1741          34 :             if (ret) {
    1742           0 :                 _kdc_free_ent(context, user2user_db, user2user_client);
    1743           0 :                 goto out;
    1744             :             }
    1745             : 
    1746             :             /*
    1747             :              * Also check that the account is the same one specified in the
    1748             :              * request.
    1749             :              */
    1750          34 :             ret = _kdc_check_client_matches_target_service(context,
    1751             :                                                            config,
    1752             :                                                            serverdb,
    1753             :                                                            priv->server,
    1754             :                                                            user2user_client,
    1755             :                                                            user2user_princ);
    1756          34 :             if (ret) {
    1757           2 :                 _kdc_free_ent(context, user2user_db, user2user_client);
    1758           2 :                 goto out;
    1759             :             }
    1760             : 
    1761             :             /* Verify the PAC of the TGT. */
    1762          32 :             ret = _kdc_check_pac(priv, user2user_princ, NULL,
    1763             :                                  user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
    1764          32 :                                  &uukey->key, &priv->ticket_key->key, &adtkt,
    1765             :                                  &user2user_kdc_issued, &user2user_pac, NULL, NULL);
    1766          32 :             _kdc_free_ent(context, user2user_db, user2user_client);
    1767          32 :             if (ret) {
    1768          12 :                 const char *msg = krb5_get_error_message(context, ret);
    1769          12 :                 kdc_log(context, config, 0,
    1770             :                         "Verify PAC failed for %s (%s) from %s with %s",
    1771             :                         spn, user2user_name, from, msg);
    1772          12 :                 krb5_free_error_message(context, msg);
    1773          12 :                 goto out;
    1774             :             }
    1775             : 
    1776          20 :             if ((config->require_pac && !user2user_pac)
    1777          20 :                 || (user2user_pac && !user2user_kdc_issued))
    1778             :             {
    1779           0 :                 ret = KRB5KDC_ERR_BADOPTION;
    1780           0 :                 kdc_log(context, config, 0,
    1781             :                         "Ticket not signed with PAC; user-to-user failed (%s).",
    1782           0 :                         user2user_pac ? "Ticket unsigned" : "No PAC");
    1783           0 :                 goto out;
    1784             :             }
    1785             : 
    1786          20 :             ekey = &adtkt.key;
    1787          20 :             for(i = 0; i < b->etype.len; i++)
    1788          20 :                 if (b->etype.val[i] == adtkt.key.keytype)
    1789          20 :                     break;
    1790          20 :             if(i == b->etype.len) {
    1791           0 :                 kdc_log(context, config, 4,
    1792             :                         "Addition ticket has no matching etypes");
    1793           0 :                 krb5_clear_error_message(context);
    1794           0 :                 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
    1795           0 :                 kdc_audit_addreason((kdc_request_t)priv,
    1796             :                                     "No matching enctypes for 2nd ticket");
    1797           0 :                 goto out;
    1798             :             }
    1799          20 :             etype = b->etype.val[i];
    1800          20 :             kvno = 0;
    1801             :         } else {
    1802        1672 :             Key *skey;
    1803             : 
    1804       51533 :             ret = _kdc_find_session_etype(priv, b->etype.val, b->etype.len,
    1805       49861 :                                           priv->server, &etype);
    1806       49861 :             if(ret) {
    1807         113 :                 kdc_log(context, config, 4,
    1808             :                         "Server (%s) has no support for etypes", spn);
    1809         113 :                 kdc_audit_addreason((kdc_request_t)priv,
    1810             :                                     "Enctype not supported");
    1811         251 :                 goto out;
    1812             :             }
    1813       49748 :             ret = _kdc_get_preferred_key(context, config, priv->server, spn,
    1814             :                                          NULL, &skey);
    1815       49748 :             if(ret) {
    1816         138 :                 kdc_log(context, config, 4,
    1817             :                         "Server (%s) has no supported etypes", spn);
    1818         138 :                 kdc_audit_addreason((kdc_request_t)priv,
    1819             :                                     "Enctype not supported");
    1820         138 :                 goto out;
    1821             :             }
    1822       49610 :             ekey = &skey->key;
    1823       49610 :             kvno = priv->server->kvno;
    1824             :         }
    1825             : 
    1826       49630 :         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
    1827       49630 :         if (ret)
    1828           0 :             goto out;
    1829             :     }
    1830             : 
    1831             :     /*
    1832             :      * Check that service is in the same realm as the krbtgt. If it's
    1833             :      * not the same, it's someone that is using a uni-directional trust
    1834             :      * backward.
    1835             :      */
    1836             : 
    1837             :     /* 
    1838             :      * The first realm is the realm of the service, the second is
    1839             :      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
    1840             :      * encrypted to.  The redirection via the krbtgt_out entry allows
    1841             :      * the DB to possibly correct the case of the realm (Samba4 does
    1842             :      * this) before the strcmp() 
    1843             :      */
    1844       49630 :     if (strcmp(krb5_principal_get_realm(context, priv->server->principal),
    1845       49630 :                krb5_principal_get_realm(context, krbtgt_out->principal)) != 0) {
    1846           0 :         char *ktpn;
    1847           0 :         ret = krb5_unparse_name(context, krbtgt_out->principal, &ktpn);
    1848           0 :         kdc_log(context, config, 4,
    1849             :                 "Request with wrong krbtgt: %s",
    1850             :                 (ret == 0) ? ktpn : "<unknown>");
    1851           0 :         if(ret == 0)
    1852           0 :             free(ktpn);
    1853           0 :         ret = KRB5KRB_AP_ERR_NOT_US;
    1854           0 :         kdc_audit_addreason((kdc_request_t)priv, "Request with wrong TGT");
    1855           0 :         goto out;
    1856             :     }
    1857             : 
    1858       49630 :     ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
    1859             :                                  NULL, &tkey_sign);
    1860       49630 :     if (ret) {
    1861           0 :         kdc_log(context, config, 4,
    1862             :                     "Failed to find key for krbtgt PAC signature");
    1863           0 :         kdc_audit_addreason((kdc_request_t)priv,
    1864             :                             "Failed to find key for krbtgt PAC signature");
    1865           0 :         goto out;
    1866             :     }
    1867       51302 :     ret = hdb_enctype2key(context, krbtgt_out, NULL,
    1868       49630 :                           tkey_sign->key.keytype, &tkey_sign);
    1869       49630 :     if(ret) {
    1870           0 :         kdc_log(context, config, 4,
    1871             :                     "Failed to find key for krbtgt PAC signature");
    1872           0 :         kdc_audit_addreason((kdc_request_t)priv,
    1873             :                             "Failed to find key for krbtgt PAC signature");
    1874           0 :         goto out;
    1875             :     }
    1876             : 
    1877       49630 :     if (_kdc_synthetic_princ_used_p(context, priv->ticket))
    1878          16 :         flags |= HDB_F_SYNTHETIC_OK;
    1879             : 
    1880       49630 :     ret = _kdc_db_fetch_client(context, config, flags, priv->client_princ,
    1881             :                                cpn, our_realm, &clientdb, &priv->client);
    1882       49630 :     if (ret)
    1883           1 :         goto out;
    1884             :     /* flags &= ~HDB_F_SYNTHETIC_OK; */ /* `flags' is not used again below */
    1885       49629 :     priv->clientdb = clientdb;
    1886             : 
    1887             :     /* Validate armor TGT before potentially including device claims */
    1888       49629 :     if (priv->armor_ticket) {
    1889         324 :         ret = _kdc_fast_check_armor_pac(priv, HDB_F_FOR_TGS_REQ);
    1890         324 :         if (ret)
    1891          12 :             goto out;
    1892             :     }
    1893             : 
    1894       51289 :     ret = _kdc_check_pac(priv, priv->client_princ, NULL,
    1895             :                          priv->client, priv->server,
    1896             :                          priv->krbtgt, priv->krbtgt,
    1897       49617 :                          &priv->ticket_key->key, &priv->ticket_key->key, tgt,
    1898             :                          &kdc_issued, &priv->pac, &priv->canon_client_princ,
    1899             :                          &priv->pac_attributes);
    1900       49617 :     if (ret) {
    1901          99 :         const char *msg = krb5_get_error_message(context, ret);
    1902          99 :         kdc_audit_addreason((kdc_request_t)priv, "PAC check failed");
    1903          99 :         kdc_log(context, config, 4,
    1904             :                 "Verify PAC failed for %s (%s) from %s with %s",
    1905             :                 spn, cpn, from, msg);
    1906          99 :         krb5_free_error_message(context, msg);
    1907          99 :         goto out;
    1908             :     }
    1909             : 
    1910             :     /*
    1911             :      * Process request
    1912             :      */
    1913             : 
    1914             :     /*
    1915             :      * Services for User: protocol transition and constrained delegation
    1916             :      */
    1917             : 
    1918       97305 :     if (priv->client != NULL &&
    1919       49459 :         (for_user = _kdc_find_padata(&priv->req,
    1920             :                                      &for_user_idx,
    1921             :                                      KRB5_PADATA_FOR_USER)) != NULL)
    1922             :     {
    1923             :         /* Process an S4U2Self request. */
    1924         658 :         ret = _kdc_validate_protocol_transition(priv, for_user);
    1925         658 :         if (ret)
    1926           8 :             goto out;
    1927       48860 :     } else if (priv->client != NULL
    1928       48801 :                && b->additional_tickets != NULL
    1929         284 :                && b->additional_tickets->len != 0
    1930         284 :                && b->kdc_options.cname_in_addl_tkt
    1931         264 :                && b->kdc_options.enc_tkt_in_skey == 0)
    1932             :     {
    1933             :         /* Process an S4U2Proxy request. */
    1934         264 :         ret = _kdc_validate_constrained_delegation(priv);
    1935         264 :         if (ret)
    1936         124 :             goto out;
    1937       48596 :     } else if (priv->pac != NULL) {
    1938       48596 :         ret = _kdc_pac_update(priv, priv->client_princ, NULL, NULL,
    1939             :                               priv->client, priv->server, priv->krbtgt,
    1940             :                               &priv->pac);
    1941       48596 :         if (ret == KRB5_PLUGIN_NO_HANDLE) {
    1942           0 :             ret = 0;
    1943             :         }
    1944       48596 :         if (ret) {
    1945          51 :             const char *msg = krb5_get_error_message(context, ret);
    1946          51 :             kdc_audit_addreason((kdc_request_t)priv, "PAC update failed");
    1947          51 :             kdc_log(context, config, 4,
    1948             :                     "Update PAC failed for %s (%s) from %s with %s",
    1949             :                     spn, cpn, from, msg);
    1950          51 :             krb5_free_error_message(context, msg);
    1951          51 :             goto out;
    1952             :         }
    1953             : 
    1954       48545 :         if (priv->pac == NULL) {
    1955             :             /* the plugin may indicate no PAC should be generated */
    1956           8 :             priv->pac_attributes = 0;
    1957             :         }
    1958             :     }
    1959             : 
    1960       49335 :     if (b->enc_authorization_data) {
    1961           0 :         unsigned auth_data_usage;
    1962           0 :         krb5_crypto crypto;
    1963           0 :         krb5_data ad;
    1964             : 
    1965           5 :         if (priv->rk_is_subkey != 0) {
    1966           3 :             auth_data_usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
    1967             :         } else {
    1968           2 :             auth_data_usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
    1969             :         }
    1970             : 
    1971           5 :         ret = krb5_crypto_init(context, &priv->enc_ad_key, 0, &crypto);
    1972           5 :         if (ret) {
    1973           0 :             const char *msg = krb5_get_error_message(context, ret);
    1974           0 :             kdc_audit_addreason((kdc_request_t)priv,
    1975             :                                 "krb5_crypto_init() failed for "
    1976             :                                 "enc_authorization_data");
    1977           0 :             kdc_log(context, config, 4, "krb5_crypto_init failed: %s", msg);
    1978           0 :             krb5_free_error_message(context, msg);
    1979           0 :             goto out;
    1980             :         }
    1981           5 :         ret = krb5_decrypt_EncryptedData(context,
    1982             :                                          crypto,
    1983             :                                          auth_data_usage,
    1984           5 :                                          b->enc_authorization_data,
    1985             :                                          &ad);
    1986           5 :         krb5_crypto_destroy(context, crypto);
    1987           5 :         if(ret){
    1988           0 :             kdc_audit_addreason((kdc_request_t)priv,
    1989             :                                 "Failed to decrypt enc-authorization-data");
    1990           0 :             kdc_log(context, config, 4,
    1991             :                     "Failed to decrypt enc-authorization-data");
    1992           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
    1993           0 :             goto out;
    1994             :         }
    1995           5 :         ALLOC(auth_data);
    1996           5 :         if (auth_data == NULL) {
    1997           0 :             krb5_data_free(&ad);
    1998           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
    1999           0 :             goto out;
    2000             :         }
    2001           5 :         ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
    2002           5 :         krb5_data_free(&ad);
    2003           5 :         if(ret){
    2004           0 :             free(auth_data);
    2005           0 :             auth_data = NULL;
    2006           0 :             kdc_audit_addreason((kdc_request_t)priv,
    2007             :                                 "Failed to decode authorization data");
    2008           0 :             kdc_log(context, config, 4, "Failed to decode authorization data");
    2009           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
    2010           0 :             goto out;
    2011             :         }
    2012             :     }
    2013             : 
    2014             :     /*
    2015             :      * Check flags
    2016             :      */
    2017             : 
    2018       49335 :     ret = kdc_check_flags(priv, FALSE, priv->client, priv->server);
    2019       49335 :     if(ret)
    2020           0 :         goto out;
    2021             : 
    2022       49395 :     if((b->kdc_options.validate || b->kdc_options.renew) &&
    2023          60 :        !krb5_principal_compare(context,
    2024          60 :                                priv->krbtgt->principal,
    2025          60 :                                priv->server->principal)){
    2026           0 :         kdc_audit_addreason((kdc_request_t)priv, "Inconsistent request");
    2027           0 :         kdc_log(context, config, 4, "Inconsistent request.");
    2028           0 :         ret = KRB5KDC_ERR_SERVER_NOMATCH;
    2029           0 :         goto out;
    2030             :     }
    2031             : 
    2032             :     /* check for valid set of addresses */
    2033       49335 :     if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) {
    2034           0 :         if (config->check_ticket_addresses) {
    2035           0 :             ret = KRB5KRB_AP_ERR_BADADDR;
    2036           0 :             kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE);
    2037           0 :             kdc_log(context, config, 4, "Request from wrong address");
    2038           0 :             kdc_audit_addreason((kdc_request_t)priv, "Request from wrong address");
    2039           0 :             goto out;
    2040           0 :         } else if (config->warn_ticket_addresses) {
    2041           0 :             kdc_audit_setkv_bool((kdc_request_t)priv, "wrongaddr", TRUE);
    2042             :         }
    2043             :     }
    2044             : 
    2045             :     /* check local and per-principal anonymous ticket issuance policy */
    2046       51007 :     if (is_anon_tgs_request_p(b, tgt)) {
    2047           0 :         ret = _kdc_check_anon_policy(priv);
    2048           0 :         if (ret)
    2049           0 :             goto out;
    2050             :     }
    2051             : 
    2052             :     /*
    2053             :      * If this is an referral, add server referral data to the
    2054             :      * auth_data reply .
    2055             :      */
    2056       49335 :     if (ref_realm) {
    2057           0 :         PA_DATA pa;
    2058           0 :         krb5_crypto crypto;
    2059             : 
    2060        1152 :         kdc_log(context, config, 3,
    2061             :                 "Adding server referral to %s", ref_realm);
    2062             : 
    2063        1152 :         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
    2064        1152 :         if (ret)
    2065           0 :             goto out;
    2066             : 
    2067        1152 :         ret = build_server_referral(context, config, crypto, ref_realm,
    2068             :                                     NULL, s, &pa.padata_value);
    2069        1152 :         krb5_crypto_destroy(context, crypto);
    2070        1152 :         if (ret) {
    2071           0 :             kdc_audit_addreason((kdc_request_t)priv, "Referral build failed");
    2072           0 :             kdc_log(context, config, 4,
    2073             :                     "Failed building server referral");
    2074           0 :             goto out;
    2075             :         }
    2076        1152 :         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
    2077             : 
    2078        1152 :         ret = add_METHOD_DATA(priv->rep.padata, &pa);
    2079        1152 :         krb5_data_free(&pa.padata_value);
    2080        1152 :         if (ret) {
    2081           0 :             kdc_log(context, config, 4,
    2082             :                     "Add server referral METHOD-DATA failed");
    2083           0 :             goto out;
    2084             :         }
    2085             :     }
    2086             : 
    2087             :     /*
    2088             :      * Only add ticket signature if the requested server is not krbtgt, and
    2089             :      * either the header server is krbtgt or, in the case of renewal/validation
    2090             :      * if it was signed with PAC ticket signature and we verified it.
    2091             :      * Currently Heimdal only allows renewal of krbtgt anyway but that might
    2092             :      * change one day (see issue #763) so make sure to check for it.
    2093             :      */
    2094             : 
    2095       98670 :     if (kdc_issued &&
    2096       49335 :         !krb5_principal_is_krbtgt(context, priv->server->principal)) {
    2097             : 
    2098       21220 :         add_ticket_sig = TRUE;
    2099             :     }
    2100             : 
    2101             :     /*
    2102             :      * Active-Directory implementations use the high part of the kvno as the
    2103             :      * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
    2104             :      */
    2105             : 
    2106       49335 :     rodc_id = krbtgt_out->kvno >> 16;
    2107             : 
    2108             :     /*
    2109             :      *
    2110             :      */
    2111             : 
    2112       49335 :     ret = tgs_make_reply(priv,
    2113             :                          tgt,
    2114             :                          ekey,
    2115       49335 :                          &tkey_sign->key,
    2116             :                          &sessionkey,
    2117             :                          kvno,
    2118             :                          auth_data,
    2119             :                          tgt_realm,
    2120             :                          rodc_id,
    2121             :                          add_ticket_sig);
    2122             : 
    2123       51192 : out:
    2124       51192 :     free(user2user_name);
    2125       51192 :     free(krbtgt_out_n);
    2126       51192 :     _krb5_free_capath(context, capath);
    2127             : 
    2128       51192 :     krb5_free_keyblock_contents(context, &sessionkey);
    2129       51192 :     if(krbtgt_out)
    2130       49900 :         _kdc_free_ent(context, krbtgt_outdb, krbtgt_out);
    2131       51192 :     if(user2user_krbtgt)
    2132          38 :         _kdc_free_ent(context, user2user_krbtgtdb, user2user_krbtgt);
    2133             : 
    2134       51192 :     krb5_free_principal(context, user2user_princ);
    2135       51192 :     krb5_free_principal(context, krbtgt_out_principal);
    2136       51192 :     free(ref_realm);
    2137             : 
    2138       51192 :     if (auth_data) {
    2139           5 :        free_AuthorizationData(auth_data);
    2140           5 :        free(auth_data);
    2141             :     }
    2142             : 
    2143       51192 :     free_EncTicketPart(&adtkt);
    2144             : 
    2145       51192 :     krb5_pac_free(context, user2user_pac);
    2146             : 
    2147       51192 :     return ret;
    2148             : }
    2149             : 
    2150             : /*
    2151             :  *
    2152             :  */
    2153             : 
    2154             : krb5_error_code
    2155       52565 : _kdc_tgs_rep(astgs_request_t r)
    2156             : {
    2157       52565 :     krb5_kdc_configuration *config = r->config;
    2158       52565 :     KDC_REQ *req = &r->req;
    2159       52565 :     krb5_data *data = r->reply;
    2160       52565 :     const char *from = r->from;
    2161       52565 :     struct sockaddr *from_addr = r->addr;
    2162       52565 :     int datagram_reply = r->datagram_reply;
    2163        1672 :     krb5_error_code ret;
    2164       52565 :     int i = 0;
    2165        1672 :     const PA_DATA *tgs_req, *pa;
    2166       52565 :     krb5_enctype krbtgt_etype = ETYPE_NULL;
    2167             : 
    2168       52565 :     time_t *csec = NULL;
    2169       52565 :     int *cusec = NULL;
    2170             : 
    2171       52565 :     r->e_text = NULL;
    2172             : 
    2173       52565 :     if(req->padata == NULL){
    2174           0 :         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
    2175           0 :         kdc_log(r->context, config, 4,
    2176             :                 "TGS-REQ from %s without PA-DATA", from);
    2177           0 :         goto out;
    2178             :     }
    2179             : 
    2180       52565 :     i = 0;
    2181       52565 :     pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR);
    2182       52565 :     if (pa) {
    2183           0 :         kdc_log(r->context, r->config, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
    2184           0 :         ret = KRB5KRB_ERR_GENERIC;
    2185           0 :         goto out;
    2186             :     }
    2187             : 
    2188       52565 :     i = 0;
    2189       52565 :     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
    2190       52565 :     if(tgs_req == NULL){
    2191           0 :         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
    2192             : 
    2193           0 :         kdc_log(r->context, config, 4,
    2194             :                 "TGS-REQ from %s without PA-TGS-REQ", from);
    2195           0 :         goto out;
    2196             :     }
    2197       52565 :     ret = tgs_parse_request(r, tgs_req,
    2198             :                             &krbtgt_etype,
    2199             :                             from, from_addr,
    2200             :                             &csec, &cusec);
    2201       52565 :     if (ret == HDB_ERR_NOT_FOUND_HERE) {
    2202             :         /* kdc_log() is called in tgs_parse_request() */
    2203        1351 :         goto out;
    2204             :     }
    2205       51214 :     if (ret) {
    2206          22 :         kdc_log(r->context, config, 4,
    2207             :                 "Failed parsing TGS-REQ from %s", from);
    2208          22 :         goto out;
    2209             :     }
    2210             : 
    2211       51192 :     ret = _kdc_fast_strengthen_reply_key(r);
    2212       51192 :     if (ret)
    2213           0 :         goto out;
    2214             : 
    2215       51192 :     ALLOC(r->rep.padata);
    2216       51192 :     if (r->rep.padata == NULL) {
    2217           0 :         ret = ENOMEM;
    2218           0 :         krb5_set_error_message(r->context, ret, N_("malloc: out of memory", ""));
    2219           0 :         goto out;
    2220             :     }
    2221             : 
    2222       51192 :     ret = tgs_build_reply(r,
    2223             :                           krbtgt_etype,
    2224             :                           from_addr);
    2225       51192 :     if (ret) {
    2226        1859 :         kdc_log(r->context, config, 4,
    2227             :                 "Failed building TGS-REP to %s", from);
    2228        1859 :         goto out;
    2229             :     }
    2230             : 
    2231             :     /* */
    2232       49333 :     if (datagram_reply && data->length > config->max_datagram_reply_length) {
    2233           0 :         krb5_data_free(data);
    2234           0 :         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
    2235           0 :         _kdc_set_const_e_text(r, "Reply packet too large");
    2236             :     }
    2237             : 
    2238       49333 : out:
    2239       52565 :     if (ret) {
    2240             :         /* Overwrite ‘error_code’ only if we have an actual error. */
    2241        3232 :         r->error_code = ret;
    2242             :     }
    2243             :     {
    2244       52565 :         krb5_error_code ret2 = _kdc_audit_request(r);
    2245       52565 :         if (ret2) {
    2246           0 :             krb5_data_free(data);
    2247           0 :             ret = ret2;
    2248             :         }
    2249             :     }
    2250             : 
    2251       52565 :     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
    2252        1839 :         METHOD_DATA error_method = { 0, NULL };
    2253             : 
    2254        1839 :         kdc_log(r->context, config, 5, "tgs-req: sending error: %d to client", ret);
    2255        5517 :         ret = _kdc_fast_mk_error(r,
    2256             :                                  &error_method,
    2257             :                                  r->armor_crypto,
    2258        1839 :                                  &req->req_body,
    2259        1839 :                                  r->error_code ? r->error_code : ret,
    2260        1839 :                                  r->client_princ ? r->client_princ :(r->ticket != NULL ? r->ticket->client : NULL),
    2261        1839 :                                  r->server_princ ? r->server_princ :(r->ticket != NULL ? r->ticket->server : NULL),
    2262             :                                  csec, cusec,
    2263             :                                  data);
    2264        1839 :         free_METHOD_DATA(&error_method);
    2265             :     }
    2266       52565 :     free(csec);
    2267       52565 :     free(cusec);
    2268             : 
    2269       52565 :     free_TGS_REP(&r->rep);
    2270       52565 :     free_TransitedEncoding(&r->et.transited);
    2271       52565 :     free(r->et.starttime);
    2272       52565 :     free(r->et.renew_till);
    2273       52565 :     if(r->et.authorization_data) {
    2274       49322 :         free_AuthorizationData(r->et.authorization_data);
    2275       49322 :         free(r->et.authorization_data);
    2276             :     }
    2277       52565 :     free_LastReq(&r->ek.last_req);
    2278       52565 :     if (r->et.key.keyvalue.data) {
    2279       49333 :         memset_s(r->et.key.keyvalue.data, 0, r->et.key.keyvalue.length,
    2280             :                  r->et.key.keyvalue.length);
    2281             :     }
    2282       52565 :     free_EncryptionKey(&r->et.key);
    2283             : 
    2284       52565 :     if (r->canon_client_princ) {
    2285       49518 :         krb5_free_principal(r->context, r->canon_client_princ);
    2286       49518 :         r->canon_client_princ = NULL;
    2287             :     }
    2288       52565 :     if (r->armor_crypto) {
    2289       44392 :         krb5_crypto_destroy(r->context, r->armor_crypto);
    2290       44392 :         r->armor_crypto = NULL;
    2291             :     }
    2292       52565 :     if (r->armor_ticket)
    2293         324 :         krb5_free_ticket(r->context, r->armor_ticket);
    2294       52565 :     if (r->armor_server)
    2295         326 :         _kdc_free_ent(r->context, r->armor_serverdb, r->armor_server);
    2296       52565 :     if (r->armor_client)
    2297         312 :         _kdc_free_ent(r->context,
    2298             :                       r->armor_clientdb,
    2299             :                       r->armor_client);
    2300       52565 :     if (r->armor_pac)
    2301         312 :         krb5_pac_free(r->context, r->armor_pac);
    2302       52565 :     krb5_free_keyblock_contents(r->context, &r->reply_key);
    2303       52565 :     krb5_free_keyblock_contents(r->context, &r->enc_ad_key);
    2304       52565 :     krb5_free_keyblock_contents(r->context, &r->strengthen_key);
    2305             : 
    2306       52565 :     if (r->ticket)
    2307       51199 :         krb5_free_ticket(r->context, r->ticket);
    2308       52565 :     if (r->krbtgt)
    2309       51206 :         _kdc_free_ent(r->context, r->krbtgtdb, r->krbtgt);
    2310             : 
    2311       52565 :     if (r->client)
    2312       49569 :         _kdc_free_ent(r->context, r->clientdb, r->client);
    2313       52565 :     krb5_free_principal(r->context, r->client_princ);
    2314       52565 :     if (r->server)
    2315       49900 :         _kdc_free_ent(r->context, r->serverdb, r->server);
    2316       52565 :     krb5_free_principal(r->context, r->server_princ);
    2317       52565 :     _kdc_free_fast_state(&r->fast);
    2318       52565 :     krb5_pac_free(r->context, r->pac);
    2319             : 
    2320       52565 :     return ret;
    2321             : }

Generated by: LCOV version 1.14