LCOV - code coverage report
Current view: top level - third_party/heimdal/kdc - krb5tgs.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 631 1180 53.5 %
Date: 2024-06-13 04:01:37 Functions: 16 17 94.1 %

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

Generated by: LCOV version 1.13