17c478bd9Sstevel@tonic-gate /*
25e01956fSGlenn Barry  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate  */
47c478bd9Sstevel@tonic-gate /*
57c478bd9Sstevel@tonic-gate  * lib/krb5/krb/rd_req_dec.c
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1994 CyberSAFE Corporation.
87c478bd9Sstevel@tonic-gate  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
97c478bd9Sstevel@tonic-gate  * All Rights Reserved.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
127c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
137c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
147c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
15*55fea89dSDan Cross  *
167c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
177c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
187c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
197c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
207c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
217c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
227c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
237c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
247c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
257c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
267c478bd9Sstevel@tonic-gate  * Neither M.I.T., the Open Computing Security Group, nor
277c478bd9Sstevel@tonic-gate  * CyberSAFE Corporation make any representations about the suitability of
287c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
297c478bd9Sstevel@tonic-gate  * or implied warranty.
30*55fea89dSDan Cross  *
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * krb5_rd_req_decoded()
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
35159d09a2SMark Phalan #include "k5-int.h"
36159d09a2SMark Phalan #include "auth_con.h"
375e01956fSGlenn Barry #include <locale.h>
385e01956fSGlenn Barry #include <syslog.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * essentially the same as krb_rd_req, but uses a decoded AP_REQ as
427c478bd9Sstevel@tonic-gate  * the input rather than an encoded input.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate  *  Parses a KRB_AP_REQ message, returning its contents.
46*55fea89dSDan Cross  *
477c478bd9Sstevel@tonic-gate  *  server specifies the expected server's name for the ticket; if NULL, then
487c478bd9Sstevel@tonic-gate  *  any server will be accepted if the key can be found, and the caller should
497c478bd9Sstevel@tonic-gate  *  verify that the principal is something it trusts.
50*55fea89dSDan Cross  *
517c478bd9Sstevel@tonic-gate  *  rcache specifies a replay detection cache used to store authenticators and
527c478bd9Sstevel@tonic-gate  *  server names
53*55fea89dSDan Cross  *
547c478bd9Sstevel@tonic-gate  *  keyproc specifies a procedure to generate a decryption key for the
557c478bd9Sstevel@tonic-gate  *  ticket.  If keyproc is non-NULL, keyprocarg is passed to it, and the result
567c478bd9Sstevel@tonic-gate  *  used as a decryption key. If keyproc is NULL, then fetchfrom is checked;
577c478bd9Sstevel@tonic-gate  *  if it is non-NULL, it specifies a parameter name from which to retrieve the
587c478bd9Sstevel@tonic-gate  *  decryption key.  If fetchfrom is NULL, then the default key store is
597c478bd9Sstevel@tonic-gate  *  consulted.
60*55fea89dSDan Cross  *
617c478bd9Sstevel@tonic-gate  *  authdat is set to point at allocated storage structures; the caller
62*55fea89dSDan Cross  *  should free them when finished.
63*55fea89dSDan Cross  *
647c478bd9Sstevel@tonic-gate  *  returns system errors, encryption errors, replay errors
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate static krb5_error_code decrypt_authenticator
68505d05c7Sgtb 	(krb5_context, const krb5_ap_req *, krb5_authenticator **,
69505d05c7Sgtb 		   int);
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate static krb5_error_code
krb5_rd_req_decrypt_tkt_part(krb5_context context,const krb5_ap_req * req,krb5_keytab keytab)73159d09a2SMark Phalan krb5_rd_req_decrypt_tkt_part(krb5_context context, const krb5_ap_req *req, krb5_keytab keytab)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate     krb5_error_code 	  retval;
767c478bd9Sstevel@tonic-gate     krb5_enctype 	  enctype;
777c478bd9Sstevel@tonic-gate     krb5_keytab_entry 	  ktent;
78*55fea89dSDan Cross 
797c478bd9Sstevel@tonic-gate     enctype = req->ticket->enc_part.enctype;
807c478bd9Sstevel@tonic-gate 
81159d09a2SMark Phalan     /* Solaris Kerberos: */
827c478bd9Sstevel@tonic-gate     memset(&ktent, 0, sizeof(krb5_keytab_entry));
83159d09a2SMark Phalan     if ((retval = krb5_kt_get_entry(context, keytab, req->ticket->server,
84159d09a2SMark Phalan 				    req->ticket->enc_part.kvno,
85159d09a2SMark Phalan 				    enctype, &ktent)))
867c478bd9Sstevel@tonic-gate 	return retval;
877c478bd9Sstevel@tonic-gate 
88159d09a2SMark Phalan 
897c478bd9Sstevel@tonic-gate     /*
90159d09a2SMark Phalan      * Solaris Kerberos:
917c478bd9Sstevel@tonic-gate      * If we get this far then we know that the enc types are similar,
927c478bd9Sstevel@tonic-gate      * therefore we should change the enc type to match that of what
937c478bd9Sstevel@tonic-gate      * we are decrypting.
947c478bd9Sstevel@tonic-gate      */
957c478bd9Sstevel@tonic-gate     ktent.key.enctype = enctype;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate     retval = krb5_decrypt_tkt_part(context, &ktent.key, req->ticket);
98159d09a2SMark Phalan     /* Upon error, Free keytab entry first, then return */
997c478bd9Sstevel@tonic-gate 
1005e01956fSGlenn Barry     if (retval == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
1015e01956fSGlenn Barry         /* Solaris Kerberos: spruce-up the err msg */
1025e01956fSGlenn Barry         krb5_principal princ = (krb5_principal) req->ticket->server;
1035e01956fSGlenn Barry 	char *s_name = NULL;
1045e01956fSGlenn Barry 	int kret = krb5_unparse_name(context, princ, &s_name);
1055e01956fSGlenn Barry 	if (kret == 0) {
1065e01956fSGlenn Barry 	    krb5_set_error_message(context, retval,
1075e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
1085e01956fSGlenn Barry 					"AP Request ticket decrypt fail for principal '%s' (kvno=%d, enctype=%d)"),
1095e01956fSGlenn Barry 				s_name,
1105e01956fSGlenn Barry 				req->ticket->enc_part.kvno,
1115e01956fSGlenn Barry 				enctype);
1125e01956fSGlenn Barry 	   krb5_free_unparsed_name(context, s_name);
1135e01956fSGlenn Barry 	}
1145e01956fSGlenn Barry     }
115*55fea89dSDan Cross 
1167c478bd9Sstevel@tonic-gate     (void) krb5_kt_free_entry(context, &ktent);
1177c478bd9Sstevel@tonic-gate     return retval;
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1205e01956fSGlenn Barry /*
1215e01956fSGlenn Barry  * Solaris Kerberos
1225e01956fSGlenn Barry  * Same as krb5int_check_clockskew() plus return the skew in seconds.
1235e01956fSGlenn Barry  */
1245e01956fSGlenn Barry static krb5_error_code
krb5int_check_clockskew2(krb5_context context,krb5_timestamp date,krb5_timestamp * ret_skew)1255e01956fSGlenn Barry krb5int_check_clockskew2(krb5_context context,
1265e01956fSGlenn Barry 			krb5_timestamp date,
1275e01956fSGlenn Barry 			krb5_timestamp *ret_skew)
1285e01956fSGlenn Barry {
1295e01956fSGlenn Barry     krb5_timestamp currenttime, skew;
1305e01956fSGlenn Barry     krb5_error_code retval;
1315e01956fSGlenn Barry 
1325e01956fSGlenn Barry     retval = krb5_timeofday(context, &currenttime);
1335e01956fSGlenn Barry     if (retval)
1345e01956fSGlenn Barry         return retval;
1355e01956fSGlenn Barry 
1365e01956fSGlenn Barry     skew = labs((date)-currenttime);
1375e01956fSGlenn Barry     if (!(skew < context->clockskew)) {
1385e01956fSGlenn Barry         *ret_skew = skew;
1395e01956fSGlenn Barry         return KRB5KRB_AP_ERR_SKEW;
1405e01956fSGlenn Barry     }
1415e01956fSGlenn Barry 
1425e01956fSGlenn Barry     return 0;
1435e01956fSGlenn Barry }
1445e01956fSGlenn Barry 
1457c478bd9Sstevel@tonic-gate static krb5_error_code
krb5_rd_req_decoded_opt(krb5_context context,krb5_auth_context * auth_context,const krb5_ap_req * req,krb5_const_principal server,krb5_keytab keytab,krb5_flags * ap_req_options,krb5_ticket ** ticket,int check_valid_flag)146159d09a2SMark Phalan krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context,
147159d09a2SMark Phalan 			const krb5_ap_req *req, krb5_const_principal server,
148159d09a2SMark Phalan 			krb5_keytab keytab, krb5_flags *ap_req_options,
149159d09a2SMark Phalan 			krb5_ticket **ticket, int check_valid_flag)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate     krb5_error_code 	  retval = 0;
152159d09a2SMark Phalan     krb5_principal_data princ_data;
1535e01956fSGlenn Barry     krb5_timestamp	  skew = 0; /* Solaris Kerberos */
154*55fea89dSDan Cross 
155159d09a2SMark Phalan     req->ticket->enc_part2 == NULL;
156159d09a2SMark Phalan     if (server && krb5_is_referral_realm(&server->realm)) {
157159d09a2SMark Phalan 	char *realm;
158159d09a2SMark Phalan 	princ_data = *server;
159159d09a2SMark Phalan 	server = &princ_data;
160159d09a2SMark Phalan 	retval = krb5_get_default_realm(context, &realm);
161159d09a2SMark Phalan 	if (retval)
162159d09a2SMark Phalan 	    return retval;
163159d09a2SMark Phalan 	princ_data.realm.data = realm;
164159d09a2SMark Phalan 	princ_data.realm.length = strlen(realm);
165159d09a2SMark Phalan     }
166159d09a2SMark Phalan     if (server && !krb5_principal_compare(context, server, req->ticket->server)) {
167159d09a2SMark Phalan 	char *found_name = 0, *wanted_name = 0;
168159d09a2SMark Phalan 	if (krb5_unparse_name(context, server, &wanted_name) == 0
169159d09a2SMark Phalan 	    && krb5_unparse_name(context, req->ticket->server, &found_name) == 0)
170159d09a2SMark Phalan 	    krb5_set_error_message(context, KRB5KRB_AP_WRONG_PRINC,
1715e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
1725e01956fSGlenn Barry 					"Wrong principal in request (found %s, wanted %s)"),
173159d09a2SMark Phalan 				   found_name, wanted_name);
174159d09a2SMark Phalan 	krb5_free_unparsed_name(context, wanted_name);
175159d09a2SMark Phalan 	krb5_free_unparsed_name(context, found_name);
176159d09a2SMark Phalan 	retval =  KRB5KRB_AP_WRONG_PRINC;
177159d09a2SMark Phalan 	goto cleanup;
178159d09a2SMark Phalan     }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate     /* if (req->ap_options & AP_OPTS_USE_SESSION_KEY)
1817c478bd9Sstevel@tonic-gate        do we need special processing here ?	*/
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate     /* decrypt the ticket */
1847c478bd9Sstevel@tonic-gate     if ((*auth_context)->keyblock) { /* User to User authentication */
1857c478bd9Sstevel@tonic-gate     	if ((retval = krb5_decrypt_tkt_part(context, (*auth_context)->keyblock,
1867c478bd9Sstevel@tonic-gate 					    req->ticket)))
187159d09a2SMark Phalan goto cleanup;
1887c478bd9Sstevel@tonic-gate 	krb5_free_keyblock(context, (*auth_context)->keyblock);
1897c478bd9Sstevel@tonic-gate 	(*auth_context)->keyblock = NULL;
1907c478bd9Sstevel@tonic-gate     } else {
1917c478bd9Sstevel@tonic-gate     	if ((retval = krb5_rd_req_decrypt_tkt_part(context, req, keytab)))
192159d09a2SMark Phalan 	    goto cleanup;
1937c478bd9Sstevel@tonic-gate     }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate     /* XXX this is an evil hack.  check_valid_flag is set iff the call
1967c478bd9Sstevel@tonic-gate        is not from inside the kdc.  we can use this to determine which
1977c478bd9Sstevel@tonic-gate        key usage to use */
198*55fea89dSDan Cross     if ((retval = decrypt_authenticator(context, req,
1997c478bd9Sstevel@tonic-gate 					&((*auth_context)->authentp),
2007c478bd9Sstevel@tonic-gate 					check_valid_flag)))
2017c478bd9Sstevel@tonic-gate 	goto cleanup;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate     if (!krb5_principal_compare(context, (*auth_context)->authentp->client,
2047c478bd9Sstevel@tonic-gate 				req->ticket->enc_part2->client)) {
2057c478bd9Sstevel@tonic-gate 	retval = KRB5KRB_AP_ERR_BADMATCH;
2067c478bd9Sstevel@tonic-gate 	goto cleanup;
2077c478bd9Sstevel@tonic-gate     }
2087c478bd9Sstevel@tonic-gate 
209*55fea89dSDan Cross     if ((*auth_context)->remote_addr &&
210*55fea89dSDan Cross       !krb5_address_search(context, (*auth_context)->remote_addr,
2117c478bd9Sstevel@tonic-gate 			   req->ticket->enc_part2->caddrs)) {
2127c478bd9Sstevel@tonic-gate 	retval = KRB5KRB_AP_ERR_BADADDR;
2137c478bd9Sstevel@tonic-gate 	goto cleanup;
2147c478bd9Sstevel@tonic-gate     }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate     /* okay, now check cross-realm policy */
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate #if defined(_SINGLE_HOP_ONLY)
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate     /* Single hop cross-realm tickets only */
2217c478bd9Sstevel@tonic-gate 
222*55fea89dSDan Cross     {
2237c478bd9Sstevel@tonic-gate 	krb5_transited *trans = &(req->ticket->enc_part2->transited);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate       	/* If the transited list is empty, then we have at most one hop */
2267c478bd9Sstevel@tonic-gate       	if (trans->tr_contents.data && trans->tr_contents.data[0])
2277c478bd9Sstevel@tonic-gate             retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
2287c478bd9Sstevel@tonic-gate     }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate #elif defined(_NO_CROSS_REALM)
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate     /* No cross-realm tickets */
2337c478bd9Sstevel@tonic-gate 
234*55fea89dSDan Cross     {
2357c478bd9Sstevel@tonic-gate 	char		* lrealm;
2367c478bd9Sstevel@tonic-gate       	krb5_data      	* realm;
2377c478bd9Sstevel@tonic-gate       	krb5_transited 	* trans;
238*55fea89dSDan Cross 
2397c478bd9Sstevel@tonic-gate 	realm = krb5_princ_realm(context, req->ticket->enc_part2->client);
2407c478bd9Sstevel@tonic-gate 	trans = &(req->ticket->enc_part2->transited);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	/*
243*55fea89dSDan Cross       	 * If the transited list is empty, then we have at most one hop
244*55fea89dSDan Cross       	 * So we also have to check that the client's realm is the local one
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate       	krb5_get_default_realm(context, &lrealm);
2477c478bd9Sstevel@tonic-gate       	if ((trans->tr_contents.data && trans->tr_contents.data[0]) ||
2487c478bd9Sstevel@tonic-gate           strlen(lrealm) != realm->length ||
2497c478bd9Sstevel@tonic-gate           memcmp(lrealm, realm->data, strlen(lrealm))) {
2507c478bd9Sstevel@tonic-gate             retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
2517c478bd9Sstevel@tonic-gate       	}
2527c478bd9Sstevel@tonic-gate       	free(lrealm);
2537c478bd9Sstevel@tonic-gate     }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate #else
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate     /* Hierarchical Cross-Realm */
258*55fea89dSDan Cross 
2597c478bd9Sstevel@tonic-gate     {
260159d09a2SMark Phalan       	krb5_data      * realm;
261159d09a2SMark Phalan       	krb5_transited * trans;
262*55fea89dSDan Cross 
2637c478bd9Sstevel@tonic-gate 	realm = krb5_princ_realm(context, req->ticket->enc_part2->client);
2647c478bd9Sstevel@tonic-gate 	trans = &(req->ticket->enc_part2->transited);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	/*
267*55fea89dSDan Cross       	 * If the transited list is not empty, then check that all realms
268*55fea89dSDan Cross       	 * transited are within the hierarchy between the client's realm
269*55fea89dSDan Cross       	 * and the local realm.
270159d09a2SMark Phalan   	 */
2717c478bd9Sstevel@tonic-gate 	if (trans->tr_contents.data && trans->tr_contents.data[0]) {
272*55fea89dSDan Cross 	    retval = krb5_check_transited_list(context, &(trans->tr_contents),
273159d09a2SMark Phalan 					       realm,
274159d09a2SMark Phalan 					       krb5_princ_realm (context,
275159d09a2SMark Phalan 								 server));
276159d09a2SMark Phalan       	}
2777c478bd9Sstevel@tonic-gate     }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate #endif
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate     if (retval)  goto cleanup;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate     /* only check rcache if sender has provided one---some services
2847c478bd9Sstevel@tonic-gate        may not be able to use replay caches (such as datagram servers) */
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate     if ((*auth_context)->rcache) {
2877c478bd9Sstevel@tonic-gate 	krb5_donot_replay  rep;
2887c478bd9Sstevel@tonic-gate         krb5_tkt_authent   tktauthent;
2897c478bd9Sstevel@tonic-gate 
290*55fea89dSDan Cross 	tktauthent.ticket = req->ticket;
2917c478bd9Sstevel@tonic-gate 	tktauthent.authenticator = (*auth_context)->authentp;
2927c478bd9Sstevel@tonic-gate 	if (!(retval = krb5_auth_to_rep(context, &tktauthent, &rep))) {
2937c478bd9Sstevel@tonic-gate 	    retval = krb5_rc_store(context, (*auth_context)->rcache, &rep);
2947c478bd9Sstevel@tonic-gate 	    krb5_xfree(rep.server);
2957c478bd9Sstevel@tonic-gate 	    krb5_xfree(rep.client);
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
2985e01956fSGlenn Barry 	if (retval == KRB5KRB_AP_ERR_SKEW)
2995e01956fSGlenn Barry 	    goto err_skew;
3005e01956fSGlenn Barry 
3017c478bd9Sstevel@tonic-gate 	if (retval)
3027c478bd9Sstevel@tonic-gate 	    goto cleanup;
3037c478bd9Sstevel@tonic-gate     }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate     retval = krb5_validate_times(context, &req->ticket->enc_part2->times);
3067c478bd9Sstevel@tonic-gate     if (retval != 0)
3077c478bd9Sstevel@tonic-gate 	    goto cleanup;
3087c478bd9Sstevel@tonic-gate 
3095e01956fSGlenn Barry err_skew:
3105e01956fSGlenn Barry     if ((retval = krb5int_check_clockskew2(context,
3115e01956fSGlenn Barry 					(*auth_context)->authentp->ctime,
3125e01956fSGlenn Barry 					&skew))) {
3135e01956fSGlenn Barry         /* Solaris Kerberos */
3145e01956fSGlenn Barry         char *s_name = NULL;
3155e01956fSGlenn Barry         char *c_name = NULL;
3165e01956fSGlenn Barry 	krb5_error_code serr, cerr;
3175e01956fSGlenn Barry 	serr = krb5_unparse_name(context, req->ticket->server, &s_name);
3185e01956fSGlenn Barry 	cerr = krb5_unparse_name(context, req->ticket->enc_part2->client,
3195e01956fSGlenn Barry 				&c_name);
3205e01956fSGlenn Barry 	krb5_set_error_message(context, retval,
3215e01956fSGlenn Barry 			    dgettext(TEXT_DOMAIN,
3225e01956fSGlenn Barry 				    "Clock skew too great: client '%s' AP request with ticket for '%s'. Skew is %dm (allowable %dm)."),
3235e01956fSGlenn Barry 			    cerr == 0 ? c_name : "unknown",
3245e01956fSGlenn Barry 			    serr == 0 ? s_name : "unknown",
3255e01956fSGlenn Barry 			    skew > 0 ? skew/60 : 0,
3265e01956fSGlenn Barry 			    context->clockskew > 0 ? context->clockskew/60 : 0);
3275e01956fSGlenn Barry 	if (s_name)
3285e01956fSGlenn Barry 	    krb5_free_unparsed_name(context, s_name);
3295e01956fSGlenn Barry 	if (c_name)
3305e01956fSGlenn Barry 	    krb5_free_unparsed_name(context, c_name);
3315e01956fSGlenn Barry         goto cleanup;
3327c478bd9Sstevel@tonic-gate     }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate     if (check_valid_flag) {
3355e01956fSGlenn Barry         if (req->ticket->enc_part2->flags & TKT_FLG_INVALID) {
3365e01956fSGlenn Barry 	    /* Solaris Kerberos */
3375e01956fSGlenn Barry 	    char *s_name = NULL;
3385e01956fSGlenn Barry 	    int err = krb5_unparse_name(context, req->ticket->server, &s_name);
3395e01956fSGlenn Barry 	    retval = KRB5KRB_AP_ERR_TKT_INVALID;
3405e01956fSGlenn Barry 	    if (!err) {
3415e01956fSGlenn Barry 	        krb5_set_error_message(context, retval,
3425e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
3435e01956fSGlenn Barry 				    "Ticket has invalid flag set for server '%s'"),
3445e01956fSGlenn Barry 				    s_name);
3455e01956fSGlenn Barry 	        krb5_free_unparsed_name(context, s_name);
3465e01956fSGlenn Barry 	    }
3475e01956fSGlenn Barry 	    goto cleanup;
3485e01956fSGlenn Barry 	}
3497c478bd9Sstevel@tonic-gate     }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate     /* check if the various etypes are permitted */
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate     if ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) {
3547c478bd9Sstevel@tonic-gate 	/* no etype check needed */
3557c478bd9Sstevel@tonic-gate 	/*EMPTY*/
3567c478bd9Sstevel@tonic-gate 	;
3577c478bd9Sstevel@tonic-gate     } else if ((*auth_context)->permitted_etypes == NULL) {
358159d09a2SMark Phalan 	int etype;
3597c478bd9Sstevel@tonic-gate 	/* check against the default set */
3607c478bd9Sstevel@tonic-gate 	if ((!krb5_is_permitted_enctype(context,
361159d09a2SMark Phalan 					etype = req->ticket->enc_part.enctype)) ||
3627c478bd9Sstevel@tonic-gate 	    (!krb5_is_permitted_enctype(context,
363159d09a2SMark Phalan 					etype = req->ticket->enc_part2->session->enctype)) ||
3647c478bd9Sstevel@tonic-gate 	    (((*auth_context)->authentp->subkey) &&
3657c478bd9Sstevel@tonic-gate 	     !krb5_is_permitted_enctype(context,
366159d09a2SMark Phalan 					etype = (*auth_context)->authentp->subkey->enctype))) {
367159d09a2SMark Phalan 	    char enctype_name[30];
3687c478bd9Sstevel@tonic-gate 	    retval = KRB5_NOPERM_ETYPE;
369159d09a2SMark Phalan 	    if (krb5_enctype_to_string(etype, enctype_name, sizeof(enctype_name)) == 0)
370159d09a2SMark Phalan 		krb5_set_error_message(context, retval,
3715e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
3725e01956fSGlenn Barry 					    "Encryption type %s not permitted"),
3735e01956fSGlenn Barry 				    enctype_name);
3747c478bd9Sstevel@tonic-gate 	    goto cleanup;
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate     } else {
3777c478bd9Sstevel@tonic-gate 	/* check against the set in the auth_context */
3787c478bd9Sstevel@tonic-gate 	int i;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	for (i=0; (*auth_context)->permitted_etypes[i]; i++)
3817c478bd9Sstevel@tonic-gate 	    if ((*auth_context)->permitted_etypes[i] ==
3827c478bd9Sstevel@tonic-gate 		req->ticket->enc_part.enctype)
3837c478bd9Sstevel@tonic-gate 		break;
3847c478bd9Sstevel@tonic-gate 	if (!(*auth_context)->permitted_etypes[i]) {
385159d09a2SMark Phalan 	    char enctype_name[30];
3867c478bd9Sstevel@tonic-gate 	    retval = KRB5_NOPERM_ETYPE;
387159d09a2SMark Phalan 	    if (krb5_enctype_to_string(req->ticket->enc_part.enctype,
388159d09a2SMark Phalan 				       enctype_name, sizeof(enctype_name)) == 0)
389159d09a2SMark Phalan 		krb5_set_error_message(context, retval,
3905e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
3915e01956fSGlenn Barry 					    "Encryption type %s not permitted"),
3925e01956fSGlenn Barry 				    enctype_name);
3937c478bd9Sstevel@tonic-gate 	    goto cleanup;
3947c478bd9Sstevel@tonic-gate 	}
395*55fea89dSDan Cross 
3967c478bd9Sstevel@tonic-gate 	for (i=0; (*auth_context)->permitted_etypes[i]; i++)
3977c478bd9Sstevel@tonic-gate 	    if ((*auth_context)->permitted_etypes[i] ==
3987c478bd9Sstevel@tonic-gate 		req->ticket->enc_part2->session->enctype)
3997c478bd9Sstevel@tonic-gate 		break;
4007c478bd9Sstevel@tonic-gate 	if (!(*auth_context)->permitted_etypes[i]) {
401159d09a2SMark Phalan 	    char enctype_name[30];
4027c478bd9Sstevel@tonic-gate 	    retval = KRB5_NOPERM_ETYPE;
403159d09a2SMark Phalan 	    if (krb5_enctype_to_string(req->ticket->enc_part2->session->enctype,
404159d09a2SMark Phalan 				       enctype_name, sizeof(enctype_name)) == 0)
405159d09a2SMark Phalan 		krb5_set_error_message(context, retval,
4065e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
4075e01956fSGlenn Barry 					    "Encryption type %s not permitted"),
4085e01956fSGlenn Barry 				    enctype_name);
4097c478bd9Sstevel@tonic-gate 	    goto cleanup;
4107c478bd9Sstevel@tonic-gate 	}
411*55fea89dSDan Cross 
4127c478bd9Sstevel@tonic-gate 	if ((*auth_context)->authentp->subkey) {
4137c478bd9Sstevel@tonic-gate 	    for (i=0; (*auth_context)->permitted_etypes[i]; i++)
4147c478bd9Sstevel@tonic-gate 		if ((*auth_context)->permitted_etypes[i] ==
4157c478bd9Sstevel@tonic-gate 		    (*auth_context)->authentp->subkey->enctype)
4167c478bd9Sstevel@tonic-gate 		    break;
4177c478bd9Sstevel@tonic-gate 	    if (!(*auth_context)->permitted_etypes[i]) {
418159d09a2SMark Phalan 		char enctype_name[30];
4197c478bd9Sstevel@tonic-gate 		retval = KRB5_NOPERM_ETYPE;
420159d09a2SMark Phalan 		if (krb5_enctype_to_string((*auth_context)->authentp->subkey->enctype,
421159d09a2SMark Phalan 					   enctype_name,
422159d09a2SMark Phalan 					   sizeof(enctype_name)) == 0)
423159d09a2SMark Phalan 		    krb5_set_error_message(context, retval,
4245e01956fSGlenn Barry 					dgettext(TEXT_DOMAIN,
4255e01956fSGlenn Barry 					    "Encryption type %s not permitted"),
4265e01956fSGlenn Barry 					enctype_name);
4277c478bd9Sstevel@tonic-gate 		goto cleanup;
4287c478bd9Sstevel@tonic-gate 	    }
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate     }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate     (*auth_context)->remote_seq_number = (*auth_context)->authentp->seq_number;
4337c478bd9Sstevel@tonic-gate     if ((*auth_context)->authentp->subkey) {
434159d09a2SMark Phalan 	/* Solaris Kerberos */
4357c478bd9Sstevel@tonic-gate 	if ((*auth_context)->recv_subkey != NULL) {
4367c478bd9Sstevel@tonic-gate 	    krb5_free_keyblock(context, (*auth_context)->recv_subkey);
4377c478bd9Sstevel@tonic-gate 	    (*auth_context)->recv_subkey = NULL;
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	if ((retval = krb5_copy_keyblock(context,
4417c478bd9Sstevel@tonic-gate 					 (*auth_context)->authentp->subkey,
4427c478bd9Sstevel@tonic-gate 					 &((*auth_context)->recv_subkey))))
4437c478bd9Sstevel@tonic-gate 	    goto cleanup;
444159d09a2SMark Phalan 	/* Solaris Kerberos */
4457c478bd9Sstevel@tonic-gate 	if ((*auth_context)->send_subkey != NULL) {
4467c478bd9Sstevel@tonic-gate 	    krb5_free_keyblock(context, (*auth_context)->send_subkey);
4477c478bd9Sstevel@tonic-gate 	    (*auth_context)->send_subkey = NULL;
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	retval = krb5_copy_keyblock(context, (*auth_context)->authentp->subkey,
451159d09a2SMark Phalan 				    &((*auth_context)->send_subkey));
4527c478bd9Sstevel@tonic-gate 	if (retval) {
453159d09a2SMark Phalan 	    krb5_free_keyblock(context, (*auth_context)->recv_subkey);
454159d09a2SMark Phalan 	    (*auth_context)->recv_subkey = NULL;
455159d09a2SMark Phalan 	    goto cleanup;
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate     } else {
4587c478bd9Sstevel@tonic-gate 	(*auth_context)->recv_subkey = 0;
4597c478bd9Sstevel@tonic-gate 	(*auth_context)->send_subkey = 0;
4607c478bd9Sstevel@tonic-gate     }
461159d09a2SMark Phalan     /* Solaris Kerberos */
4627c478bd9Sstevel@tonic-gate     if ((*auth_context)->keyblock != NULL) {
4637c478bd9Sstevel@tonic-gate 	krb5_free_keyblock(context, (*auth_context)->keyblock);
4647c478bd9Sstevel@tonic-gate 	(*auth_context)->keyblock = NULL;
4657c478bd9Sstevel@tonic-gate     }
4667c478bd9Sstevel@tonic-gate     if ((retval = krb5_copy_keyblock(context, req->ticket->enc_part2->session,
4677c478bd9Sstevel@tonic-gate 				     &((*auth_context)->keyblock))))
4687c478bd9Sstevel@tonic-gate 	goto cleanup;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate     /*
471*55fea89dSDan Cross      * If not AP_OPTS_MUTUAL_REQUIRED then and sequence numbers are used
4727c478bd9Sstevel@tonic-gate      * then the default sequence number is the one's complement of the
4737c478bd9Sstevel@tonic-gate      * sequence number sent ot us.
4747c478bd9Sstevel@tonic-gate      */
475*55fea89dSDan Cross     if ((!(req->ap_options & AP_OPTS_MUTUAL_REQUIRED)) &&
4767c478bd9Sstevel@tonic-gate       (*auth_context)->remote_seq_number) {
477*55fea89dSDan Cross 	(*auth_context)->local_seq_number ^=
4787c478bd9Sstevel@tonic-gate 	  (*auth_context)->remote_seq_number;
4797c478bd9Sstevel@tonic-gate     }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate     if (ticket)
4827c478bd9Sstevel@tonic-gate    	if ((retval = krb5_copy_ticket(context, req->ticket, ticket)))
4837c478bd9Sstevel@tonic-gate 	    goto cleanup;
4847c478bd9Sstevel@tonic-gate     if (ap_req_options)
4857c478bd9Sstevel@tonic-gate     	*ap_req_options = req->ap_options;
4867c478bd9Sstevel@tonic-gate     retval = 0;
487*55fea89dSDan Cross 
4887c478bd9Sstevel@tonic-gate cleanup:
489159d09a2SMark Phalan     if (server == &princ_data)
490159d09a2SMark Phalan 	krb5_free_default_realm(context, princ_data.realm.data);
4917c478bd9Sstevel@tonic-gate     if (retval) {
4927c478bd9Sstevel@tonic-gate 	/* only free if we're erroring out...otherwise some
4937c478bd9Sstevel@tonic-gate 	   applications will need the output. */
494159d09a2SMark Phalan 	if (req->ticket->enc_part2)
495159d09a2SMark Phalan 	    krb5_free_enc_tkt_part(context, req->ticket->enc_part2);
4967c478bd9Sstevel@tonic-gate 	req->ticket->enc_part2 = NULL;
4977c478bd9Sstevel@tonic-gate     }
4987c478bd9Sstevel@tonic-gate     return retval;
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate krb5_error_code
krb5_rd_req_decoded(krb5_context context,krb5_auth_context * auth_context,const krb5_ap_req * req,krb5_const_principal server,krb5_keytab keytab,krb5_flags * ap_req_options,krb5_ticket ** ticket)502159d09a2SMark Phalan krb5_rd_req_decoded(krb5_context context, krb5_auth_context *auth_context,
503159d09a2SMark Phalan 		    const krb5_ap_req *req, krb5_const_principal server,
504159d09a2SMark Phalan 		    krb5_keytab keytab, krb5_flags *ap_req_options,
505159d09a2SMark Phalan 		    krb5_ticket **ticket)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate   krb5_error_code retval;
5087c478bd9Sstevel@tonic-gate   retval = krb5_rd_req_decoded_opt(context, auth_context,
509*55fea89dSDan Cross 				   req, server, keytab,
5107c478bd9Sstevel@tonic-gate 				   ap_req_options, ticket,
5117c478bd9Sstevel@tonic-gate 				   1); /* check_valid_flag */
5127c478bd9Sstevel@tonic-gate   return retval;
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate krb5_error_code
krb5_rd_req_decoded_anyflag(krb5_context context,krb5_auth_context * auth_context,const krb5_ap_req * req,krb5_const_principal server,krb5_keytab keytab,krb5_flags * ap_req_options,krb5_ticket ** ticket)516159d09a2SMark Phalan krb5_rd_req_decoded_anyflag(krb5_context context,
517159d09a2SMark Phalan 			    krb5_auth_context *auth_context,
518159d09a2SMark Phalan 			    const krb5_ap_req *req,
519159d09a2SMark Phalan 			    krb5_const_principal server, krb5_keytab keytab,
520159d09a2SMark Phalan 			    krb5_flags *ap_req_options, krb5_ticket **ticket)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate   krb5_error_code retval;
5237c478bd9Sstevel@tonic-gate   retval = krb5_rd_req_decoded_opt(context, auth_context,
524*55fea89dSDan Cross 				   req, server, keytab,
5257c478bd9Sstevel@tonic-gate 				   ap_req_options, ticket,
5267c478bd9Sstevel@tonic-gate 				   0); /* don't check_valid_flag */
5277c478bd9Sstevel@tonic-gate   return retval;
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5317c478bd9Sstevel@tonic-gate static krb5_error_code
decrypt_authenticator(krb5_context context,const krb5_ap_req * request,krb5_authenticator ** authpp,int is_ap_req)532159d09a2SMark Phalan decrypt_authenticator(krb5_context context, const krb5_ap_req *request,
533159d09a2SMark Phalan 		      krb5_authenticator **authpp, int is_ap_req)
5347c478bd9Sstevel@tonic-gate {
5357c478bd9Sstevel@tonic-gate     krb5_authenticator *local_auth;
5367c478bd9Sstevel@tonic-gate     krb5_error_code retval;
5377c478bd9Sstevel@tonic-gate     krb5_data scratch;
5387c478bd9Sstevel@tonic-gate     krb5_keyblock *sesskey;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate     sesskey = request->ticket->enc_part2->session;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate     scratch.length = request->authenticator.ciphertext.length;
5437c478bd9Sstevel@tonic-gate     if (!(scratch.data = malloc(scratch.length)))
5447c478bd9Sstevel@tonic-gate 	return(ENOMEM);
5457c478bd9Sstevel@tonic-gate 
546159d09a2SMark Phalan     if ((retval = krb5_c_decrypt(context, sesskey,
5477c478bd9Sstevel@tonic-gate 				 is_ap_req?KRB5_KEYUSAGE_AP_REQ_AUTH:
5487c478bd9Sstevel@tonic-gate 				 KRB5_KEYUSAGE_TGS_REQ_AUTH, 0,
549159d09a2SMark Phalan 				 &request->authenticator, &scratch))) {
5507c478bd9Sstevel@tonic-gate 	free(scratch.data);
5517c478bd9Sstevel@tonic-gate 	return(retval);
5527c478bd9Sstevel@tonic-gate     }
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate #define clean_scratch() {memset(scratch.data, 0, scratch.length); \
5557c478bd9Sstevel@tonic-gate free(scratch.data);}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate     /*  now decode the decrypted stuff */
5587c478bd9Sstevel@tonic-gate     if (!(retval = decode_krb5_authenticator(&scratch, &local_auth))) {
5597c478bd9Sstevel@tonic-gate 	*authpp = local_auth;
5607c478bd9Sstevel@tonic-gate     }
5617c478bd9Sstevel@tonic-gate     clean_scratch();
5627c478bd9Sstevel@tonic-gate     return retval;
5637c478bd9Sstevel@tonic-gate }
564ba7b222eSGlenn Barry 
565ba7b222eSGlenn Barry krb5_error_code
krb5int_check_clockskew(krb5_context context,krb5_timestamp date)566ba7b222eSGlenn Barry krb5int_check_clockskew(krb5_context context, krb5_timestamp date)
567ba7b222eSGlenn Barry {
568ba7b222eSGlenn Barry     krb5_timestamp currenttime;
569ba7b222eSGlenn Barry     krb5_error_code retval;
570ba7b222eSGlenn Barry 
571ba7b222eSGlenn Barry     retval = krb5_timeofday(context, &currenttime);
572ba7b222eSGlenn Barry     if (retval)
573ba7b222eSGlenn Barry         return retval;
574ba7b222eSGlenn Barry     if (!(labs((date)-currenttime) < context->clockskew))
575ba7b222eSGlenn Barry         return KRB5KRB_AP_ERR_SKEW;
576ba7b222eSGlenn Barry     return 0;
577ba7b222eSGlenn Barry }
578