LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - ticket.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 262 455 57.6 %
Date: 2024-04-21 15:09:00 Functions: 10 15 66.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include "krb5_locl.h"
      37             : 
      38             : /**
      39             :  * Free ticket and content
      40             :  *
      41             :  * @param context a Kerberos 5 context
      42             :  * @param ticket ticket to free
      43             :  *
      44             :  * @return Returns 0 to indicate success.  Otherwise an kerberos et
      45             :  * error code is returned, see krb5_get_error_message().
      46             :  *
      47             :  * @ingroup krb5
      48             :  */
      49             : 
      50             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
      51      158857 : krb5_free_ticket(krb5_context context,
      52             :                  krb5_ticket *ticket)
      53             : {
      54      158857 :     free_EncTicketPart(&ticket->ticket);
      55      158857 :     krb5_free_principal(context, ticket->client);
      56      158857 :     krb5_free_principal(context, ticket->server);
      57      158857 :     free(ticket);
      58      158857 :     return 0;
      59             : }
      60             : 
      61             : /**
      62             :  * Copy ticket and content
      63             :  *
      64             :  * @param context a Kerberos 5 context
      65             :  * @param from ticket to copy
      66             :  * @param to new copy of ticket, free with krb5_free_ticket()
      67             :  *
      68             :  * @return Returns 0 to indicate success.  Otherwise an kerberos et
      69             :  * error code is returned, see krb5_get_error_message().
      70             :  *
      71             :  * @ingroup krb5
      72             :  */
      73             : 
      74             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
      75       53442 : krb5_copy_ticket(krb5_context context,
      76             :                  const krb5_ticket *from,
      77             :                  krb5_ticket **to)
      78             : {
      79         881 :     krb5_error_code ret;
      80         881 :     krb5_ticket *tmp;
      81             : 
      82       53442 :     *to = NULL;
      83       53442 :     tmp = malloc(sizeof(*tmp));
      84       53442 :     if (tmp == NULL)
      85           0 :         return krb5_enomem(context);
      86       53442 :     if((ret = copy_EncTicketPart(&from->ticket, &tmp->ticket))){
      87           0 :         free(tmp);
      88           0 :         return ret;
      89             :     }
      90       53442 :     ret = krb5_copy_principal(context, from->client, &tmp->client);
      91       53442 :     if(ret){
      92           0 :         free_EncTicketPart(&tmp->ticket);
      93           0 :         free(tmp);
      94           0 :         return ret;
      95             :     }
      96       53442 :     ret = krb5_copy_principal(context, from->server, &tmp->server);
      97       53442 :     if(ret){
      98           0 :         krb5_free_principal(context, tmp->client);
      99           0 :         free_EncTicketPart(&tmp->ticket);
     100           0 :         free(tmp);
     101           0 :         return ret;
     102             :     }
     103       53442 :     *to = tmp;
     104       53442 :     return 0;
     105             : }
     106             : 
     107             : /**
     108             :  * Return client principal in ticket
     109             :  *
     110             :  * @param context a Kerberos 5 context
     111             :  * @param ticket ticket to copy
     112             :  * @param client client principal, free with krb5_free_principal()
     113             :  *
     114             :  * @return Returns 0 to indicate success.  Otherwise an kerberos et
     115             :  * error code is returned, see krb5_get_error_message().
     116             :  *
     117             :  * @ingroup krb5
     118             :  */
     119             : 
     120             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     121        1212 : krb5_ticket_get_client(krb5_context context,
     122             :                        const krb5_ticket *ticket,
     123             :                        krb5_principal *client)
     124             : {
     125        1212 :     return krb5_copy_principal(context, ticket->client, client);
     126             : }
     127             : 
     128             : /**
     129             :  * Return server principal in ticket
     130             :  *
     131             :  * @param context a Kerberos 5 context
     132             :  * @param ticket ticket to copy
     133             :  * @param server server principal, free with krb5_free_principal()
     134             :  *
     135             :  * @return Returns 0 to indicate success.  Otherwise an kerberos et
     136             :  * error code is returned, see krb5_get_error_message().
     137             :  *
     138             :  * @ingroup krb5
     139             :  */
     140             : 
     141             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     142           0 : krb5_ticket_get_server(krb5_context context,
     143             :                        const krb5_ticket *ticket,
     144             :                        krb5_principal *server)
     145             : {
     146           0 :     return krb5_copy_principal(context, ticket->server, server);
     147             : }
     148             : 
     149             : /**
     150             :  * Return end time of a ticket
     151             :  *
     152             :  * @param context a Kerberos 5 context
     153             :  * @param ticket ticket to copy
     154             :  *
     155             :  * @return end time of ticket
     156             :  *
     157             :  * @ingroup krb5
     158             :  */
     159             : 
     160             : KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL
     161           0 : krb5_ticket_get_endtime(krb5_context context,
     162             :                         const krb5_ticket *ticket)
     163             : {
     164           0 :     return ticket->ticket.endtime;
     165             : }
     166             : 
     167             : /**
     168             :  * Return authentication, start, end, and renew limit times of a ticket
     169             :  *
     170             :  * @param context a Kerberos 5 context
     171             :  * @param ticket ticket to copy
     172             :  * @param t pointer to krb5_times structure
     173             :  *
     174             :  * @ingroup krb5
     175             :  */
     176             : 
     177             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     178           0 : krb5_ticket_get_times(krb5_context context,
     179             :                       const krb5_ticket *ticket,
     180             :                       krb5_times *t)
     181             : {
     182           0 :     t->authtime   = ticket->ticket.authtime;
     183           0 :     t->starttime  = ticket->ticket.starttime  ? *ticket->ticket.starttime  :
     184             :                                                 t->authtime;
     185           0 :     t->endtime    = ticket->ticket.endtime;
     186           0 :     t->renew_till = ticket->ticket.renew_till ? *ticket->ticket.renew_till :
     187             :                                                 t->endtime;
     188           0 : }
     189             : 
     190             : /**
     191             :  * Get the flags from the Kerberos ticket
     192             :  *
     193             :  * @param context Kerberos context
     194             :  * @param ticket Kerberos ticket
     195             :  *
     196             :  * @return ticket flags
     197             :  *
     198             :  * @ingroup krb5_ticket
     199             :  */
     200             : KRB5_LIB_FUNCTION unsigned long KRB5_LIB_CALL
     201           0 : krb5_ticket_get_flags(krb5_context context,
     202             :                       const krb5_ticket *ticket)
     203             : {
     204           0 :     return TicketFlags2int(ticket->ticket.flags);
     205             : }
     206             : 
     207             : /*
     208             :  * Find an authz-data element in the given `ad'.  If `failp', then validate any
     209             :  * containing AD-KDC-ISSUED's keyed checksum with the `sessionkey' (if given).
     210             :  *
     211             :  * All AD-KDC-ISSUED will be validated (if requested) even when `type' is
     212             :  * `KRB5_AUTHDATA_KDC_ISSUED'.
     213             :  *
     214             :  * Only the first matching element will be output (via `data').
     215             :  *
     216             :  * Note that all AD-KDC-ISSUEDs found while traversing the authz-data will be
     217             :  * validated, though only the first one will be returned.
     218             :  *
     219             :  * XXX We really need a better interface though.  First, forget AD-AND-OR --
     220             :  * just remove it.  Second, probably forget AD-KDC-ISSUED, but still, between
     221             :  * that, the PAC, and the CAMMAC, we need an interface that can:
     222             :  *
     223             :  * a) take the derived keys instead of the service key or the session key,
     224             :  * b) can indicate whether the element was marked critical,
     225             :  * c) can indicate whether the element was authenticated to the KDC,
     226             :  * d) can iterate over all the instances found (if more than one is found).
     227             :  *
     228             :  * Also, we need to know here if the authz-data is from a Ticket or from an
     229             :  * Authenticator -- if the latter then we must refuse to find AD-KDC-ISSUED /
     230             :  * PAC / CAMMAC or anything of the sort, ever.
     231             :  */
     232             : static int
     233     1055704 : find_type_in_ad(krb5_context context,
     234             :                 int type,
     235             :                 krb5_data *data,                /* optional */
     236             :                 krb5_boolean *found,
     237             :                 krb5_boolean failp,             /* validate AD-KDC-ISSUED */
     238             :                 krb5_keyblock *sessionkey,      /* ticket session key */
     239             :                 const AuthorizationData *ad,
     240             :                 int level)
     241             : {
     242     1055704 :     krb5_error_code ret = 0;
     243       27048 :     size_t i;
     244             : 
     245     1055704 :     if (level > 9) {
     246           0 :         ret = ENOENT; /* XXX */
     247           0 :         krb5_set_error_message(context, ret,
     248           0 :                                N_("Authorization data nested deeper "
     249             :                                   "then %d levels, stop searching", ""),
     250             :                                level);
     251           0 :         goto out;
     252             :     }
     253             : 
     254             :     /*
     255             :      * Only copy out the element the first time we get to it, we need
     256             :      * to run over the whole authorization data fields to check if
     257             :      * there are any container clases we need to care about.
     258             :      */
     259     2019872 :     for (i = 0; i < ad->len; i++) {
     260     1055884 :         if (!*found && ad->val[i].ad_type == type) {
     261      202897 :             if (data) {
     262      202897 :                 ret = der_copy_octet_string(&ad->val[i].ad_data, data);
     263      202897 :                 if (ret) {
     264           0 :                     krb5_set_error_message(context, ret,
     265           0 :                                            N_("malloc: out of memory", ""));
     266           0 :                     goto out;
     267             :                 }
     268             :             }
     269      202897 :             *found = TRUE;
     270      207198 :             if (type != KRB5_AUTHDATA_KDC_ISSUED ||
     271        4301 :                 !failp || !sessionkey || !sessionkey->keyvalue.length)
     272      202897 :                 continue;
     273             :             /* else go on to validate the AD-KDC-ISSUED's keyed checksum */
     274             :         }
     275      852987 :         switch (ad->val[i].ad_type) {
     276      460096 :         case KRB5_AUTHDATA_IF_RELEVANT: {
     277       11037 :             AuthorizationData child;
     278      460096 :             ret = decode_AuthorizationData(ad->val[i].ad_data.data,
     279      449059 :                                            ad->val[i].ad_data.length,
     280             :                                            &child,
     281             :                                            NULL);
     282      460096 :             if (ret) {
     283           0 :                 krb5_set_error_message(context, ret,
     284           0 :                                        N_("Failed to decode "
     285             :                                           "IF_RELEVANT with %d", ""),
     286             :                                        (int)ret);
     287           0 :                 goto out;
     288             :             }
     289      460096 :             ret = find_type_in_ad(context, type, data, found, FALSE,
     290             :                                   sessionkey, &child, level + 1);
     291      460096 :             free_AuthorizationData(&child);
     292      460096 :             if (ret)
     293           0 :                 goto out;
     294      460096 :             break;
     295             :         }
     296           0 :         case KRB5_AUTHDATA_KDC_ISSUED: {
     297           0 :             AD_KDCIssued child;
     298             : 
     299           0 :             ret = decode_AD_KDCIssued(ad->val[i].ad_data.data,
     300           0 :                                       ad->val[i].ad_data.length,
     301             :                                       &child,
     302             :                                       NULL);
     303           0 :             if (ret) {
     304           0 :                 krb5_set_error_message(context, ret,
     305           0 :                                        N_("Failed to decode "
     306             :                                           "AD_KDCIssued with %d", ""),
     307             :                                        ret);
     308           0 :                 goto out;
     309             :             }
     310           0 :             if (failp && sessionkey && sessionkey->keyvalue.length) {
     311           0 :                 krb5_boolean valid;
     312           0 :                 krb5_data buf;
     313           0 :                 size_t len;
     314             : 
     315           0 :                 ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length,
     316             :                                    &child.elements, &len, ret);
     317           0 :                 if (ret) {
     318           0 :                     free_AD_KDCIssued(&child);
     319           0 :                     krb5_clear_error_message(context);
     320           0 :                     goto out;
     321             :                 }
     322           0 :                 if(buf.length != len)
     323           0 :                     krb5_abortx(context, "internal error in ASN.1 encoder");
     324             : 
     325           0 :                 ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf,
     326             :                                              &child.ad_checksum, &valid);
     327           0 :                 krb5_data_free(&buf);
     328           0 :                 if (ret) {
     329           0 :                     free_AD_KDCIssued(&child);
     330           0 :                     goto out;
     331             :                 }
     332           0 :                 if (!valid) {
     333           0 :                     krb5_clear_error_message(context);
     334           0 :                     ret = ENOENT;
     335           0 :                     free_AD_KDCIssued(&child);
     336           0 :                     goto out;
     337             :                 }
     338           0 :             } else if (failp) {
     339           0 :                     krb5_clear_error_message(context);
     340           0 :                     ret = ENOENT;
     341           0 :                     free_AD_KDCIssued(&child);
     342           0 :                     goto out;
     343             :             }
     344           0 :             ret = find_type_in_ad(context, type, data, found, failp, sessionkey,
     345             :                                   &child.elements, level + 1);
     346           0 :             free_AD_KDCIssued(&child);
     347           0 :             if (ret)
     348           0 :                 goto out;
     349           0 :             break;
     350             :         }
     351           0 :         case KRB5_AUTHDATA_AND_OR:
     352           0 :             if (!failp)
     353           0 :                 break;
     354           0 :             ret = ENOENT; /* XXX */
     355           0 :             krb5_set_error_message(context, ret,
     356           0 :                                    N_("Authorization data contains "
     357             :                                       "AND-OR element that is unknown to the "
     358             :                                       "application", ""));
     359           0 :             goto out;
     360      392891 :         default:
     361      392891 :             if (!failp)
     362      292781 :                 break;
     363       91716 :             ret = ENOENT; /* XXX */
     364       91716 :             krb5_set_error_message(context, ret,
     365       91716 :                                    N_("Authorization data contains "
     366             :                                       "unknown type (%d) ", ""),
     367       88400 :                                    ad->val[i].ad_type);
     368       91716 :             goto out;
     369             :         }
     370             :     }
     371      963988 : out:
     372     1055704 :     if (ret) {
     373       91716 :         if (*found) {
     374           0 :             if (data)
     375           0 :                 krb5_data_free(data);
     376           0 :             *found = 0;
     377             :         }
     378             :     }
     379     1055704 :     return ret;
     380             : }
     381             : 
     382             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     383      347019 : _krb5_get_ad(krb5_context context,
     384             :              const AuthorizationData *ad,
     385             :              krb5_keyblock *sessionkey,
     386             :              int type,
     387             :              krb5_data *data)
     388             : {
     389      347019 :     krb5_boolean found = FALSE;
     390       10052 :     krb5_error_code ret;
     391             : 
     392      347019 :     if (data)
     393      347019 :         krb5_data_zero(data);
     394             : 
     395      347019 :     if (ad == NULL) {
     396       12353 :         krb5_set_error_message(context, ENOENT,
     397       12353 :                                N_("No authorization data", ""));
     398       12353 :         return ENOENT; /* XXX */
     399             :     }
     400             : 
     401      334666 :     ret = find_type_in_ad(context, type, data, &found, TRUE, sessionkey, ad, 0);
     402      334666 :     if (ret)
     403       88398 :         return ret;
     404      242952 :     if (!found) {
     405      146841 :         krb5_set_error_message(context, ENOENT,
     406      146841 :                                N_("Have no authorization data of type %d", ""),
     407             :                                type);
     408      146841 :         return ENOENT; /* XXX */
     409             :     }
     410       93572 :     return 0;
     411             : }
     412             : 
     413             : 
     414             : /**
     415             :  * Extract the authorization data type of type from the ticket. Store
     416             :  * the field in data. This function is to use for kerberos
     417             :  * applications.
     418             :  *
     419             :  * @param context a Kerberos 5 context
     420             :  * @param ticket Kerberos ticket
     421             :  * @param type type to fetch
     422             :  * @param data returned data, free with krb5_data_free()
     423             :  *
     424             :  * @ingroup krb5
     425             :  */
     426             : 
     427             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     428      261000 : krb5_ticket_get_authorization_data_type(krb5_context context,
     429             :                                         krb5_ticket *ticket,
     430             :                                         int type,
     431             :                                         krb5_data *data)
     432             : {
     433        5959 :     AuthorizationData *ad;
     434        5959 :     krb5_error_code ret;
     435      261000 :     krb5_boolean found = FALSE;
     436             : 
     437      261000 :     if (data)
     438      207558 :         krb5_data_zero(data);
     439             : 
     440      261000 :     ad = ticket->ticket.authorization_data;
     441      261000 :     if (ticket->ticket.authorization_data == NULL) {
     442          58 :         krb5_set_error_message(context, ENOENT,
     443          58 :                                N_("Ticket has no authorization data", ""));
     444          58 :         return ENOENT; /* XXX */
     445             :     }
     446             : 
     447      266901 :     ret = find_type_in_ad(context, type, data, &found, TRUE,
     448      260942 :                           &ticket->ticket.key, ad, 0);
     449      260942 :     if (ret)
     450           2 :         return ret;
     451      260940 :     if (!found) {
     452      154154 :         krb5_set_error_message(context, ENOENT,
     453      154154 :                                N_("Ticket has no "
     454             :                                   "authorization data of type %d", ""),
     455             :                                type);
     456      154154 :         return ENOENT; /* XXX */
     457             :     }
     458      105024 :     return 0;
     459             : }
     460             : 
     461             : static krb5_error_code
     462       46949 : check_server_referral(krb5_context context,
     463             :                       krb5_kdc_rep *rep,
     464             :                       unsigned flags,
     465             :                       krb5_const_principal requested,
     466             :                       krb5_const_principal returned,
     467             :                       krb5_keyblock * key)
     468             : {
     469        1658 :     krb5_error_code ret;
     470        1658 :     PA_ServerReferralData ref;
     471        1658 :     krb5_crypto session;
     472        1658 :     EncryptedData ed;
     473        1658 :     size_t len;
     474        1658 :     krb5_data data;
     475        1658 :     PA_DATA *pa;
     476       46949 :     int i = 0, cmp;
     477             : 
     478       46949 :     if (rep->kdc_rep.padata == NULL)
     479        3766 :         goto noreferral;
     480             : 
     481       43183 :     pa = krb5_find_padata(rep->kdc_rep.padata->val,
     482       41525 :                           rep->kdc_rep.padata->len,
     483             :                           KRB5_PADATA_SERVER_REFERRAL, &i);
     484       43183 :     if (pa == NULL)
     485       42031 :         goto noreferral;
     486             : 
     487        1152 :     memset(&ed, 0, sizeof(ed));
     488        1152 :     memset(&ref, 0, sizeof(ref));
     489             : 
     490        1152 :     ret = decode_EncryptedData(pa->padata_value.data,
     491             :                                pa->padata_value.length,
     492             :                                &ed, &len);
     493        1152 :     if (ret)
     494           0 :         return ret;
     495        1152 :     if (len != pa->padata_value.length) {
     496           0 :         free_EncryptedData(&ed);
     497           0 :         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     498           0 :                                N_("Referral EncryptedData wrong for realm %s",
     499           0 :                                   "realm"), requested->realm);
     500           0 :         return KRB5KRB_AP_ERR_MODIFIED;
     501             :     }
     502             : 
     503        1152 :     ret = krb5_crypto_init(context, key, 0, &session);
     504        1152 :     if (ret) {
     505           0 :         free_EncryptedData(&ed);
     506           0 :         return ret;
     507             :     }
     508             : 
     509        1152 :     ret = krb5_decrypt_EncryptedData(context, session,
     510             :                                      KRB5_KU_PA_SERVER_REFERRAL,
     511             :                                      &ed, &data);
     512        1152 :     free_EncryptedData(&ed);
     513        1152 :     krb5_crypto_destroy(context, session);
     514        1152 :     if (ret)
     515           0 :         return ret;
     516             : 
     517        1152 :     ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
     518        1152 :     if (ret) {
     519           0 :         krb5_data_free(&data);
     520           0 :         return ret;
     521             :     }
     522        1152 :     krb5_data_free(&data);
     523             : 
     524        1152 :     if (strcmp(requested->realm, returned->realm) != 0) {
     525           0 :         free_PA_ServerReferralData(&ref);
     526           0 :         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     527           0 :                                N_("server ref realm mismatch, "
     528             :                                   "requested realm %s got back %s", ""),
     529           0 :                                requested->realm, returned->realm);
     530           0 :         return KRB5KRB_AP_ERR_MODIFIED;
     531             :     }
     532             : 
     533        1152 :     if (krb5_principal_is_krbtgt(context, returned)) {
     534        1152 :         const char *realm = returned->name.name_string.val[1];
     535             : 
     536        1152 :         if (ref.referred_realm == NULL
     537        1152 :             || strcmp(*ref.referred_realm, realm) != 0)
     538             :         {
     539           0 :             free_PA_ServerReferralData(&ref);
     540           0 :             krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     541           0 :                                    N_("tgt returned with wrong ref", ""));
     542           0 :             return KRB5KRB_AP_ERR_MODIFIED;
     543             :         }
     544           0 :     } else if (krb5_principal_compare(context, returned, requested) == 0) {
     545           0 :         free_PA_ServerReferralData(&ref);
     546           0 :         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     547           0 :                                N_("req princ no same as returned", ""));
     548           0 :         return KRB5KRB_AP_ERR_MODIFIED;
     549             :     }
     550             : 
     551        1152 :     if (ref.requested_principal_name) {
     552        1152 :         cmp = _krb5_principal_compare_PrincipalName(context,
     553             :                                                     requested,
     554             :                                                     ref.requested_principal_name);
     555        1152 :         if (!cmp) {
     556           0 :             free_PA_ServerReferralData(&ref);
     557           0 :             krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     558           0 :                                    N_("referred principal not same "
     559             :                                       "as requested", ""));
     560           0 :             return KRB5KRB_AP_ERR_MODIFIED;
     561             :         }
     562           0 :     } else if (flags & EXTRACT_TICKET_AS_REQ) {
     563           0 :         free_PA_ServerReferralData(&ref);
     564           0 :         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     565           0 :                                N_("Requested principal missing on AS-REQ", ""));
     566           0 :         return KRB5KRB_AP_ERR_MODIFIED;
     567             :     }
     568             : 
     569        1152 :     free_PA_ServerReferralData(&ref);
     570             : 
     571        1152 :     return ret;
     572       45797 : noreferral:
     573             :     /*
     574             :      * Expect excact match or that we got a krbtgt
     575             :      */
     576       48677 :     if (krb5_principal_compare(context, requested, returned) != TRUE &&
     577        2880 :         (krb5_realm_compare(context, requested, returned) != TRUE &&
     578           0 :          krb5_principal_is_krbtgt(context, returned) != TRUE))
     579             :     {
     580           0 :         krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     581           0 :                                N_("Not same server principal returned "
     582             :                                   "as requested", ""));
     583           0 :         return KRB5KRB_AP_ERR_MODIFIED;
     584             :     }
     585       44139 :     return 0;
     586             : }
     587             : 
     588             : /*
     589             :  * Verify KDC supported anonymous if requested
     590             :  */
     591             : static krb5_error_code
     592           0 : check_client_anonymous(krb5_context context,
     593             :                        krb5_kdc_rep *rep,
     594             :                        krb5_const_principal requested,
     595             :                        krb5_const_principal mapped,
     596             :                        krb5_boolean is_tgs_rep)
     597             : {
     598           0 :     int flags;
     599             : 
     600           0 :     if (!rep->enc_part.flags.anonymous)
     601           0 :         return KRB5KDC_ERR_BADOPTION;
     602             : 
     603             :     /*
     604             :      * Here we must validate that the AS returned a ticket of the expected type
     605             :      * for either a fully anonymous request, or authenticated request for an
     606             :      * anonymous ticket.  If this is a TGS request, we're done.  Then if the
     607             :      * 'requested' principal was anonymous, we'll check the 'mapped' principal
     608             :      * accordingly (without enforcing the name type and perhaps the realm).
     609             :      * Finally, if the 'requested' principal was not anonymous, well check
     610             :      * that the 'mapped' principal has an anonymous name and type, in a
     611             :      * non-anonymous realm.  (Should we also be checking for a realm match
     612             :      * between the request and the mapped name in this case?)
     613             :      */
     614           0 :     if (is_tgs_rep)
     615           0 :         flags = KRB5_ANON_MATCH_ANY_NONT;
     616           0 :     else if (krb5_principal_is_anonymous(context, requested,
     617             :                                          KRB5_ANON_MATCH_ANY_NONT))
     618           0 :         flags = KRB5_ANON_MATCH_UNAUTHENTICATED | KRB5_ANON_IGNORE_NAME_TYPE;
     619             :     else
     620           0 :         flags = KRB5_ANON_MATCH_AUTHENTICATED;
     621             : 
     622           0 :     if (!krb5_principal_is_anonymous(context, mapped, flags))
     623           0 :         return KRB5KRB_AP_ERR_MODIFIED;
     624             : 
     625           0 :     return 0;
     626             : }
     627             : 
     628             : /*
     629             :  * Verify returned client principal name in anonymous/referral case
     630             :  */
     631             : 
     632             : static krb5_error_code
     633       46549 : check_client_mismatch(krb5_context context,
     634             :                       krb5_kdc_rep *rep,
     635             :                       krb5_const_principal requested,
     636             :                       krb5_const_principal mapped,
     637             :                       krb5_keyblock const * key)
     638             : {
     639       46549 :     if (rep->enc_part.flags.anonymous) {
     640           0 :         if (!krb5_principal_is_anonymous(context, mapped,
     641             :                                          KRB5_ANON_MATCH_ANY_NONT)) {
     642           0 :             krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     643           0 :                                    N_("Anonymous ticket does not contain anonymous "
     644             :                                       "principal", ""));
     645           0 :             return KRB5KRB_AP_ERR_MODIFIED;
     646             :         }
     647             :     } else {
     648       46549 :         if (krb5_principal_compare(context, requested, mapped) == FALSE &&
     649         384 :             !rep->enc_part.flags.enc_pa_rep) {
     650           0 :             krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
     651           0 :                                    N_("Not same client principal returned "
     652             :                                    "as requested", ""));
     653           0 :             return KRB5KRB_AP_ERR_MODIFIED;
     654             :         }
     655             :     }
     656             : 
     657       44891 :     return 0;
     658             : }
     659             : 
     660             : 
     661             : static krb5_error_code KRB5_CALLCONV
     662       14095 : decrypt_tkt (krb5_context context,
     663             :              krb5_keyblock *key,
     664             :              krb5_key_usage usage,
     665             :              krb5_const_pointer decrypt_arg,
     666             :              krb5_kdc_rep *dec_rep)
     667             : {
     668         585 :     krb5_error_code ret;
     669         585 :     krb5_data data;
     670         585 :     size_t size;
     671         585 :     krb5_crypto crypto;
     672             : 
     673       14095 :     ret = krb5_crypto_init(context, key, 0, &crypto);
     674       14095 :     if (ret)
     675           0 :         return ret;
     676             : 
     677       14680 :     ret = krb5_decrypt_EncryptedData (context,
     678             :                                       crypto,
     679             :                                       usage,
     680       14095 :                                       &dec_rep->kdc_rep.enc_part,
     681             :                                       &data);
     682       14095 :     krb5_crypto_destroy(context, crypto);
     683             : 
     684       14095 :     if (ret)
     685           0 :         return ret;
     686             : 
     687       14680 :     ret = decode_EncASRepPart(data.data,
     688             :                               data.length,
     689       14095 :                               &dec_rep->enc_part,
     690             :                               &size);
     691       14095 :     if (ret)
     692           0 :         ret = decode_EncTGSRepPart(data.data,
     693             :                                    data.length,
     694           0 :                                    &dec_rep->enc_part,
     695             :                                    &size);
     696       14095 :     krb5_data_free (&data);
     697       14095 :     if (ret) {
     698           0 :         krb5_set_error_message(context, ret,
     699           0 :                                N_("Failed to decode encpart in ticket", ""));
     700           0 :         return ret;
     701             :     }
     702       13510 :     return 0;
     703             : }
     704             : 
     705             : KRB5_LIB_FUNCTION int KRB5_LIB_CALL
     706       60269 : _krb5_extract_ticket(krb5_context context,
     707             :                      krb5_kdc_rep *rep,
     708             :                      krb5_creds *creds,
     709             :                      krb5_keyblock *key,
     710             :                      krb5_const_pointer keyseed,
     711             :                      krb5_key_usage key_usage,
     712             :                      krb5_addresses *addrs,
     713             :                      unsigned nonce,
     714             :                      unsigned flags,
     715             :                      krb5_data *request,
     716             :                      krb5_decrypt_proc decrypt_proc,
     717             :                      krb5_const_pointer decryptarg)
     718             : {
     719        2243 :     krb5_error_code ret;
     720        2243 :     krb5_principal tmp_principal;
     721       60269 :     size_t len = 0;
     722        2243 :     time_t tmp_time;
     723        2243 :     krb5_timestamp sec_now;
     724             : 
     725             :     /* decrypt */
     726             : 
     727       60269 :     if (decrypt_proc == NULL)
     728       14095 :         decrypt_proc = decrypt_tkt;
     729             : 
     730       60269 :     ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
     731       60269 :     if (ret)
     732           0 :         goto out;
     733             : 
     734       60269 :     if (rep->enc_part.flags.enc_pa_rep && request) {
     735       14095 :         krb5_crypto crypto = NULL;
     736         585 :         Checksum cksum;
     737       14095 :         PA_DATA *pa = NULL;
     738       14095 :         int idx = 0;
     739             : 
     740       14095 :         _krb5_debug(context, 5, "processing enc-ap-rep");
     741             : 
     742       27605 :         if (rep->enc_part.encrypted_pa_data == NULL ||
     743       14095 :             (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val,
     744       13510 :                                    rep->enc_part.encrypted_pa_data->len,
     745             :                                    KRB5_PADATA_REQ_ENC_PA_REP,
     746             :                                    &idx)) == NULL)
     747             :         {
     748           0 :             _krb5_debug(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing");
     749           0 :             ret = KRB5KRB_AP_ERR_MODIFIED;
     750          12 :             goto out;
     751             :         }
     752             :         
     753       14095 :         ret = krb5_crypto_init(context, key, 0, &crypto);
     754       14095 :         if (ret)
     755           0 :             goto out;
     756             :         
     757       14095 :         ret = decode_Checksum(pa->padata_value.data,
     758             :                               pa->padata_value.length,
     759             :                               &cksum, NULL);
     760       14095 :         if (ret) {
     761           0 :             krb5_crypto_destroy(context, crypto);
     762           0 :             goto out;
     763             :         }
     764             :         
     765       14095 :         ret = krb5_verify_checksum(context, crypto,
     766             :                                    KRB5_KU_AS_REQ,
     767             :                                    request->data, request->length,
     768             :                                    &cksum);
     769       14095 :         krb5_crypto_destroy(context, crypto);
     770       14095 :         free_Checksum(&cksum);
     771       14095 :         _krb5_debug(context, 5, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in");
     772       14095 :         if (ret)
     773          12 :             goto out;
     774             :     }
     775             : 
     776             :     /* save session key */
     777             : 
     778       60257 :     creds->session.keyvalue.length = 0;
     779       60257 :     creds->session.keyvalue.data   = NULL;
     780       60257 :     creds->session.keytype = rep->enc_part.key.keytype;
     781       62500 :     ret = krb5_data_copy (&creds->session.keyvalue,
     782       60257 :                           rep->enc_part.key.keyvalue.data,
     783             :                           rep->enc_part.key.keyvalue.length);
     784       60257 :     if (ret) {
     785           0 :         krb5_clear_error_message(context);
     786           0 :         goto out;
     787             :     }
     788             : 
     789             :     /* compare client and save */
     790       60257 :     ret = _krb5_principalname2krb5_principal(context,
     791             :                                              &tmp_principal,
     792             :                                              rep->kdc_rep.cname,
     793             :                                              rep->kdc_rep.crealm);
     794       60257 :     if (ret)
     795           0 :         goto out;
     796             : 
     797             :     /* check KDC supported anonymous if it was requested */
     798       60257 :     if (flags & EXTRACT_TICKET_MATCH_ANON) {
     799           0 :         ret = check_client_anonymous(context,rep,
     800           0 :                                      creds->client,
     801             :                                      tmp_principal,
     802             :                                      request == NULL); /* is TGS */
     803           0 :         if (ret) {
     804           0 :             krb5_free_principal(context, tmp_principal);
     805           0 :             goto out;
     806             :         }
     807             :     }
     808             : 
     809             :     /* check client referral and save principal */
     810       60257 :     if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
     811       48207 :         ret = check_client_mismatch(context, rep,
     812       46549 :                                     creds->client,
     813             :                                     tmp_principal,
     814       46549 :                                     &creds->session);
     815       46549 :         if (ret) {
     816           0 :             krb5_free_principal (context, tmp_principal);
     817           0 :             goto out;
     818             :         }
     819             :     }
     820       60257 :     krb5_free_principal (context, creds->client);
     821       60257 :     creds->client = tmp_principal;
     822             : 
     823             :     /* check server referral and save principal */
     824       60257 :     ret = _krb5_kdcrep2krb5_principal(context, &tmp_principal, &rep->enc_part);
     825       60257 :     if (ret)
     826           0 :         goto out;
     827             : 
     828       60257 :     tmp_principal->nameattrs->peer_realm =
     829       60257 :         calloc(1, sizeof(tmp_principal->nameattrs->peer_realm[0]));
     830       60257 :     if (tmp_principal->nameattrs->peer_realm == NULL) {
     831           0 :         ret = krb5_enomem(context);
     832           0 :         goto out;
     833             :     }
     834       60257 :     ret = copy_Realm(&creds->client->realm, tmp_principal->nameattrs->peer_realm);
     835       60257 :     if (ret) goto out;
     836             : 
     837       60257 :     if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
     838       48607 :         ret = check_server_referral(context,
     839             :                                     rep,
     840             :                                     flags,
     841       46949 :                                     creds->server,
     842             :                                     tmp_principal,
     843             :                                     &creds->session);
     844       46949 :         if (ret) {
     845           0 :             krb5_free_principal (context, tmp_principal);
     846           0 :             goto out;
     847             :         }
     848             :     }
     849       60257 :     krb5_free_principal(context, creds->server);
     850       60257 :     creds->server = tmp_principal;
     851             : 
     852             :     /* verify names */
     853       60257 :     if(flags & EXTRACT_TICKET_MATCH_REALM){
     854       13308 :         const char *srealm = krb5_principal_get_realm(context, creds->server);
     855       13308 :         const char *crealm = krb5_principal_get_realm(context, creds->client);
     856             : 
     857       13308 :         if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
     858       13308 :             strcmp(rep->enc_part.srealm, crealm) != 0)
     859             :         {
     860           0 :             ret = KRB5KRB_AP_ERR_MODIFIED;
     861           0 :             krb5_clear_error_message(context);
     862           0 :             goto out;
     863             :         }
     864             :     }
     865             : 
     866             :     /* compare nonces */
     867             : 
     868       60257 :     if (nonce != (unsigned)rep->enc_part.nonce) {
     869           0 :         ret = KRB5KRB_AP_ERR_MODIFIED;
     870           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     871           0 :         goto out;
     872             :     }
     873             : 
     874             :     /* set kdc-offset */
     875             : 
     876       60257 :     krb5_timeofday (context, &sec_now);
     877       60257 :     if (rep->enc_part.flags.initial
     878       14083 :         && (flags & EXTRACT_TICKET_TIMESYNC)
     879       14083 :         && context->kdc_sec_offset == 0
     880       14083 :         && krb5_config_get_bool (context, NULL,
     881             :                                  "libdefaults",
     882             :                                  "kdc_timesync",
     883             :                                  NULL)) {
     884           0 :         context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
     885           0 :         krb5_timeofday (context, &sec_now);
     886             :     }
     887             : 
     888             :     /* check all times */
     889             : 
     890       60257 :     if (rep->enc_part.starttime) {
     891       46174 :         tmp_time = *rep->enc_part.starttime;
     892             :     } else
     893       14083 :         tmp_time = rep->enc_part.authtime;
     894             : 
     895       60257 :     if (creds->times.starttime == 0
     896       60257 :         && krb5_time_abs(tmp_time, sec_now) > context->max_skew) {
     897           0 :         ret = KRB5KRB_AP_ERR_SKEW;
     898           0 :         krb5_set_error_message (context, ret,
     899           0 :                                 N_("time skew (%ld) larger than max (%ld)", ""),
     900           0 :                                (long)krb5_time_abs(tmp_time, sec_now),
     901           0 :                                (long)context->max_skew);
     902           0 :         goto out;
     903             :     }
     904             : 
     905       60257 :     if (creds->times.starttime != 0
     906           0 :         && tmp_time != creds->times.starttime) {
     907           0 :         krb5_clear_error_message (context);
     908           0 :         ret = KRB5KRB_AP_ERR_MODIFIED;
     909           0 :         goto out;
     910             :     }
     911             : 
     912       60257 :     creds->times.starttime = tmp_time;
     913             : 
     914       60257 :     if (rep->enc_part.renew_till) {
     915        4716 :         tmp_time = *rep->enc_part.renew_till;
     916             :     } else
     917       53298 :         tmp_time = 0;
     918             : 
     919       60257 :     if (creds->times.renew_till != 0
     920        1635 :         && tmp_time > creds->times.renew_till) {
     921           0 :         krb5_clear_error_message (context);
     922           0 :         ret = KRB5KRB_AP_ERR_MODIFIED;
     923           0 :         goto out;
     924             :     }
     925             : 
     926       60257 :     creds->times.renew_till = tmp_time;
     927             : 
     928       60257 :     creds->times.authtime = rep->enc_part.authtime;
     929             : 
     930       60257 :     if (creds->times.endtime != 0
     931       14133 :         && rep->enc_part.endtime > creds->times.endtime) {
     932           0 :         krb5_clear_error_message (context);
     933           0 :         ret = KRB5KRB_AP_ERR_MODIFIED;
     934           0 :         goto out;
     935             :     }
     936             : 
     937       60257 :     creds->times.endtime  = rep->enc_part.endtime;
     938             : 
     939       60257 :     if(rep->enc_part.caddr)
     940       23031 :         krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
     941       37226 :     else if(addrs)
     942       23146 :         krb5_copy_addresses (context, addrs, &creds->addresses);
     943             :     else {
     944       14080 :         creds->addresses.len = 0;
     945       14080 :         creds->addresses.val = NULL;
     946             :     }
     947       60257 :     creds->flags.b = rep->enc_part.flags;
     948             : 
     949       60257 :     creds->authdata.len = 0;
     950       60257 :     creds->authdata.val = NULL;
     951             : 
     952             :     /* extract ticket */
     953       60257 :     ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
     954             :                        &rep->kdc_rep.ticket, &len, ret);
     955       60257 :     if(ret)
     956           0 :         goto out;
     957       60257 :     if (creds->ticket.length != len)
     958           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
     959       60257 :     creds->second_ticket.length = 0;
     960       60257 :     creds->second_ticket.data   = NULL;
     961             : 
     962             : 
     963       60269 : out:
     964       60269 :     memset (rep->enc_part.key.keyvalue.data, 0,
     965             :             rep->enc_part.key.keyvalue.length);
     966       60269 :     return ret;
     967             : }

Generated by: LCOV version 1.14