Home | History | Annotate | Line # | Download | only in krb5
      1  1.1     elric /*	$NetBSD: rd_req.c,v 1.3 2023/06/19 21:41:44 christos Exp $	*/
      2  1.1     elric 
      3  1.1     elric 
      4  1.1     elric /*
      5  1.1     elric  * Copyright (c) 1997 - 2007 Kungliga Tekniska Hgskolan
      6  1.1     elric  * (Royal Institute of Technology, Stockholm, Sweden).
      7  1.1     elric  * All rights reserved.
      8  1.1     elric  *
      9  1.1     elric  * Redistribution and use in source and binary forms, with or without
     10  1.1     elric  * modification, are permitted provided that the following conditions
     11  1.1     elric  * are met:
     12  1.1     elric  *
     13  1.1     elric  * 1. Redistributions of source code must retain the above copyright
     14  1.1     elric  *    notice, this list of conditions and the following disclaimer.
     15  1.1     elric  *
     16  1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     17  1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     18  1.1     elric  *    documentation and/or other materials provided with the distribution.
     19  1.1     elric  *
     20  1.1     elric  * 3. Neither the name of the Institute nor the names of its contributors
     21  1.1     elric  *    may be used to endorse or promote products derived from this software
     22  1.1     elric  *    without specific prior written permission.
     23  1.1     elric  *
     24  1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     25  1.1     elric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  1.1     elric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  1.1     elric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     28  1.1     elric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  1.1     elric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  1.1     elric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  1.1     elric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  1.1     elric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  1.1     elric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  1.1     elric  * SUCH DAMAGE.
     35  1.1     elric  */
     36  1.1     elric 
     37  1.1     elric #include "krb5_locl.h"
     38  1.1     elric 
     39  1.1     elric static krb5_error_code
     40  1.1     elric decrypt_tkt_enc_part (krb5_context context,
     41  1.1     elric 		      krb5_keyblock *key,
     42  1.1     elric 		      EncryptedData *enc_part,
     43  1.1     elric 		      EncTicketPart *decr_part)
     44  1.1     elric {
     45  1.1     elric     krb5_error_code ret;
     46  1.1     elric     krb5_data plain;
     47  1.1     elric     size_t len;
     48  1.1     elric     krb5_crypto crypto;
     49  1.1     elric 
     50  1.1     elric     ret = krb5_crypto_init(context, key, 0, &crypto);
     51  1.1     elric     if (ret)
     52  1.1     elric 	return ret;
     53  1.1     elric     ret = krb5_decrypt_EncryptedData (context,
     54  1.1     elric 				      crypto,
     55  1.1     elric 				      KRB5_KU_TICKET,
     56  1.1     elric 				      enc_part,
     57  1.1     elric 				      &plain);
     58  1.1     elric     krb5_crypto_destroy(context, crypto);
     59  1.1     elric     if (ret)
     60  1.1     elric 	return ret;
     61  1.1     elric 
     62  1.1     elric     ret = decode_EncTicketPart(plain.data, plain.length, decr_part, &len);
     63  1.1     elric     if (ret)
     64  1.2  christos         krb5_set_error_message(context, ret,
     65  1.1     elric 			       N_("Failed to decode encrypted "
     66  1.1     elric 				  "ticket part", ""));
     67  1.1     elric     krb5_data_free (&plain);
     68  1.1     elric     return ret;
     69  1.1     elric }
     70  1.1     elric 
     71  1.1     elric static krb5_error_code
     72  1.1     elric decrypt_authenticator (krb5_context context,
     73  1.1     elric 		       EncryptionKey *key,
     74  1.1     elric 		       EncryptedData *enc_part,
     75  1.1     elric 		       Authenticator *authenticator,
     76  1.1     elric 		       krb5_key_usage usage)
     77  1.1     elric {
     78  1.1     elric     krb5_error_code ret;
     79  1.1     elric     krb5_data plain;
     80  1.1     elric     size_t len;
     81  1.1     elric     krb5_crypto crypto;
     82  1.1     elric 
     83  1.1     elric     ret = krb5_crypto_init(context, key, 0, &crypto);
     84  1.1     elric     if (ret)
     85  1.1     elric 	return ret;
     86  1.1     elric     ret = krb5_decrypt_EncryptedData (context,
     87  1.1     elric 				      crypto,
     88  1.1     elric 				      usage /* KRB5_KU_AP_REQ_AUTH */,
     89  1.1     elric 				      enc_part,
     90  1.1     elric 				      &plain);
     91  1.1     elric     /* for backwards compatibility, also try the old usage */
     92  1.1     elric     if (ret && usage == KRB5_KU_TGS_REQ_AUTH)
     93  1.1     elric 	ret = krb5_decrypt_EncryptedData (context,
     94  1.1     elric 					  crypto,
     95  1.1     elric 					  KRB5_KU_AP_REQ_AUTH,
     96  1.1     elric 					  enc_part,
     97  1.1     elric 					  &plain);
     98  1.1     elric     krb5_crypto_destroy(context, crypto);
     99  1.1     elric     if (ret)
    100  1.1     elric 	return ret;
    101  1.1     elric 
    102  1.1     elric     ret = decode_Authenticator(plain.data, plain.length,
    103  1.1     elric 			       authenticator, &len);
    104  1.1     elric     krb5_data_free (&plain);
    105  1.1     elric     return ret;
    106  1.1     elric }
    107  1.1     elric 
    108  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    109  1.1     elric krb5_decode_ap_req(krb5_context context,
    110  1.1     elric 		   const krb5_data *inbuf,
    111  1.1     elric 		   krb5_ap_req *ap_req)
    112  1.1     elric {
    113  1.1     elric     krb5_error_code ret;
    114  1.1     elric     size_t len;
    115  1.1     elric     ret = decode_AP_REQ(inbuf->data, inbuf->length, ap_req, &len);
    116  1.1     elric     if (ret)
    117  1.1     elric 	return ret;
    118  1.1     elric     if (ap_req->pvno != 5){
    119  1.1     elric 	free_AP_REQ(ap_req);
    120  1.1     elric 	krb5_clear_error_message (context);
    121  1.1     elric 	return KRB5KRB_AP_ERR_BADVERSION;
    122  1.1     elric     }
    123  1.1     elric     if (ap_req->msg_type != krb_ap_req){
    124  1.1     elric 	free_AP_REQ(ap_req);
    125  1.1     elric 	krb5_clear_error_message (context);
    126  1.1     elric 	return KRB5KRB_AP_ERR_MSG_TYPE;
    127  1.1     elric     }
    128  1.1     elric     if (ap_req->ticket.tkt_vno != 5){
    129  1.1     elric 	free_AP_REQ(ap_req);
    130  1.1     elric 	krb5_clear_error_message (context);
    131  1.1     elric 	return KRB5KRB_AP_ERR_BADVERSION;
    132  1.1     elric     }
    133  1.1     elric     return 0;
    134  1.1     elric }
    135  1.1     elric 
    136  1.1     elric static krb5_error_code
    137  1.1     elric check_transited(krb5_context context, Ticket *ticket, EncTicketPart *enc)
    138  1.1     elric {
    139  1.1     elric     char **realms;
    140  1.2  christos     unsigned int num_realms, n;
    141  1.1     elric     krb5_error_code ret;
    142  1.2  christos 
    143  1.1     elric     /*
    144  1.1     elric      * Windows 2000 and 2003 uses this inside their TGT so it's normaly
    145  1.1     elric      * not seen by others, however, samba4 joined with a Windows AD as
    146  1.1     elric      * a Domain Controller gets exposed to this.
    147  1.1     elric      */
    148  1.1     elric     if(enc->transited.tr_type == 0 && enc->transited.contents.length == 0)
    149  1.1     elric 	return 0;
    150  1.1     elric 
    151  1.1     elric     if(enc->transited.tr_type != DOMAIN_X500_COMPRESS)
    152  1.1     elric 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
    153  1.1     elric 
    154  1.1     elric     if(enc->transited.contents.length == 0)
    155  1.1     elric 	return 0;
    156  1.1     elric 
    157  1.1     elric     ret = krb5_domain_x500_decode(context, enc->transited.contents,
    158  1.1     elric 				  &realms, &num_realms,
    159  1.1     elric 				  enc->crealm,
    160  1.1     elric 				  ticket->realm);
    161  1.1     elric     if(ret)
    162  1.1     elric 	return ret;
    163  1.1     elric     ret = krb5_check_transited(context, enc->crealm,
    164  1.1     elric 			       ticket->realm,
    165  1.1     elric 			       realms, num_realms, NULL);
    166  1.2  christos     for (n = 0; n < num_realms; n++)
    167  1.2  christos 	free(realms[n]);
    168  1.1     elric     free(realms);
    169  1.1     elric     return ret;
    170  1.1     elric }
    171  1.1     elric 
    172  1.1     elric static krb5_error_code
    173  1.1     elric find_etypelist(krb5_context context,
    174  1.1     elric 	       krb5_auth_context auth_context,
    175  1.1     elric 	       EtypeList *etypes)
    176  1.1     elric {
    177  1.1     elric     krb5_error_code ret;
    178  1.2  christos     krb5_data data;
    179  1.2  christos 
    180  1.2  christos     ret = _krb5_get_ad(context, auth_context->authenticator->authorization_data, NULL, KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION, &data);
    181  1.2  christos     if (ret)
    182  1.2  christos   	return 0;
    183  1.2  christos 
    184  1.2  christos     ret = decode_EtypeList(data.data, data.length, etypes, NULL);
    185  1.2  christos     krb5_data_free(&data);
    186  1.1     elric     if (ret)
    187  1.2  christos   	krb5_clear_error_message(context);
    188  1.2  christos 
    189  1.1     elric     return ret;
    190  1.1     elric }
    191  1.1     elric 
    192  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    193  1.1     elric krb5_decrypt_ticket(krb5_context context,
    194  1.1     elric 		    Ticket *ticket,
    195  1.1     elric 		    krb5_keyblock *key,
    196  1.1     elric 		    EncTicketPart *out,
    197  1.1     elric 		    krb5_flags flags)
    198  1.1     elric {
    199  1.1     elric     EncTicketPart t;
    200  1.1     elric     krb5_error_code ret;
    201  1.1     elric     ret = decrypt_tkt_enc_part (context, key, &ticket->enc_part, &t);
    202  1.1     elric     if (ret)
    203  1.1     elric 	return ret;
    204  1.1     elric 
    205  1.1     elric     {
    206  1.1     elric 	krb5_timestamp now;
    207  1.1     elric 	time_t start = t.authtime;
    208  1.1     elric 
    209  1.1     elric 	krb5_timeofday (context, &now);
    210  1.1     elric 	if(t.starttime)
    211  1.1     elric 	    start = *t.starttime;
    212  1.1     elric 	if(start - now > context->max_skew
    213  1.1     elric 	   || (t.flags.invalid
    214  1.1     elric 	       && !(flags & KRB5_VERIFY_AP_REQ_IGNORE_INVALID))) {
    215  1.1     elric 	    free_EncTicketPart(&t);
    216  1.1     elric 	    krb5_clear_error_message (context);
    217  1.1     elric 	    return KRB5KRB_AP_ERR_TKT_NYV;
    218  1.1     elric 	}
    219  1.1     elric 	if(now - t.endtime > context->max_skew) {
    220  1.1     elric 	    free_EncTicketPart(&t);
    221  1.1     elric 	    krb5_clear_error_message (context);
    222  1.1     elric 	    return KRB5KRB_AP_ERR_TKT_EXPIRED;
    223  1.1     elric 	}
    224  1.2  christos 
    225  1.1     elric 	if(!t.flags.transited_policy_checked) {
    226  1.1     elric 	    ret = check_transited(context, ticket, &t);
    227  1.1     elric 	    if(ret) {
    228  1.1     elric 		free_EncTicketPart(&t);
    229  1.1     elric 		return ret;
    230  1.1     elric 	    }
    231  1.1     elric 	}
    232  1.1     elric     }
    233  1.1     elric 
    234  1.1     elric     if(out)
    235  1.1     elric 	*out = t;
    236  1.1     elric     else
    237  1.1     elric 	free_EncTicketPart(&t);
    238  1.1     elric     return 0;
    239  1.1     elric }
    240  1.1     elric 
    241  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    242  1.1     elric krb5_verify_authenticator_checksum(krb5_context context,
    243  1.1     elric 				   krb5_auth_context ac,
    244  1.1     elric 				   void *data,
    245  1.1     elric 				   size_t len)
    246  1.1     elric {
    247  1.1     elric     krb5_error_code ret;
    248  1.2  christos     krb5_keyblock *key = NULL;
    249  1.1     elric     krb5_authenticator authenticator;
    250  1.1     elric     krb5_crypto crypto;
    251  1.1     elric 
    252  1.2  christos     ret = krb5_auth_con_getauthenticator(context, ac, &authenticator);
    253  1.2  christos     if (ret)
    254  1.1     elric 	return ret;
    255  1.2  christos     if (authenticator->cksum == NULL) {
    256  1.2  christos 	ret = -17;
    257  1.2  christos         goto out;
    258  1.1     elric     }
    259  1.1     elric     ret = krb5_auth_con_getkey(context, ac, &key);
    260  1.2  christos     if (ret)
    261  1.2  christos         goto out;
    262  1.1     elric     ret = krb5_crypto_init(context, key, 0, &crypto);
    263  1.2  christos     if (ret)
    264  1.1     elric 	goto out;
    265  1.2  christos     ret = krb5_verify_checksum(context, crypto,
    266  1.2  christos                                KRB5_KU_AP_REQ_AUTH_CKSUM,
    267  1.2  christos                                data, len, authenticator->cksum);
    268  1.1     elric     krb5_crypto_destroy(context, crypto);
    269  1.1     elric out:
    270  1.1     elric     krb5_free_authenticator(context, &authenticator);
    271  1.1     elric     krb5_free_keyblock(context, key);
    272  1.1     elric     return ret;
    273  1.1     elric }
    274  1.1     elric 
    275  1.1     elric 
    276  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    277  1.1     elric krb5_verify_ap_req(krb5_context context,
    278  1.1     elric 		   krb5_auth_context *auth_context,
    279  1.1     elric 		   krb5_ap_req *ap_req,
    280  1.1     elric 		   krb5_const_principal server,
    281  1.1     elric 		   krb5_keyblock *keyblock,
    282  1.1     elric 		   krb5_flags flags,
    283  1.1     elric 		   krb5_flags *ap_req_options,
    284  1.1     elric 		   krb5_ticket **ticket)
    285  1.1     elric {
    286  1.1     elric     return krb5_verify_ap_req2 (context,
    287  1.1     elric 				auth_context,
    288  1.1     elric 				ap_req,
    289  1.1     elric 				server,
    290  1.1     elric 				keyblock,
    291  1.1     elric 				flags,
    292  1.1     elric 				ap_req_options,
    293  1.1     elric 				ticket,
    294  1.1     elric 				KRB5_KU_AP_REQ_AUTH);
    295  1.1     elric }
    296  1.1     elric 
    297  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    298  1.1     elric krb5_verify_ap_req2(krb5_context context,
    299  1.1     elric 		    krb5_auth_context *auth_context,
    300  1.1     elric 		    krb5_ap_req *ap_req,
    301  1.1     elric 		    krb5_const_principal server,
    302  1.1     elric 		    krb5_keyblock *keyblock,
    303  1.1     elric 		    krb5_flags flags,
    304  1.1     elric 		    krb5_flags *ap_req_options,
    305  1.1     elric 		    krb5_ticket **ticket,
    306  1.1     elric 		    krb5_key_usage usage)
    307  1.1     elric {
    308  1.1     elric     krb5_ticket *t;
    309  1.1     elric     krb5_auth_context ac;
    310  1.1     elric     krb5_error_code ret;
    311  1.1     elric     EtypeList etypes;
    312  1.1     elric 
    313  1.2  christos     memset(&etypes, 0, sizeof(etypes));
    314  1.2  christos 
    315  1.1     elric     if (ticket)
    316  1.1     elric 	*ticket = NULL;
    317  1.1     elric 
    318  1.1     elric     if (auth_context && *auth_context) {
    319  1.1     elric 	ac = *auth_context;
    320  1.1     elric     } else {
    321  1.1     elric 	ret = krb5_auth_con_init (context, &ac);
    322  1.1     elric 	if (ret)
    323  1.1     elric 	    return ret;
    324  1.1     elric     }
    325  1.1     elric 
    326  1.1     elric     t = calloc(1, sizeof(*t));
    327  1.1     elric     if (t == NULL) {
    328  1.2  christos 	ret = krb5_enomem(context);
    329  1.1     elric 	goto out;
    330  1.1     elric     }
    331  1.1     elric 
    332  1.1     elric     if (ap_req->ap_options.use_session_key && ac->keyblock){
    333  1.1     elric 	ret = krb5_decrypt_ticket(context, &ap_req->ticket,
    334  1.1     elric 				  ac->keyblock,
    335  1.1     elric 				  &t->ticket,
    336  1.1     elric 				  flags);
    337  1.1     elric 	krb5_free_keyblock(context, ac->keyblock);
    338  1.1     elric 	ac->keyblock = NULL;
    339  1.1     elric     }else
    340  1.1     elric 	ret = krb5_decrypt_ticket(context, &ap_req->ticket,
    341  1.1     elric 				  keyblock,
    342  1.1     elric 				  &t->ticket,
    343  1.1     elric 				  flags);
    344  1.1     elric 
    345  1.1     elric     if(ret)
    346  1.1     elric 	goto out;
    347  1.1     elric 
    348  1.1     elric     ret = _krb5_principalname2krb5_principal(context,
    349  1.1     elric 					     &t->server,
    350  1.1     elric 					     ap_req->ticket.sname,
    351  1.1     elric 					     ap_req->ticket.realm);
    352  1.1     elric     if (ret) goto out;
    353  1.1     elric     ret = _krb5_principalname2krb5_principal(context,
    354  1.1     elric 					     &t->client,
    355  1.1     elric 					     t->ticket.cname,
    356  1.1     elric 					     t->ticket.crealm);
    357  1.1     elric     if (ret) goto out;
    358  1.1     elric 
    359  1.1     elric     ret = decrypt_authenticator (context,
    360  1.1     elric 				 &t->ticket.key,
    361  1.1     elric 				 &ap_req->authenticator,
    362  1.1     elric 				 ac->authenticator,
    363  1.1     elric 				 usage);
    364  1.1     elric     if (ret)
    365  1.1     elric 	goto out;
    366  1.1     elric 
    367  1.1     elric     {
    368  1.1     elric 	krb5_principal p1, p2;
    369  1.1     elric 	krb5_boolean res;
    370  1.2  christos 
    371  1.1     elric 	_krb5_principalname2krb5_principal(context,
    372  1.1     elric 					   &p1,
    373  1.1     elric 					   ac->authenticator->cname,
    374  1.1     elric 					   ac->authenticator->crealm);
    375  1.1     elric 	_krb5_principalname2krb5_principal(context,
    376  1.1     elric 					   &p2,
    377  1.1     elric 					   t->ticket.cname,
    378  1.1     elric 					   t->ticket.crealm);
    379  1.1     elric 	res = krb5_principal_compare (context, p1, p2);
    380  1.1     elric 	krb5_free_principal (context, p1);
    381  1.1     elric 	krb5_free_principal (context, p2);
    382  1.1     elric 	if (!res) {
    383  1.1     elric 	    ret = KRB5KRB_AP_ERR_BADMATCH;
    384  1.1     elric 	    krb5_clear_error_message (context);
    385  1.1     elric 	    goto out;
    386  1.1     elric 	}
    387  1.1     elric     }
    388  1.1     elric 
    389  1.1     elric     /* check addresses */
    390  1.1     elric 
    391  1.1     elric     if (t->ticket.caddr
    392  1.1     elric 	&& ac->remote_address
    393  1.1     elric 	&& !krb5_address_search (context,
    394  1.1     elric 				 ac->remote_address,
    395  1.1     elric 				 t->ticket.caddr)) {
    396  1.1     elric 	ret = KRB5KRB_AP_ERR_BADADDR;
    397  1.1     elric 	krb5_clear_error_message (context);
    398  1.1     elric 	goto out;
    399  1.1     elric     }
    400  1.1     elric 
    401  1.1     elric     /* check timestamp in authenticator */
    402  1.1     elric     {
    403  1.1     elric 	krb5_timestamp now;
    404  1.1     elric 
    405  1.1     elric 	krb5_timeofday (context, &now);
    406  1.1     elric 
    407  1.2  christos 	if (labs(ac->authenticator->ctime - now) > context->max_skew) {
    408  1.1     elric 	    ret = KRB5KRB_AP_ERR_SKEW;
    409  1.1     elric 	    krb5_clear_error_message (context);
    410  1.1     elric 	    goto out;
    411  1.1     elric 	}
    412  1.1     elric     }
    413  1.1     elric 
    414  1.1     elric     if (ac->authenticator->seq_number)
    415  1.1     elric 	krb5_auth_con_setremoteseqnumber(context, ac,
    416  1.1     elric 					 *ac->authenticator->seq_number);
    417  1.1     elric 
    418  1.1     elric     /* XXX - Xor sequence numbers */
    419  1.1     elric 
    420  1.1     elric     if (ac->authenticator->subkey) {
    421  1.1     elric 	ret = krb5_auth_con_setremotesubkey(context, ac,
    422  1.1     elric 					    ac->authenticator->subkey);
    423  1.1     elric 	if (ret)
    424  1.1     elric 	    goto out;
    425  1.1     elric     }
    426  1.1     elric 
    427  1.1     elric     ret = find_etypelist(context, ac, &etypes);
    428  1.1     elric     if (ret)
    429  1.1     elric 	goto out;
    430  1.1     elric 
    431  1.1     elric     ac->keytype = ETYPE_NULL;
    432  1.1     elric 
    433  1.1     elric     if (etypes.val) {
    434  1.2  christos 	size_t i;
    435  1.1     elric 
    436  1.1     elric 	for (i = 0; i < etypes.len; i++) {
    437  1.1     elric 	    if (krb5_enctype_valid(context, etypes.val[i]) == 0) {
    438  1.1     elric 		ac->keytype = etypes.val[i];
    439  1.1     elric 		break;
    440  1.1     elric 	    }
    441  1.1     elric 	}
    442  1.1     elric     }
    443  1.1     elric 
    444  1.1     elric     /* save key */
    445  1.1     elric     ret = krb5_copy_keyblock(context, &t->ticket.key, &ac->keyblock);
    446  1.1     elric     if (ret) goto out;
    447  1.1     elric 
    448  1.1     elric     if (ap_req_options) {
    449  1.1     elric 	*ap_req_options = 0;
    450  1.2  christos 	if (ac->keytype != (krb5_enctype)ETYPE_NULL)
    451  1.1     elric 	    *ap_req_options |= AP_OPTS_USE_SUBKEY;
    452  1.1     elric 	if (ap_req->ap_options.use_session_key)
    453  1.1     elric 	    *ap_req_options |= AP_OPTS_USE_SESSION_KEY;
    454  1.1     elric 	if (ap_req->ap_options.mutual_required)
    455  1.1     elric 	    *ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
    456  1.1     elric     }
    457  1.1     elric 
    458  1.1     elric     if(ticket)
    459  1.1     elric 	*ticket = t;
    460  1.1     elric     else
    461  1.1     elric 	krb5_free_ticket (context, t);
    462  1.1     elric     if (auth_context) {
    463  1.1     elric 	if (*auth_context == NULL)
    464  1.1     elric 	    *auth_context = ac;
    465  1.1     elric     } else
    466  1.1     elric 	krb5_auth_con_free (context, ac);
    467  1.1     elric     free_EtypeList(&etypes);
    468  1.1     elric     return 0;
    469  1.1     elric  out:
    470  1.2  christos     free_EtypeList(&etypes);
    471  1.1     elric     if (t)
    472  1.1     elric 	krb5_free_ticket (context, t);
    473  1.1     elric     if (auth_context == NULL || *auth_context == NULL)
    474  1.1     elric 	krb5_auth_con_free (context, ac);
    475  1.1     elric     return ret;
    476  1.1     elric }
    477  1.2  christos 
    478  1.1     elric /*
    479  1.1     elric  *
    480  1.1     elric  */
    481  1.1     elric 
    482  1.1     elric struct krb5_rd_req_in_ctx_data {
    483  1.1     elric     krb5_keytab keytab;
    484  1.1     elric     krb5_keyblock *keyblock;
    485  1.1     elric     krb5_boolean check_pac;
    486  1.1     elric };
    487  1.1     elric 
    488  1.1     elric struct krb5_rd_req_out_ctx_data {
    489  1.1     elric     krb5_keyblock *keyblock;
    490  1.1     elric     krb5_flags ap_req_options;
    491  1.1     elric     krb5_ticket *ticket;
    492  1.1     elric     krb5_principal server;
    493  1.1     elric };
    494  1.1     elric 
    495  1.1     elric /**
    496  1.1     elric  * Allocate a krb5_rd_req_in_ctx as an input parameter to
    497  1.1     elric  * krb5_rd_req_ctx(). The caller should free the context with
    498  1.1     elric  * krb5_rd_req_in_ctx_free() when done with the context.
    499  1.1     elric  *
    500  1.1     elric  * @param context Keberos 5 context.
    501  1.1     elric  * @param ctx in ctx to krb5_rd_req_ctx().
    502  1.1     elric  *
    503  1.1     elric  * @return Kerberos 5 error code, see krb5_get_error_message().
    504  1.1     elric  *
    505  1.1     elric  * @ingroup krb5_auth
    506  1.1     elric  */
    507  1.1     elric 
    508  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    509  1.1     elric krb5_rd_req_in_ctx_alloc(krb5_context context, krb5_rd_req_in_ctx *ctx)
    510  1.1     elric {
    511  1.1     elric     *ctx = calloc(1, sizeof(**ctx));
    512  1.2  christos     if (*ctx == NULL)
    513  1.2  christos 	return krb5_enomem(context);
    514  1.1     elric     (*ctx)->check_pac = (context->flags & KRB5_CTX_F_CHECK_PAC) ? 1 : 0;
    515  1.1     elric     return 0;
    516  1.1     elric }
    517  1.1     elric 
    518  1.1     elric /**
    519  1.1     elric  * Set the keytab that krb5_rd_req_ctx() will use.
    520  1.1     elric  *
    521  1.1     elric  * @param context Keberos 5 context.
    522  1.1     elric  * @param in in ctx to krb5_rd_req_ctx().
    523  1.1     elric  * @param keytab keytab that krb5_rd_req_ctx() will use, only copy the
    524  1.1     elric  *        pointer, so the caller must free they keytab after
    525  1.1     elric  *        krb5_rd_req_in_ctx_free() is called.
    526  1.1     elric  *
    527  1.1     elric  * @return Kerberos 5 error code, see krb5_get_error_message().
    528  1.1     elric  *
    529  1.1     elric  * @ingroup krb5_auth
    530  1.1     elric  */
    531  1.1     elric 
    532  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    533  1.1     elric krb5_rd_req_in_set_keytab(krb5_context context,
    534  1.1     elric 			  krb5_rd_req_in_ctx in,
    535  1.1     elric 			  krb5_keytab keytab)
    536  1.1     elric {
    537  1.1     elric     in->keytab = keytab;
    538  1.1     elric     return 0;
    539  1.1     elric }
    540  1.1     elric 
    541  1.1     elric /**
    542  1.1     elric  * Set if krb5_rq_red() is going to check the Windows PAC or not
    543  1.1     elric  *
    544  1.1     elric  * @param context Keberos 5 context.
    545  1.1     elric  * @param in krb5_rd_req_in_ctx to check the option on.
    546  1.1     elric  * @param flag flag to select if to check the pac (TRUE) or not (FALSE).
    547  1.1     elric  *
    548  1.1     elric  * @return Kerberos 5 error code, see krb5_get_error_message().
    549  1.1     elric  *
    550  1.1     elric  * @ingroup krb5_auth
    551  1.1     elric  */
    552  1.1     elric 
    553  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    554  1.1     elric krb5_rd_req_in_set_pac_check(krb5_context context,
    555  1.1     elric 			     krb5_rd_req_in_ctx in,
    556  1.1     elric 			     krb5_boolean flag)
    557  1.1     elric {
    558  1.1     elric     in->check_pac = flag;
    559  1.1     elric     return 0;
    560  1.1     elric }
    561  1.1     elric 
    562  1.1     elric 
    563  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    564  1.1     elric krb5_rd_req_in_set_keyblock(krb5_context context,
    565  1.1     elric 			    krb5_rd_req_in_ctx in,
    566  1.1     elric 			    krb5_keyblock *keyblock)
    567  1.1     elric {
    568  1.1     elric     in->keyblock = keyblock; /* XXX should make copy */
    569  1.1     elric     return 0;
    570  1.1     elric }
    571  1.1     elric 
    572  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    573  1.1     elric krb5_rd_req_out_get_ap_req_options(krb5_context context,
    574  1.1     elric 				   krb5_rd_req_out_ctx out,
    575  1.1     elric 				   krb5_flags *ap_req_options)
    576  1.1     elric {
    577  1.1     elric     *ap_req_options = out->ap_req_options;
    578  1.1     elric     return 0;
    579  1.1     elric }
    580  1.1     elric 
    581  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    582  1.1     elric krb5_rd_req_out_get_ticket(krb5_context context,
    583  1.1     elric 			    krb5_rd_req_out_ctx out,
    584  1.1     elric 			    krb5_ticket **ticket)
    585  1.1     elric {
    586  1.1     elric     return krb5_copy_ticket(context, out->ticket, ticket);
    587  1.1     elric }
    588  1.1     elric 
    589  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    590  1.1     elric krb5_rd_req_out_get_keyblock(krb5_context context,
    591  1.1     elric 			    krb5_rd_req_out_ctx out,
    592  1.1     elric 			    krb5_keyblock **keyblock)
    593  1.1     elric {
    594  1.1     elric     return krb5_copy_keyblock(context, out->keyblock, keyblock);
    595  1.1     elric }
    596  1.1     elric 
    597  1.1     elric /**
    598  1.1     elric  * Get the principal that was used in the request from the
    599  1.1     elric  * client. Might not match whats in the ticket if krb5_rd_req_ctx()
    600  1.1     elric  * searched in the keytab for a matching key.
    601  1.1     elric  *
    602  1.1     elric  * @param context a Kerberos 5 context.
    603  1.1     elric  * @param out a krb5_rd_req_out_ctx from krb5_rd_req_ctx().
    604  1.1     elric  * @param principal return principal, free with krb5_free_principal().
    605  1.1     elric  *
    606  1.1     elric  * @ingroup krb5_auth
    607  1.1     elric  */
    608  1.1     elric 
    609  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    610  1.1     elric krb5_rd_req_out_get_server(krb5_context context,
    611  1.1     elric 			    krb5_rd_req_out_ctx out,
    612  1.1     elric 			    krb5_principal *principal)
    613  1.1     elric {
    614  1.1     elric     return krb5_copy_principal(context, out->server, principal);
    615  1.1     elric }
    616  1.1     elric 
    617  1.1     elric KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    618  1.1     elric krb5_rd_req_in_ctx_free(krb5_context context, krb5_rd_req_in_ctx ctx)
    619  1.1     elric {
    620  1.1     elric     free(ctx);
    621  1.1     elric }
    622  1.1     elric 
    623  1.1     elric /**
    624  1.1     elric  * Free the krb5_rd_req_out_ctx.
    625  1.1     elric  *
    626  1.1     elric  * @param context Keberos 5 context.
    627  1.1     elric  * @param ctx krb5_rd_req_out_ctx context to free.
    628  1.1     elric  *
    629  1.1     elric  * @ingroup krb5_auth
    630  1.1     elric  */
    631  1.1     elric 
    632  1.1     elric KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    633  1.1     elric krb5_rd_req_out_ctx_free(krb5_context context, krb5_rd_req_out_ctx ctx)
    634  1.1     elric {
    635  1.1     elric     if (ctx->ticket)
    636  1.1     elric 	krb5_free_ticket(context, ctx->ticket);
    637  1.1     elric     if (ctx->keyblock)
    638  1.1     elric 	krb5_free_keyblock(context, ctx->keyblock);
    639  1.1     elric     if (ctx->server)
    640  1.1     elric 	krb5_free_principal(context, ctx->server);
    641  1.1     elric     free(ctx);
    642  1.1     elric }
    643  1.1     elric 
    644  1.2  christos /**
    645  1.2  christos  * Process an AP_REQ message.
    646  1.2  christos  *
    647  1.2  christos  * @param context        Kerberos 5 context.
    648  1.2  christos  * @param auth_context   authentication context of the peer.
    649  1.2  christos  * @param inbuf          the AP_REQ message, obtained for example with krb5_read_message().
    650  1.2  christos  * @param server         server principal.
    651  1.2  christos  * @param keytab         server keytab.
    652  1.2  christos  * @param ap_req_options set to the AP_REQ options. See the AP_OPTS_* defines.
    653  1.2  christos  * @param ticket         on success, set to the authenticated client credentials.
    654  1.2  christos  *                       Must be deallocated with krb5_free_ticket(). If not
    655  1.2  christos  *                       interested, pass a NULL value.
    656  1.1     elric  *
    657  1.2  christos  * @return 0 to indicate success. Otherwise a Kerberos error code is
    658  1.2  christos  *         returned, see krb5_get_error_message().
    659  1.1     elric  */
    660  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    661  1.1     elric krb5_rd_req(krb5_context context,
    662  1.1     elric 	    krb5_auth_context *auth_context,
    663  1.1     elric 	    const krb5_data *inbuf,
    664  1.1     elric 	    krb5_const_principal server,
    665  1.1     elric 	    krb5_keytab keytab,
    666  1.1     elric 	    krb5_flags *ap_req_options,
    667  1.1     elric 	    krb5_ticket **ticket)
    668  1.1     elric {
    669  1.1     elric     krb5_error_code ret;
    670  1.1     elric     krb5_rd_req_in_ctx in;
    671  1.1     elric     krb5_rd_req_out_ctx out;
    672  1.1     elric 
    673  1.1     elric     ret = krb5_rd_req_in_ctx_alloc(context, &in);
    674  1.1     elric     if (ret)
    675  1.1     elric 	return ret;
    676  1.1     elric 
    677  1.1     elric     ret = krb5_rd_req_in_set_keytab(context, in, keytab);
    678  1.1     elric     if (ret) {
    679  1.1     elric 	krb5_rd_req_in_ctx_free(context, in);
    680  1.1     elric 	return ret;
    681  1.1     elric     }
    682  1.1     elric 
    683  1.1     elric     ret = krb5_rd_req_ctx(context, auth_context, inbuf, server, in, &out);
    684  1.1     elric     krb5_rd_req_in_ctx_free(context, in);
    685  1.1     elric     if (ret)
    686  1.1     elric 	return ret;
    687  1.1     elric 
    688  1.1     elric     if (ap_req_options)
    689  1.1     elric 	*ap_req_options = out->ap_req_options;
    690  1.1     elric     if (ticket) {
    691  1.1     elric 	ret = krb5_copy_ticket(context, out->ticket, ticket);
    692  1.1     elric 	if (ret)
    693  1.1     elric 	    goto out;
    694  1.1     elric     }
    695  1.1     elric 
    696  1.1     elric out:
    697  1.1     elric     krb5_rd_req_out_ctx_free(context, out);
    698  1.1     elric     return ret;
    699  1.1     elric }
    700  1.1     elric 
    701  1.1     elric /*
    702  1.1     elric  *
    703  1.1     elric  */
    704  1.1     elric 
    705  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    706  1.1     elric krb5_rd_req_with_keyblock(krb5_context context,
    707  1.1     elric 			  krb5_auth_context *auth_context,
    708  1.1     elric 			  const krb5_data *inbuf,
    709  1.1     elric 			  krb5_const_principal server,
    710  1.1     elric 			  krb5_keyblock *keyblock,
    711  1.1     elric 			  krb5_flags *ap_req_options,
    712  1.1     elric 			  krb5_ticket **ticket)
    713  1.1     elric {
    714  1.1     elric     krb5_error_code ret;
    715  1.1     elric     krb5_rd_req_in_ctx in;
    716  1.1     elric     krb5_rd_req_out_ctx out;
    717  1.1     elric 
    718  1.1     elric     ret = krb5_rd_req_in_ctx_alloc(context, &in);
    719  1.1     elric     if (ret)
    720  1.1     elric 	return ret;
    721  1.1     elric 
    722  1.1     elric     ret = krb5_rd_req_in_set_keyblock(context, in, keyblock);
    723  1.1     elric     if (ret) {
    724  1.1     elric 	krb5_rd_req_in_ctx_free(context, in);
    725  1.1     elric 	return ret;
    726  1.1     elric     }
    727  1.1     elric 
    728  1.1     elric     ret = krb5_rd_req_ctx(context, auth_context, inbuf, server, in, &out);
    729  1.1     elric     krb5_rd_req_in_ctx_free(context, in);
    730  1.1     elric     if (ret)
    731  1.1     elric 	return ret;
    732  1.1     elric 
    733  1.1     elric     if (ap_req_options)
    734  1.1     elric 	*ap_req_options = out->ap_req_options;
    735  1.1     elric     if (ticket) {
    736  1.1     elric 	ret = krb5_copy_ticket(context, out->ticket, ticket);
    737  1.1     elric 	if (ret)
    738  1.1     elric 	    goto out;
    739  1.1     elric     }
    740  1.1     elric 
    741  1.1     elric out:
    742  1.1     elric     krb5_rd_req_out_ctx_free(context, out);
    743  1.1     elric     return ret;
    744  1.1     elric }
    745  1.1     elric 
    746  1.1     elric /*
    747  1.1     elric  *
    748  1.1     elric  */
    749  1.1     elric 
    750  1.1     elric static krb5_error_code
    751  1.1     elric get_key_from_keytab(krb5_context context,
    752  1.1     elric 		    krb5_ap_req *ap_req,
    753  1.1     elric 		    krb5_const_principal server,
    754  1.1     elric 		    krb5_keytab keytab,
    755  1.1     elric 		    krb5_keyblock **out_key)
    756  1.1     elric {
    757  1.1     elric     krb5_keytab_entry entry;
    758  1.1     elric     krb5_error_code ret;
    759  1.1     elric     int kvno;
    760  1.1     elric     krb5_keytab real_keytab;
    761  1.1     elric 
    762  1.1     elric     if(keytab == NULL)
    763  1.1     elric 	krb5_kt_default(context, &real_keytab);
    764  1.1     elric     else
    765  1.1     elric 	real_keytab = keytab;
    766  1.1     elric 
    767  1.1     elric     if (ap_req->ticket.enc_part.kvno)
    768  1.1     elric 	kvno = *ap_req->ticket.enc_part.kvno;
    769  1.1     elric     else
    770  1.1     elric 	kvno = 0;
    771  1.1     elric 
    772  1.1     elric     ret = krb5_kt_get_entry (context,
    773  1.1     elric 			     real_keytab,
    774  1.1     elric 			     server,
    775  1.1     elric 			     kvno,
    776  1.1     elric 			     ap_req->ticket.enc_part.etype,
    777  1.1     elric 			     &entry);
    778  1.3  christos     if(ret == 0) {
    779  1.3  christos         ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
    780  1.3  christos         krb5_kt_free_entry(context, &entry);
    781  1.3  christos     }
    782  1.1     elric     if(keytab == NULL)
    783  1.1     elric 	krb5_kt_close(context, real_keytab);
    784  1.1     elric 
    785  1.1     elric     return ret;
    786  1.1     elric }
    787  1.1     elric 
    788  1.1     elric /**
    789  1.1     elric  * The core server function that verify application authentication
    790  1.1     elric  * requests from clients.
    791  1.1     elric  *
    792  1.1     elric  * @param context Keberos 5 context.
    793  1.1     elric  * @param auth_context the authentication context, can be NULL, then
    794  1.1     elric  *        default values for the authentication context will used.
    795  1.1     elric  * @param inbuf the (AP-REQ) authentication buffer
    796  1.1     elric  *
    797  1.2  christos  * @param server the server to authenticate to. If NULL the function
    798  1.1     elric  *        will try to find any available credential in the keytab
    799  1.1     elric  *        that will verify the reply. The function will prefer the
    800  1.2  christos  *        server specified in the AP-REQ, but if
    801  1.1     elric  *        there is no mach, it will try all keytab entries for a
    802  1.2  christos  *        match. This has serious performance issues for large keytabs.
    803  1.1     elric  *
    804  1.1     elric  * @param inctx control the behavior of the function, if NULL, the
    805  1.1     elric  *        default behavior is used.
    806  1.1     elric  * @param outctx the return outctx, free with krb5_rd_req_out_ctx_free().
    807  1.1     elric  * @return Kerberos 5 error code, see krb5_get_error_message().
    808  1.1     elric  *
    809  1.1     elric  * @ingroup krb5_auth
    810  1.1     elric  */
    811  1.1     elric 
    812  1.1     elric KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    813  1.1     elric krb5_rd_req_ctx(krb5_context context,
    814  1.1     elric 		krb5_auth_context *auth_context,
    815  1.1     elric 		const krb5_data *inbuf,
    816  1.1     elric 		krb5_const_principal server,
    817  1.1     elric 		krb5_rd_req_in_ctx inctx,
    818  1.1     elric 		krb5_rd_req_out_ctx *outctx)
    819  1.1     elric {
    820  1.1     elric     krb5_error_code ret;
    821  1.1     elric     krb5_ap_req ap_req;
    822  1.1     elric     krb5_rd_req_out_ctx o = NULL;
    823  1.1     elric     krb5_keytab id = NULL, keytab = NULL;
    824  1.1     elric     krb5_principal service = NULL;
    825  1.1     elric 
    826  1.1     elric     *outctx = NULL;
    827  1.1     elric 
    828  1.1     elric     o = calloc(1, sizeof(*o));
    829  1.2  christos     if (o == NULL)
    830  1.2  christos 	return krb5_enomem(context);
    831  1.1     elric 
    832  1.1     elric     if (*auth_context == NULL) {
    833  1.1     elric 	ret = krb5_auth_con_init(context, auth_context);
    834  1.1     elric 	if (ret)
    835  1.1     elric 	    goto out;
    836  1.1     elric     }
    837  1.1     elric 
    838  1.1     elric     ret = krb5_decode_ap_req(context, inbuf, &ap_req);
    839  1.1     elric     if(ret)
    840  1.1     elric 	goto out;
    841  1.1     elric 
    842  1.2  christos     /* Save the principal that was in the request */
    843  1.1     elric     ret = _krb5_principalname2krb5_principal(context,
    844  1.1     elric 					     &o->server,
    845  1.1     elric 					     ap_req.ticket.sname,
    846  1.1     elric 					     ap_req.ticket.realm);
    847  1.1     elric     if (ret)
    848  1.1     elric 	goto out;
    849  1.1     elric 
    850  1.1     elric     if (ap_req.ap_options.use_session_key &&
    851  1.1     elric 	(*auth_context)->keyblock == NULL) {
    852  1.1     elric 	ret = KRB5KRB_AP_ERR_NOKEY;
    853  1.1     elric 	krb5_set_error_message(context, ret,
    854  1.1     elric 			       N_("krb5_rd_req: user to user auth "
    855  1.1     elric 				  "without session key given", ""));
    856  1.1     elric 	goto out;
    857  1.1     elric     }
    858  1.1     elric 
    859  1.1     elric     if (inctx && inctx->keytab)
    860  1.1     elric 	id = inctx->keytab;
    861  1.1     elric 
    862  1.1     elric     if((*auth_context)->keyblock){
    863  1.1     elric 	ret = krb5_copy_keyblock(context,
    864  1.1     elric 				 (*auth_context)->keyblock,
    865  1.1     elric 				 &o->keyblock);
    866  1.1     elric 	if (ret)
    867  1.1     elric 	    goto out;
    868  1.1     elric     } else if(inctx && inctx->keyblock){
    869  1.1     elric 	ret = krb5_copy_keyblock(context,
    870  1.1     elric 				 inctx->keyblock,
    871  1.1     elric 				 &o->keyblock);
    872  1.1     elric 	if (ret)
    873  1.1     elric 	    goto out;
    874  1.1     elric     } else {
    875  1.1     elric 
    876  1.1     elric 	if(id == NULL) {
    877  1.1     elric 	    krb5_kt_default(context, &keytab);
    878  1.1     elric 	    id = keytab;
    879  1.1     elric 	}
    880  1.1     elric 	if (id == NULL)
    881  1.1     elric 	    goto out;
    882  1.1     elric 
    883  1.1     elric 	if (server == NULL) {
    884  1.1     elric 	    ret = _krb5_principalname2krb5_principal(context,
    885  1.1     elric 						     &service,
    886  1.1     elric 						     ap_req.ticket.sname,
    887  1.1     elric 						     ap_req.ticket.realm);
    888  1.1     elric 	    if (ret)
    889  1.1     elric 		goto out;
    890  1.1     elric 	    server = service;
    891  1.1     elric 	}
    892  1.1     elric 
    893  1.1     elric 	ret = get_key_from_keytab(context,
    894  1.1     elric 				  &ap_req,
    895  1.1     elric 				  server,
    896  1.1     elric 				  id,
    897  1.1     elric 				  &o->keyblock);
    898  1.1     elric 	if (ret) {
    899  1.1     elric 	    /* If caller specified a server, fail. */
    900  1.1     elric 	    if (service == NULL && (context->flags & KRB5_CTX_F_RD_REQ_IGNORE) == 0)
    901  1.1     elric 		goto out;
    902  1.1     elric 	    /* Otherwise, fall back to iterating over the keytab. This
    903  1.1     elric 	     * have serious performace issues for larger keytab.
    904  1.1     elric 	     */
    905  1.1     elric 	    o->keyblock = NULL;
    906  1.1     elric 	}
    907  1.1     elric     }
    908  1.1     elric 
    909  1.1     elric     if (o->keyblock) {
    910  1.1     elric 	/*
    911  1.1     elric 	 * We got an exact keymatch, use that.
    912  1.1     elric 	 */
    913  1.1     elric 
    914  1.1     elric 	ret = krb5_verify_ap_req2(context,
    915  1.1     elric 				  auth_context,
    916  1.1     elric 				  &ap_req,
    917  1.1     elric 				  server,
    918  1.1     elric 				  o->keyblock,
    919  1.1     elric 				  0,
    920  1.1     elric 				  &o->ap_req_options,
    921  1.1     elric 				  &o->ticket,
    922  1.1     elric 				  KRB5_KU_AP_REQ_AUTH);
    923  1.2  christos 
    924  1.1     elric 	if (ret)
    925  1.1     elric 	    goto out;
    926  1.1     elric 
    927  1.1     elric     } else {
    928  1.1     elric 	/*
    929  1.1     elric 	 * Interate over keytab to find a key that can decrypt the request.
    930  1.1     elric 	 */
    931  1.1     elric 
    932  1.1     elric 	krb5_keytab_entry entry;
    933  1.1     elric 	krb5_kt_cursor cursor;
    934  1.1     elric 	int done = 0, kvno = 0;
    935  1.1     elric 
    936  1.1     elric 	memset(&cursor, 0, sizeof(cursor));
    937  1.1     elric 
    938  1.1     elric 	if (ap_req.ticket.enc_part.kvno)
    939  1.1     elric 	    kvno = *ap_req.ticket.enc_part.kvno;
    940  1.1     elric 
    941  1.1     elric 	ret = krb5_kt_start_seq_get(context, id, &cursor);
    942  1.1     elric 	if (ret)
    943  1.1     elric 	    goto out;
    944  1.1     elric 
    945  1.1     elric 	done = 0;
    946  1.2  christos 	while (!done) {
    947  1.1     elric 	    krb5_principal p;
    948  1.1     elric 
    949  1.1     elric 	    ret = krb5_kt_next_entry(context, id, &entry, &cursor);
    950  1.1     elric 	    if (ret) {
    951  1.1     elric 		_krb5_kt_principal_not_found(context, ret, id, o->server,
    952  1.1     elric 					     ap_req.ticket.enc_part.etype,
    953  1.1     elric 					     kvno);
    954  1.2  christos 		break;
    955  1.1     elric 	    }
    956  1.1     elric 
    957  1.2  christos 	    if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype) {
    958  1.1     elric 		krb5_kt_free_entry (context, &entry);
    959  1.1     elric 		continue;
    960  1.1     elric 	    }
    961  1.1     elric 
    962  1.1     elric 	    ret = krb5_verify_ap_req2(context,
    963  1.1     elric 				      auth_context,
    964  1.1     elric 				      &ap_req,
    965  1.1     elric 				      server,
    966  1.1     elric 				      &entry.keyblock,
    967  1.1     elric 				      0,
    968  1.1     elric 				      &o->ap_req_options,
    969  1.1     elric 				      &o->ticket,
    970  1.1     elric 				      KRB5_KU_AP_REQ_AUTH);
    971  1.1     elric 	    if (ret) {
    972  1.1     elric 		krb5_kt_free_entry (context, &entry);
    973  1.1     elric 		continue;
    974  1.1     elric 	    }
    975  1.1     elric 
    976  1.1     elric 	    /*
    977  1.1     elric 	     * Found a match, save the keyblock for PAC processing,
    978  1.1     elric 	     * and update the service principal in the ticket to match
    979  1.1     elric 	     * whatever is in the keytab.
    980  1.1     elric 	     */
    981  1.2  christos 
    982  1.2  christos 	    ret = krb5_copy_keyblock(context,
    983  1.1     elric 				     &entry.keyblock,
    984  1.1     elric 				     &o->keyblock);
    985  1.1     elric 	    if (ret) {
    986  1.1     elric 		krb5_kt_free_entry (context, &entry);
    987  1.2  christos 		break;
    988  1.2  christos 	    }
    989  1.1     elric 
    990  1.1     elric 	    ret = krb5_copy_principal(context, entry.principal, &p);
    991  1.1     elric 	    if (ret) {
    992  1.1     elric 		krb5_kt_free_entry (context, &entry);
    993  1.2  christos 		break;
    994  1.1     elric 	    }
    995  1.1     elric 	    krb5_free_principal(context, o->ticket->server);
    996  1.1     elric 	    o->ticket->server = p;
    997  1.2  christos 
    998  1.1     elric 	    krb5_kt_free_entry (context, &entry);
    999  1.1     elric 
   1000  1.1     elric 	    done = 1;
   1001  1.1     elric 	}
   1002  1.1     elric 	krb5_kt_end_seq_get (context, id, &cursor);
   1003  1.2  christos         if (ret)
   1004  1.2  christos             goto out;
   1005  1.1     elric     }
   1006  1.1     elric 
   1007  1.1     elric     /* If there is a PAC, verify its server signature */
   1008  1.1     elric     if (inctx == NULL || inctx->check_pac) {
   1009  1.1     elric 	krb5_pac pac;
   1010  1.1     elric 	krb5_data data;
   1011  1.1     elric 
   1012  1.1     elric 	ret = krb5_ticket_get_authorization_data_type(context,
   1013  1.1     elric 						      o->ticket,
   1014  1.1     elric 						      KRB5_AUTHDATA_WIN2K_PAC,
   1015  1.1     elric 						      &data);
   1016  1.1     elric 	if (ret == 0) {
   1017  1.1     elric 	    ret = krb5_pac_parse(context, data.data, data.length, &pac);
   1018  1.1     elric 	    krb5_data_free(&data);
   1019  1.1     elric 	    if (ret)
   1020  1.1     elric 		goto out;
   1021  1.2  christos 
   1022  1.1     elric 	    ret = krb5_pac_verify(context,
   1023  1.1     elric 				  pac,
   1024  1.1     elric 				  o->ticket->ticket.authtime,
   1025  1.1     elric 				  o->ticket->client,
   1026  1.1     elric 				  o->keyblock,
   1027  1.1     elric 				  NULL);
   1028  1.1     elric 	    krb5_pac_free(context, pac);
   1029  1.1     elric 	    if (ret)
   1030  1.1     elric 		goto out;
   1031  1.1     elric 	} else
   1032  1.1     elric 	  ret = 0;
   1033  1.1     elric     }
   1034  1.1     elric out:
   1035  1.1     elric 
   1036  1.1     elric     if (ret || outctx == NULL) {
   1037  1.1     elric 	krb5_rd_req_out_ctx_free(context, o);
   1038  1.1     elric     } else
   1039  1.1     elric 	*outctx = o;
   1040  1.1     elric 
   1041  1.1     elric     free_AP_REQ(&ap_req);
   1042  1.1     elric 
   1043  1.1     elric     if (service)
   1044  1.1     elric 	krb5_free_principal(context, service);
   1045  1.1     elric 
   1046  1.1     elric     if (keytab)
   1047  1.1     elric 	krb5_kt_close(context, keytab);
   1048  1.1     elric 
   1049  1.1     elric     return ret;
   1050  1.1     elric }
   1051