17c478bd9Sstevel@tonic-gate /*
212b65585SGordon Ross  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3cfed4d70SMatt Barden  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
412b65585SGordon Ross  */
57c478bd9Sstevel@tonic-gate /*
67c478bd9Sstevel@tonic-gate  * lib/krb5/krb/get_in_tkt.c
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Copyright 1990,1991, 2003 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  * M.I.T. makes no representations about the suitability of
277c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
287c478bd9Sstevel@tonic-gate  * or implied warranty.
29*55fea89dSDan Cross  *
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * krb5_get_in_tkt()
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <string.h>
355e01956fSGlenn Barry #include <ctype.h>
36159d09a2SMark Phalan #include "k5-int.h"
37159d09a2SMark Phalan #include "int-proto.h"
38159d09a2SMark Phalan #include "os-proto.h"
395e01956fSGlenn Barry #include <locale.h>
405e01956fSGlenn Barry #include <syslog.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  All-purpose initial ticket routine, usually called via
447c478bd9Sstevel@tonic-gate  krb5_get_in_tkt_with_password or krb5_get_in_tkt_with_skey.
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate  Attempts to get an initial ticket for creds->client to use server
477c478bd9Sstevel@tonic-gate  creds->server, (realm is taken from creds->client), with options
487c478bd9Sstevel@tonic-gate  options, and using creds->times.starttime, creds->times.endtime,
49*55fea89dSDan Cross  creds->times.renew_till as from, till, and rtime.
507c478bd9Sstevel@tonic-gate  creds->times.renew_till is ignored unless the RENEWABLE option is requested.
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate  key_proc is called to fill in the key to be used for decryption.
537c478bd9Sstevel@tonic-gate  keyseed is passed on to key_proc.
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate  decrypt_proc is called to perform the decryption of the response (the
567c478bd9Sstevel@tonic-gate  encrypted part is in dec_rep->enc_part; the decrypted part should be
577c478bd9Sstevel@tonic-gate  allocated and filled into dec_rep->enc_part2
587c478bd9Sstevel@tonic-gate  arg is passed on to decrypt_proc.
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate  If addrs is non-NULL, it is used for the addresses requested.  If it is
617c478bd9Sstevel@tonic-gate  null, the system standard addresses are used.
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate  A succesful call will place the ticket in the credentials cache ccache
647c478bd9Sstevel@tonic-gate  and fill in creds with the ticket information used/returned..
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate  returns system errors, encryption errors
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate 
70159d09a2SMark Phalan /* Solaris Kerberos */
713441f6a1Ssemery #define	max(a, b)	((a) > (b) ? (a) : (b))
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /* some typedef's for the function args to make things look a bit cleaner */
747c478bd9Sstevel@tonic-gate 
75505d05c7Sgtb typedef krb5_error_code (*git_key_proc) (krb5_context,
767c478bd9Sstevel@tonic-gate 						   const krb5_enctype,
777c478bd9Sstevel@tonic-gate 						   krb5_data *,
787c478bd9Sstevel@tonic-gate 						   krb5_const_pointer,
79505d05c7Sgtb 						   krb5_keyblock **);
807c478bd9Sstevel@tonic-gate 
81505d05c7Sgtb typedef krb5_error_code (*git_decrypt_proc) (krb5_context,
827c478bd9Sstevel@tonic-gate 						       const krb5_keyblock *,
837c478bd9Sstevel@tonic-gate 						       krb5_const_pointer,
84159d09a2SMark Phalan 						       krb5_kdc_rep * );
857c478bd9Sstevel@tonic-gate 
86*55fea89dSDan Cross static krb5_error_code make_preauth_list (krb5_context,
877c478bd9Sstevel@tonic-gate 						    krb5_preauthtype *,
88505d05c7Sgtb 						    int, krb5_pa_data ***);
89159d09a2SMark Phalan static krb5_error_code sort_krb5_padata_sequence(krb5_context context,
90159d09a2SMark Phalan 						 krb5_data *realm,
91159d09a2SMark Phalan 						 krb5_pa_data **padata);
92505d05c7Sgtb 
93505d05c7Sgtb /*
94505d05c7Sgtb  * This function performs 32 bit bounded addition so we can generate
95505d05c7Sgtb  * lifetimes without overflowing krb5_int32
96505d05c7Sgtb  */
krb5int_addint32(krb5_int32 x,krb5_int32 y)97505d05c7Sgtb static krb5_int32 krb5int_addint32 (krb5_int32 x, krb5_int32 y)
98505d05c7Sgtb {
99505d05c7Sgtb     if ((x > 0) && (y > (KRB5_INT32_MAX - x))) {
100505d05c7Sgtb         /* sum will be be greater than KRB5_INT32_MAX */
101505d05c7Sgtb         return KRB5_INT32_MAX;
102505d05c7Sgtb     } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) {
103505d05c7Sgtb         /* sum will be less than KRB5_INT32_MIN */
104505d05c7Sgtb         return KRB5_INT32_MIN;
105505d05c7Sgtb     }
106*55fea89dSDan Cross 
107505d05c7Sgtb     return x + y;
108505d05c7Sgtb }
109505d05c7Sgtb 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * This function sends a request to the KDC, and gets back a response;
1127c478bd9Sstevel@tonic-gate  * the response is parsed into ret_err_reply or ret_as_reply if the
1137c478bd9Sstevel@tonic-gate  * reponse is a KRB_ERROR or a KRB_AS_REP packet.  If it is some other
1147c478bd9Sstevel@tonic-gate  * unexpected response, an error is returned.
1157c478bd9Sstevel@tonic-gate  */
1167c478bd9Sstevel@tonic-gate static krb5_error_code
send_as_request2(krb5_context context,krb5_kdc_req * request,krb5_error ** ret_err_reply,krb5_kdc_rep ** ret_as_reply,int * use_master,char ** hostname_used)1175e01956fSGlenn Barry send_as_request2(krb5_context 		context,
118505d05c7Sgtb 		krb5_kdc_req		*request,
119505d05c7Sgtb 		krb5_error ** 		ret_err_reply,
120505d05c7Sgtb 		krb5_kdc_rep ** 	ret_as_reply,
1215e01956fSGlenn Barry 		int 			*use_master,
1225e01956fSGlenn Barry 		char			**hostname_used)
1235e01956fSGlenn Barry 
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate     krb5_kdc_rep *as_reply = 0;
1267c478bd9Sstevel@tonic-gate     krb5_error_code retval;
1277c478bd9Sstevel@tonic-gate     krb5_data *packet = 0;
1287c478bd9Sstevel@tonic-gate     krb5_data reply;
1297c478bd9Sstevel@tonic-gate     char k4_version;		/* same type as *(krb5_data::data) */
1307c478bd9Sstevel@tonic-gate     int tcp_only = 0;
131159d09a2SMark Phalan     krb5_timestamp time_now;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate     reply.data = 0;
1347c478bd9Sstevel@tonic-gate 
13512b65585SGordon Ross     /* Solaris Kerberos (illumos) */
13612b65585SGordon Ross     if (krb5_getenv("MS_INTEROP")) {
13712b65585SGordon Ross         /* Don't bother with UDP. */
13812b65585SGordon Ross         tcp_only = 1;
13912b65585SGordon Ross     }
14012b65585SGordon Ross 
141159d09a2SMark Phalan     /* set the nonce if the caller expects us to do it */
142159d09a2SMark Phalan     if (request->nonce == 0) {
143159d09a2SMark Phalan         if ((retval = krb5_timeofday(context, &time_now)))
144159d09a2SMark Phalan 	    goto cleanup;
145159d09a2SMark Phalan         request->nonce = (krb5_int32) time_now;
146159d09a2SMark Phalan     }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate     /* encode & send to KDC */
1497c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_as_req(request, &packet)) != 0)
1507c478bd9Sstevel@tonic-gate 	goto cleanup;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate     k4_version = packet->data[0];
1537c478bd9Sstevel@tonic-gate send_again:
154*55fea89dSDan Cross     retval = krb5_sendto_kdc2(context, packet,
1555e01956fSGlenn Barry 			    krb5_princ_realm(context, request->client),
1565e01956fSGlenn Barry 			    &reply, use_master, tcp_only, hostname_used);
1577c478bd9Sstevel@tonic-gate     if (retval)
1587c478bd9Sstevel@tonic-gate 	goto cleanup;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate     /* now decode the reply...could be error or as_rep */
1617c478bd9Sstevel@tonic-gate     if (krb5_is_krb_error(&reply)) {
1627c478bd9Sstevel@tonic-gate 	krb5_error *err_reply;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if ((retval = decode_krb5_error(&reply, &err_reply)))
165*55fea89dSDan Cross 	    /* some other error code--??? */
1667c478bd9Sstevel@tonic-gate 	    goto cleanup;
167*55fea89dSDan Cross 
1687c478bd9Sstevel@tonic-gate 	if (ret_err_reply) {
1697c478bd9Sstevel@tonic-gate 	    if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG
1707c478bd9Sstevel@tonic-gate 		&& tcp_only == 0) {
1717c478bd9Sstevel@tonic-gate 		tcp_only = 1;
1727c478bd9Sstevel@tonic-gate 		krb5_free_error(context, err_reply);
1737c478bd9Sstevel@tonic-gate 		free(reply.data);
1747c478bd9Sstevel@tonic-gate 		reply.data = 0;
1757c478bd9Sstevel@tonic-gate 		goto send_again;
1767c478bd9Sstevel@tonic-gate 	    }
1777c478bd9Sstevel@tonic-gate 	    *ret_err_reply = err_reply;
1785e01956fSGlenn Barry 	} else {
1797c478bd9Sstevel@tonic-gate 	    krb5_free_error(context, err_reply);
1805e01956fSGlenn Barry 	    err_reply = NULL;
1815e01956fSGlenn Barry 	}
1827c478bd9Sstevel@tonic-gate 	goto cleanup;
1837c478bd9Sstevel@tonic-gate     }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate     /*
1867c478bd9Sstevel@tonic-gate      * Check to make sure it isn't a V4 reply.
1877c478bd9Sstevel@tonic-gate      */
1887c478bd9Sstevel@tonic-gate     if (!krb5_is_as_rep(&reply)) {
1897c478bd9Sstevel@tonic-gate /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
1907c478bd9Sstevel@tonic-gate #define V4_KRB_PROT_VERSION	4
1917c478bd9Sstevel@tonic-gate #define V4_AUTH_MSG_ERR_REPLY	(5<<1)
1927c478bd9Sstevel@tonic-gate 	/* check here for V4 reply */
1937c478bd9Sstevel@tonic-gate 	unsigned int t_switch;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	/* From v4 g_in_tkt.c: This used to be
1967c478bd9Sstevel@tonic-gate 	   switch (pkt_msg_type(rpkt) & ~1) {
1977c478bd9Sstevel@tonic-gate 	   but SCO 3.2v4 cc compiled that incorrectly.  */
1987c478bd9Sstevel@tonic-gate 	t_switch = reply.data[1];
1997c478bd9Sstevel@tonic-gate 	t_switch &= ~1;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if (t_switch == V4_AUTH_MSG_ERR_REPLY
2027c478bd9Sstevel@tonic-gate 	    && (reply.data[0] == V4_KRB_PROT_VERSION
2037c478bd9Sstevel@tonic-gate 		|| reply.data[0] == k4_version)) {
2047c478bd9Sstevel@tonic-gate 	    retval = KRB5KRB_AP_ERR_V4_REPLY;
2057c478bd9Sstevel@tonic-gate 	} else {
2067c478bd9Sstevel@tonic-gate 	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 	goto cleanup;
2097c478bd9Sstevel@tonic-gate     }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate     /* It must be a KRB_AS_REP message, or an bad returned packet */
2127c478bd9Sstevel@tonic-gate     if ((retval = decode_krb5_as_rep(&reply, &as_reply)))
2137c478bd9Sstevel@tonic-gate 	/* some other error code ??? */
2147c478bd9Sstevel@tonic-gate 	goto cleanup;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate     if (as_reply->msg_type != KRB5_AS_REP) {
2177c478bd9Sstevel@tonic-gate 	retval = KRB5KRB_AP_ERR_MSG_TYPE;
2187c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, as_reply);
2197c478bd9Sstevel@tonic-gate 	goto cleanup;
2207c478bd9Sstevel@tonic-gate     }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate     if (ret_as_reply)
2237c478bd9Sstevel@tonic-gate 	*ret_as_reply = as_reply;
2247c478bd9Sstevel@tonic-gate     else
2257c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, as_reply);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate cleanup:
2287c478bd9Sstevel@tonic-gate     if (packet)
2297c478bd9Sstevel@tonic-gate 	krb5_free_data(context, packet);
2307c478bd9Sstevel@tonic-gate     if (reply.data)
2317c478bd9Sstevel@tonic-gate 	free(reply.data);
2327c478bd9Sstevel@tonic-gate     return retval;
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2355e01956fSGlenn Barry static krb5_error_code
send_as_request(krb5_context context,krb5_kdc_req * request,krb5_error ** ret_err_reply,krb5_kdc_rep ** ret_as_reply,int * use_master)2365e01956fSGlenn Barry send_as_request(krb5_context 		context,
2375e01956fSGlenn Barry 		krb5_kdc_req		*request,
2385e01956fSGlenn Barry 		krb5_error ** 		ret_err_reply,
2395e01956fSGlenn Barry 		krb5_kdc_rep ** 	ret_as_reply,
2405e01956fSGlenn Barry 		int 			    *use_master)
2415e01956fSGlenn Barry {
2425e01956fSGlenn Barry 	return send_as_request2(context,
2435e01956fSGlenn Barry 			    request,
2445e01956fSGlenn Barry 			    ret_err_reply,
2455e01956fSGlenn Barry 			    ret_as_reply,
2465e01956fSGlenn Barry 			    use_master,
2475e01956fSGlenn Barry 			    NULL);
2485e01956fSGlenn Barry }
2495e01956fSGlenn Barry 
2507c478bd9Sstevel@tonic-gate static krb5_error_code
decrypt_as_reply(krb5_context context,krb5_kdc_req * request,krb5_kdc_rep * as_reply,git_key_proc key_proc,krb5_const_pointer keyseed,krb5_keyblock * key,git_decrypt_proc decrypt_proc,krb5_const_pointer decryptarg)251505d05c7Sgtb decrypt_as_reply(krb5_context 		context,
252505d05c7Sgtb 		 krb5_kdc_req		*request,
253505d05c7Sgtb 		 krb5_kdc_rep		*as_reply,
254505d05c7Sgtb 		 git_key_proc 		key_proc,
255505d05c7Sgtb 		 krb5_const_pointer 	keyseed,
256505d05c7Sgtb 		 krb5_keyblock *	key,
257505d05c7Sgtb 		 git_decrypt_proc 	decrypt_proc,
258505d05c7Sgtb 		 krb5_const_pointer 	decryptarg)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate     krb5_error_code		retval;
2617c478bd9Sstevel@tonic-gate     krb5_keyblock *		decrypt_key = 0;
2627c478bd9Sstevel@tonic-gate     krb5_data 			salt;
263*55fea89dSDan Cross 
2647c478bd9Sstevel@tonic-gate     if (as_reply->enc_part2)
2657c478bd9Sstevel@tonic-gate 	return 0;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate     if (key)
2687c478bd9Sstevel@tonic-gate 	    decrypt_key = key;
269159d09a2SMark Phalan     /* Solaris Kerberos */
2707c478bd9Sstevel@tonic-gate     else if (request != NULL) {
2717c478bd9Sstevel@tonic-gate 	if ((retval = krb5_principal2salt(context, request->client, &salt)))
2727c478bd9Sstevel@tonic-gate 	    return(retval);
273*55fea89dSDan Cross 
2747c478bd9Sstevel@tonic-gate 	retval = (*key_proc)(context, as_reply->enc_part.enctype,
2757c478bd9Sstevel@tonic-gate 			     &salt, keyseed, &decrypt_key);
2767c478bd9Sstevel@tonic-gate 	krb5_xfree(salt.data);
2777c478bd9Sstevel@tonic-gate 	if (retval)
2787c478bd9Sstevel@tonic-gate 	    goto cleanup;
2797c478bd9Sstevel@tonic-gate     } else {
2807c478bd9Sstevel@tonic-gate 	KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, "
2817c478bd9Sstevel@tonic-gate 		"error key == NULL and request == NULL");
2827c478bd9Sstevel@tonic-gate 	return (EINVAL);
2837c478bd9Sstevel@tonic-gate     }
2847c478bd9Sstevel@tonic-gate 
285159d09a2SMark Phalan     /*
286159d09a2SMark Phalan      * Solaris kerberos: Overwriting the decrypt_key->enctype because the
2877c478bd9Sstevel@tonic-gate      * decrypt key's enctype may not be an exact match with the enctype that the
2887c478bd9Sstevel@tonic-gate      * KDC used to encrypt this part of the AS reply.  This assumes the
2897c478bd9Sstevel@tonic-gate      * as_reply->enc_part.enctype has been validated which is done by checking
2907c478bd9Sstevel@tonic-gate      * to see if the enctype that the KDC sent back in the as_reply is one of
2917c478bd9Sstevel@tonic-gate      * the enctypes originally requested.  Note, if request is NULL then the
2927c478bd9Sstevel@tonic-gate      * as_reply->enc_part.enctype could not be validated.
2937c478bd9Sstevel@tonic-gate      */
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate     if (request != NULL) {
2967c478bd9Sstevel@tonic-gate         if (is_in_keytype(request->ktype, request->nktypes,
2977c478bd9Sstevel@tonic-gate                 as_reply->enc_part.enctype)) {
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	    decrypt_key->enctype = as_reply->enc_part.enctype;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	} else {
3027c478bd9Sstevel@tonic-gate 	    KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, "
3037c478bd9Sstevel@tonic-gate 		    "error is_in_keytype() returned false");
3047c478bd9Sstevel@tonic-gate 	    retval = KRB5_BAD_ENCTYPE;
3057c478bd9Sstevel@tonic-gate 	    goto cleanup;
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate     }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate     if ((retval = (*decrypt_proc)(context, decrypt_key, decryptarg, as_reply))){
3107c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "decrypt_as_reply() error (*decrypt_proc)() retval "
3117c478bd9Sstevel@tonic-gate 			    "= %d", retval);
3127c478bd9Sstevel@tonic-gate 	goto cleanup;
3137c478bd9Sstevel@tonic-gate     }
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate cleanup:
3167c478bd9Sstevel@tonic-gate     if (!key && decrypt_key)
3177c478bd9Sstevel@tonic-gate 	krb5_free_keyblock(context, decrypt_key);
3187c478bd9Sstevel@tonic-gate     return (retval);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate static krb5_error_code
verify_as_reply(krb5_context context,krb5_timestamp time_now,krb5_kdc_req * request,krb5_kdc_rep * as_reply)322505d05c7Sgtb verify_as_reply(krb5_context 		context,
323505d05c7Sgtb 		krb5_timestamp 		time_now,
324505d05c7Sgtb 		krb5_kdc_req		*request,
325505d05c7Sgtb 		krb5_kdc_rep		*as_reply)
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate     krb5_error_code		retval;
328*55fea89dSDan Cross 
3297c478bd9Sstevel@tonic-gate     /* check the contents for sanity: */
3307c478bd9Sstevel@tonic-gate     if (!as_reply->enc_part2->times.starttime)
3317c478bd9Sstevel@tonic-gate 	as_reply->enc_part2->times.starttime =
3327c478bd9Sstevel@tonic-gate 	    as_reply->enc_part2->times.authtime;
333*55fea89dSDan Cross 
3347c478bd9Sstevel@tonic-gate     if (!krb5_principal_compare(context, as_reply->client, request->client)
3357c478bd9Sstevel@tonic-gate 	|| !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)
3367c478bd9Sstevel@tonic-gate 	|| !krb5_principal_compare(context, as_reply->ticket->server, request->server)
3377c478bd9Sstevel@tonic-gate 	|| (request->nonce != as_reply->enc_part2->nonce)
3387c478bd9Sstevel@tonic-gate 	/* XXX check for extraneous flags */
3397c478bd9Sstevel@tonic-gate 	/* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
3407c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_POSTDATED) &&
3417c478bd9Sstevel@tonic-gate 	    (request->from != 0) &&
3427c478bd9Sstevel@tonic-gate 	    (request->from != as_reply->enc_part2->times.starttime))
3437c478bd9Sstevel@tonic-gate 	|| ((request->till != 0) &&
3447c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.endtime > request->till))
3457c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_RENEWABLE) &&
3463441f6a1Ssemery 	    /*
3473441f6a1Ssemery 	     * Solaris Kerberos: Here we error only if renewable_ok was not set.
3483441f6a1Ssemery 	     */
3493441f6a1Ssemery 	    !(request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
3503441f6a1Ssemery 	    (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
3517c478bd9Sstevel@tonic-gate 	    (request->rtime != 0) &&
3527c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.renew_till > request->rtime))
3537c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
3547c478bd9Sstevel@tonic-gate 	    !(request->kdc_options & KDC_OPT_RENEWABLE) &&
3557c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
3567c478bd9Sstevel@tonic-gate 	    (request->till != 0) &&
3577c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.renew_till > request->till))
3583441f6a1Ssemery 	    /*
3593441f6a1Ssemery 	     * Solaris Kerberos: renew_till should never be greater than till or
3603441f6a1Ssemery 	     * rtime.
3613441f6a1Ssemery 	     */
3623441f6a1Ssemery 	|| ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
3633441f6a1Ssemery 	    (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
3643441f6a1Ssemery 	    (request->till != 0) &&
3653441f6a1Ssemery 	    (request->rtime != 0) &&
3663441f6a1Ssemery 	    (as_reply->enc_part2->times.renew_till > max(request->till,
3673441f6a1Ssemery 	     request->rtime)))
3687c478bd9Sstevel@tonic-gate 	)
3697c478bd9Sstevel@tonic-gate 	return KRB5_KDCREP_MODIFIED;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate     if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
3727c478bd9Sstevel@tonic-gate 	retval = krb5_set_real_time(context,
3737c478bd9Sstevel@tonic-gate 				    as_reply->enc_part2->times.authtime, 0);
3747c478bd9Sstevel@tonic-gate 	if (retval)
3757c478bd9Sstevel@tonic-gate 	    return retval;
3767c478bd9Sstevel@tonic-gate     } else {
3777c478bd9Sstevel@tonic-gate 	if ((request->from == 0) &&
3787c478bd9Sstevel@tonic-gate 	    (labs(as_reply->enc_part2->times.starttime - time_now)
3797c478bd9Sstevel@tonic-gate 	     > context->clockskew))
3807c478bd9Sstevel@tonic-gate 	    return (KRB5_KDCREP_SKEW);
3817c478bd9Sstevel@tonic-gate     }
3827c478bd9Sstevel@tonic-gate     return 0;
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3867c478bd9Sstevel@tonic-gate static krb5_error_code
stash_as_reply(krb5_context context,krb5_timestamp time_now,krb5_kdc_req * request,krb5_kdc_rep * as_reply,krb5_creds * creds,krb5_ccache ccache)387505d05c7Sgtb stash_as_reply(krb5_context 		context,
388505d05c7Sgtb 	       krb5_timestamp 		time_now,
389505d05c7Sgtb 	       krb5_kdc_req		*request,
390505d05c7Sgtb 	       krb5_kdc_rep		*as_reply,
391505d05c7Sgtb 	       krb5_creds * 		creds,
392505d05c7Sgtb 	       krb5_ccache 		ccache)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate     krb5_error_code 		retval;
3957c478bd9Sstevel@tonic-gate     krb5_data *			packet;
3967c478bd9Sstevel@tonic-gate     krb5_principal		client;
3977c478bd9Sstevel@tonic-gate     krb5_principal		server;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate     client = NULL;
4007c478bd9Sstevel@tonic-gate     server = NULL;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate     if (!creds->client)
403505d05c7Sgtb         if ((retval = krb5_copy_principal(context, as_reply->client, &client)))
4047c478bd9Sstevel@tonic-gate 	    goto cleanup;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate     if (!creds->server)
407505d05c7Sgtb 	if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server,
408505d05c7Sgtb 					  &server)))
4097c478bd9Sstevel@tonic-gate 	    goto cleanup;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate     /* fill in the credentials */
412*55fea89dSDan Cross     if ((retval = krb5_copy_keyblock_contents(context,
4137c478bd9Sstevel@tonic-gate 					      as_reply->enc_part2->session,
4147c478bd9Sstevel@tonic-gate 					      &creds->keyblock)))
4157c478bd9Sstevel@tonic-gate 	goto cleanup;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate     creds->times = as_reply->enc_part2->times;
4187c478bd9Sstevel@tonic-gate     creds->is_skey = FALSE;		/* this is an AS_REQ, so cannot
4197c478bd9Sstevel@tonic-gate 					   be encrypted in skey */
4207c478bd9Sstevel@tonic-gate     creds->ticket_flags = as_reply->enc_part2->flags;
4217c478bd9Sstevel@tonic-gate     if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs,
4227c478bd9Sstevel@tonic-gate 				      &creds->addresses)))
4237c478bd9Sstevel@tonic-gate 	goto cleanup;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate     creds->second_ticket.length = 0;
4267c478bd9Sstevel@tonic-gate     creds->second_ticket.data = 0;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_ticket(as_reply->ticket, &packet)))
4297c478bd9Sstevel@tonic-gate 	goto cleanup;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate     creds->ticket = *packet;
4327c478bd9Sstevel@tonic-gate     krb5_xfree(packet);
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate     /* store it in the ccache! */
435159d09a2SMark Phalan     if (ccache) /* Solaris Kerberos */
4367c478bd9Sstevel@tonic-gate 	if ((retval = krb5_cc_store_cred(context, ccache, creds)) !=0)
4377c478bd9Sstevel@tonic-gate 	    goto cleanup;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate     if (!creds->client)
4407c478bd9Sstevel@tonic-gate 	creds->client = client;
4417c478bd9Sstevel@tonic-gate     if (!creds->server)
4427c478bd9Sstevel@tonic-gate 	creds->server = server;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate cleanup:
4457c478bd9Sstevel@tonic-gate     if (retval) {
4467c478bd9Sstevel@tonic-gate 	if (client)
4477c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, client);
4487c478bd9Sstevel@tonic-gate 	if (server)
4497c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, server);
4507c478bd9Sstevel@tonic-gate 	if (creds->keyblock.contents) {
4517c478bd9Sstevel@tonic-gate 	    memset((char *)creds->keyblock.contents, 0,
4527c478bd9Sstevel@tonic-gate 		   creds->keyblock.length);
4537c478bd9Sstevel@tonic-gate 	    krb5_xfree(creds->keyblock.contents);
4547c478bd9Sstevel@tonic-gate 	    creds->keyblock.contents = 0;
4557c478bd9Sstevel@tonic-gate 	    creds->keyblock.length = 0;
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 	if (creds->ticket.data) {
4587c478bd9Sstevel@tonic-gate 	    krb5_xfree(creds->ticket.data);
4597c478bd9Sstevel@tonic-gate 	    creds->ticket.data = 0;
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 	if (creds->addresses) {
4627c478bd9Sstevel@tonic-gate 	    krb5_free_addresses(context, creds->addresses);
4637c478bd9Sstevel@tonic-gate 	    creds->addresses = 0;
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate     }
4667c478bd9Sstevel@tonic-gate     return (retval);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4707c478bd9Sstevel@tonic-gate static krb5_error_code
make_preauth_list(krb5_context context,krb5_preauthtype * ptypes,int nptypes,krb5_pa_data *** ret_list)471505d05c7Sgtb make_preauth_list(krb5_context	context,
472505d05c7Sgtb 		  krb5_preauthtype *	ptypes,
473505d05c7Sgtb 		  int			nptypes,
474505d05c7Sgtb 		  krb5_pa_data ***	ret_list)
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate     krb5_preauthtype *		ptypep;
4777c478bd9Sstevel@tonic-gate     krb5_pa_data **		preauthp;
4787c478bd9Sstevel@tonic-gate     int				i;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate     if (nptypes < 0) {
4817c478bd9Sstevel@tonic-gate  	for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++)
4827c478bd9Sstevel@tonic-gate  	    ;
4837c478bd9Sstevel@tonic-gate     }
484*55fea89dSDan Cross 
4857c478bd9Sstevel@tonic-gate     /* allocate space for a NULL to terminate the list */
486*55fea89dSDan Cross 
4877c478bd9Sstevel@tonic-gate     if ((preauthp =
4887c478bd9Sstevel@tonic-gate  	 (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
4897c478bd9Sstevel@tonic-gate  	return(ENOMEM);
490*55fea89dSDan Cross 
4917c478bd9Sstevel@tonic-gate     for (i=0; i<nptypes; i++) {
4927c478bd9Sstevel@tonic-gate  	if ((preauthp[i] =
4937c478bd9Sstevel@tonic-gate  	     (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
4947c478bd9Sstevel@tonic-gate  	    for (; i>=0; i++)
4957c478bd9Sstevel@tonic-gate  		free(preauthp[i]);
4967c478bd9Sstevel@tonic-gate  	    free(preauthp);
4977c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate  	preauthp[i]->magic = KV5M_PA_DATA;
5007c478bd9Sstevel@tonic-gate  	preauthp[i]->pa_type = ptypes[i];
5017c478bd9Sstevel@tonic-gate  	preauthp[i]->length = 0;
5027c478bd9Sstevel@tonic-gate  	preauthp[i]->contents = 0;
5037c478bd9Sstevel@tonic-gate     }
504*55fea89dSDan Cross 
5057c478bd9Sstevel@tonic-gate     /* fill in the terminating NULL */
506*55fea89dSDan Cross 
5077c478bd9Sstevel@tonic-gate     preauthp[nptypes] = NULL;
508*55fea89dSDan Cross 
5097c478bd9Sstevel@tonic-gate     *ret_list = preauthp;
5107c478bd9Sstevel@tonic-gate     return 0;
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate #define MAX_IN_TKT_LOOPS 16
514505d05c7Sgtb static const krb5_enctype get_in_tkt_enctypes[] = {
515505d05c7Sgtb     ENCTYPE_DES3_CBC_SHA1,
516505d05c7Sgtb     ENCTYPE_ARCFOUR_HMAC,
517505d05c7Sgtb     ENCTYPE_DES_CBC_MD5,
518505d05c7Sgtb     ENCTYPE_DES_CBC_MD4,
519505d05c7Sgtb     ENCTYPE_DES_CBC_CRC,
520505d05c7Sgtb     0
521505d05c7Sgtb };
522159d09a2SMark Phalan 
523159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV
krb5_get_in_tkt(krb5_context context,const krb5_flags options,krb5_address * const * addrs,krb5_enctype * ktypes,krb5_preauthtype * ptypes,git_key_proc key_proc,krb5_const_pointer keyseed,git_decrypt_proc decrypt_proc,krb5_const_pointer decryptarg,krb5_creds * creds,krb5_ccache ccache,krb5_kdc_rep ** ret_as_reply)524159d09a2SMark Phalan krb5_get_in_tkt(krb5_context context,
525159d09a2SMark Phalan 		const krb5_flags options,
526159d09a2SMark Phalan 		krb5_address * const * addrs,
527159d09a2SMark Phalan 		krb5_enctype * ktypes,
528159d09a2SMark Phalan 		krb5_preauthtype * ptypes,
529159d09a2SMark Phalan 		git_key_proc key_proc,
530159d09a2SMark Phalan 		krb5_const_pointer keyseed,
531159d09a2SMark Phalan 		git_decrypt_proc decrypt_proc,
532159d09a2SMark Phalan 		krb5_const_pointer decryptarg,
533159d09a2SMark Phalan 		krb5_creds * creds,
534159d09a2SMark Phalan 		krb5_ccache ccache,
535159d09a2SMark Phalan 		krb5_kdc_rep ** ret_as_reply)
536159d09a2SMark Phalan {
537159d09a2SMark Phalan     krb5_error_code	retval;
538159d09a2SMark Phalan     krb5_timestamp	time_now;
539159d09a2SMark Phalan     krb5_keyblock *	decrypt_key = 0;
540159d09a2SMark Phalan     krb5_kdc_req	request;
541159d09a2SMark Phalan     krb5_pa_data	**padata = 0;
542159d09a2SMark Phalan     krb5_error *	err_reply;
543159d09a2SMark Phalan     krb5_kdc_rep *	as_reply = 0;
544159d09a2SMark Phalan     krb5_pa_data  **	preauth_to_use = 0;
545159d09a2SMark Phalan     int			loopcount = 0;
546159d09a2SMark Phalan     krb5_int32		do_more = 0;
547159d09a2SMark Phalan     int             use_master = 0;
5485e01956fSGlenn Barry     char *hostname_used = NULL;
549159d09a2SMark Phalan 
5505e01956fSGlenn Barry     if (! krb5_realm_compare(context, creds->client, creds->server)) {
5515e01956fSGlenn Barry 	/* Solaris Kerberos */
5525e01956fSGlenn Barry 	char *s_name = NULL;
5535e01956fSGlenn Barry 	char *c_name = NULL;
5545e01956fSGlenn Barry 	krb5_error_code serr, cerr;
5555e01956fSGlenn Barry 	serr = krb5_unparse_name(context, creds->server, &s_name);
5565e01956fSGlenn Barry 	cerr = krb5_unparse_name(context, creds->client, &c_name);
5575e01956fSGlenn Barry 	krb5_set_error_message(context, KRB5_IN_TKT_REALM_MISMATCH,
5585e01956fSGlenn Barry 			    dgettext(TEXT_DOMAIN,
5595e01956fSGlenn Barry 				    "Client/server realm mismatch in initial ticket request: '%s' requesting ticket '%s'"),
5605e01956fSGlenn Barry 			    cerr ? "unknown" : c_name,
5615e01956fSGlenn Barry 			    serr ? "unknown" : s_name);
5625e01956fSGlenn Barry 	if (s_name)
5635e01956fSGlenn Barry 	    krb5_free_unparsed_name(context, s_name);
5645e01956fSGlenn Barry 	if (c_name)
5655e01956fSGlenn Barry 	    krb5_free_unparsed_name(context, c_name);
566159d09a2SMark Phalan 	return KRB5_IN_TKT_REALM_MISMATCH;
5675e01956fSGlenn Barry     }
568159d09a2SMark Phalan 
569159d09a2SMark Phalan     if (ret_as_reply)
570159d09a2SMark Phalan 	*ret_as_reply = 0;
571*55fea89dSDan Cross 
572159d09a2SMark Phalan     /*
573159d09a2SMark Phalan      * Set up the basic request structure
574159d09a2SMark Phalan      */
575159d09a2SMark Phalan     request.magic = KV5M_KDC_REQ;
576159d09a2SMark Phalan     request.msg_type = KRB5_AS_REQ;
577159d09a2SMark Phalan     request.addresses = 0;
578159d09a2SMark Phalan     request.ktype = 0;
579159d09a2SMark Phalan     request.padata = 0;
580159d09a2SMark Phalan     if (addrs)
581159d09a2SMark Phalan 	request.addresses = (krb5_address **) addrs;
582159d09a2SMark Phalan     else
583159d09a2SMark Phalan 	if ((retval = krb5_os_localaddr(context, &request.addresses)))
584159d09a2SMark Phalan 	    goto cleanup;
585159d09a2SMark Phalan     request.kdc_options = options;
586159d09a2SMark Phalan     request.client = creds->client;
587159d09a2SMark Phalan     request.server = creds->server;
588159d09a2SMark Phalan     request.nonce = 0;
589159d09a2SMark Phalan     request.from = creds->times.starttime;
590159d09a2SMark Phalan     request.till = creds->times.endtime;
591159d09a2SMark Phalan     request.rtime = creds->times.renew_till;
592159d09a2SMark Phalan 
593159d09a2SMark Phalan     request.ktype = malloc (sizeof(get_in_tkt_enctypes));
594159d09a2SMark Phalan     if (request.ktype == NULL) {
595159d09a2SMark Phalan 	retval = ENOMEM;
596159d09a2SMark Phalan 	goto cleanup;
597159d09a2SMark Phalan     }
598159d09a2SMark Phalan     memcpy(request.ktype, get_in_tkt_enctypes, sizeof(get_in_tkt_enctypes));
599159d09a2SMark Phalan     for (request.nktypes = 0;request.ktype[request.nktypes];request.nktypes++);
600159d09a2SMark Phalan     if (ktypes) {
601159d09a2SMark Phalan 	int i, req, next = 0;
602159d09a2SMark Phalan 	for (req = 0; ktypes[req]; req++) {
603159d09a2SMark Phalan 	    if (ktypes[req] == request.ktype[next]) {
604159d09a2SMark Phalan 		next++;
605159d09a2SMark Phalan 		continue;
606159d09a2SMark Phalan 	    }
607159d09a2SMark Phalan 	    for (i = next + 1; i < request.nktypes; i++)
608159d09a2SMark Phalan 		if (ktypes[req] == request.ktype[i]) {
609159d09a2SMark Phalan 		    /* Found the enctype we want, but not in the
610159d09a2SMark Phalan 		       position we want.  Move it, but keep the old
611159d09a2SMark Phalan 		       one from the desired slot around in case it's
612159d09a2SMark Phalan 		       later in our requested-ktypes list.  */
613159d09a2SMark Phalan 		    krb5_enctype t;
614159d09a2SMark Phalan 		    t = request.ktype[next];
615159d09a2SMark Phalan 		    request.ktype[next] = request.ktype[i];
616159d09a2SMark Phalan 		    request.ktype[i] = t;
617159d09a2SMark Phalan 		    next++;
618159d09a2SMark Phalan 		    break;
619159d09a2SMark Phalan 		}
620159d09a2SMark Phalan 	    /* If we didn't find it, don't do anything special, just
621159d09a2SMark Phalan 	       drop it.  */
622159d09a2SMark Phalan 	}
623159d09a2SMark Phalan 	request.ktype[next] = 0;
624159d09a2SMark Phalan 	request.nktypes = next;
625159d09a2SMark Phalan     }
626159d09a2SMark Phalan     request.authorization_data.ciphertext.length = 0;
627159d09a2SMark Phalan     request.authorization_data.ciphertext.data = 0;
628159d09a2SMark Phalan     request.unenc_authdata = 0;
629159d09a2SMark Phalan     request.second_ticket = 0;
630159d09a2SMark Phalan 
631159d09a2SMark Phalan     /*
632159d09a2SMark Phalan      * If a list of preauth types are passed in, convert it to a
633159d09a2SMark Phalan      * preauth_to_use list.
634159d09a2SMark Phalan      */
635159d09a2SMark Phalan     if (ptypes) {
636159d09a2SMark Phalan 	retval = make_preauth_list(context, ptypes, -1, &preauth_to_use);
637159d09a2SMark Phalan 	if (retval)
638159d09a2SMark Phalan 	    goto cleanup;
639159d09a2SMark Phalan     }
640*55fea89dSDan Cross 
641159d09a2SMark Phalan     while (1) {
642159d09a2SMark Phalan 	if (loopcount++ > MAX_IN_TKT_LOOPS) {
643159d09a2SMark Phalan 	    retval = KRB5_GET_IN_TKT_LOOP;
6445e01956fSGlenn Barry 	    /* Solaris Kerberos */
6455e01956fSGlenn Barry 	    {
6465e01956fSGlenn Barry                 char *s_name = NULL;
6475e01956fSGlenn Barry 		char *c_name = NULL;
6485e01956fSGlenn Barry 		krb5_error_code serr, cerr;
6495e01956fSGlenn Barry 		serr = krb5_unparse_name(context, creds->server, &s_name);
6505e01956fSGlenn Barry 		cerr = krb5_unparse_name(context, creds->client, &c_name);
6515e01956fSGlenn Barry 		krb5_set_error_message(context, retval,
6525e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
6535e01956fSGlenn Barry 					    "Looping detected getting ticket: '%s' requesting ticket '%s'. Max loops is %d.  Make sure a KDC is available"),
6545e01956fSGlenn Barry 				    cerr ? "unknown" : c_name,
6555e01956fSGlenn Barry 				    serr ? "unknown" : s_name,
6565e01956fSGlenn Barry 				    MAX_IN_TKT_LOOPS);
6575e01956fSGlenn Barry 		if (s_name)
6585e01956fSGlenn Barry 		    krb5_free_unparsed_name(context, s_name);
6595e01956fSGlenn Barry 		if (c_name)
6605e01956fSGlenn Barry 		    krb5_free_unparsed_name(context, c_name);
6615e01956fSGlenn Barry 	    }
662159d09a2SMark Phalan 	    goto cleanup;
663159d09a2SMark Phalan 	}
664159d09a2SMark Phalan 
665159d09a2SMark Phalan 	if ((retval = krb5_obtain_padata(context, preauth_to_use, key_proc,
666159d09a2SMark Phalan 					 keyseed, creds, &request)) != 0)
667159d09a2SMark Phalan 	    goto cleanup;
668159d09a2SMark Phalan 	if (preauth_to_use)
669159d09a2SMark Phalan 	    krb5_free_pa_data(context, preauth_to_use);
670159d09a2SMark Phalan 	preauth_to_use = 0;
671*55fea89dSDan Cross 
672159d09a2SMark Phalan 	err_reply = 0;
673159d09a2SMark Phalan 	as_reply = 0;
674159d09a2SMark Phalan 
675159d09a2SMark Phalan         if ((retval = krb5_timeofday(context, &time_now)))
676159d09a2SMark Phalan 	    goto cleanup;
677159d09a2SMark Phalan 
678159d09a2SMark Phalan         /*
679159d09a2SMark Phalan          * XXX we know they are the same size... and we should do
680159d09a2SMark Phalan          * something better than just the current time
681159d09a2SMark Phalan          */
682159d09a2SMark Phalan 	request.nonce = (krb5_int32) time_now;
683159d09a2SMark Phalan 
6845e01956fSGlenn Barry 	if ((retval = send_as_request2(context, &request, &err_reply,
6855e01956fSGlenn Barry 				    &as_reply, &use_master,
6865e01956fSGlenn Barry 				    &hostname_used)))
687159d09a2SMark Phalan 	    goto cleanup;
688159d09a2SMark Phalan 
689159d09a2SMark Phalan 	if (err_reply) {
690159d09a2SMark Phalan 	    if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
691159d09a2SMark Phalan 		err_reply->e_data.length > 0) {
692159d09a2SMark Phalan 		retval = decode_krb5_padata_sequence(&err_reply->e_data,
693159d09a2SMark Phalan 						     &preauth_to_use);
694159d09a2SMark Phalan 		krb5_free_error(context, err_reply);
6955e01956fSGlenn Barry                 err_reply = NULL;
696159d09a2SMark Phalan 		if (retval)
697159d09a2SMark Phalan 		    goto cleanup;
698159d09a2SMark Phalan                 retval = sort_krb5_padata_sequence(context,
699159d09a2SMark Phalan 						   &request.server->realm,
700159d09a2SMark Phalan 						   padata);
701159d09a2SMark Phalan 		if (retval)
702159d09a2SMark Phalan 		    goto cleanup;
703159d09a2SMark Phalan 		continue;
704159d09a2SMark Phalan 	    } else {
705*55fea89dSDan Cross 		retval = (krb5_error_code) err_reply->error
706159d09a2SMark Phalan 		    + ERROR_TABLE_BASE_krb5;
707159d09a2SMark Phalan 		krb5_free_error(context, err_reply);
7085e01956fSGlenn Barry                 err_reply = NULL;
709159d09a2SMark Phalan 		goto cleanup;
710159d09a2SMark Phalan 	    }
711159d09a2SMark Phalan 	} else if (!as_reply) {
712159d09a2SMark Phalan 	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
713159d09a2SMark Phalan 	    goto cleanup;
714159d09a2SMark Phalan 	}
715159d09a2SMark Phalan 	if ((retval = krb5_process_padata(context, &request, as_reply,
716*55fea89dSDan Cross 					  key_proc, keyseed, decrypt_proc,
717159d09a2SMark Phalan 					  &decrypt_key, creds,
718159d09a2SMark Phalan 					  &do_more)) != 0)
719159d09a2SMark Phalan 	    goto cleanup;
720159d09a2SMark Phalan 
721159d09a2SMark Phalan 	if (!do_more)
722159d09a2SMark Phalan 	    break;
723159d09a2SMark Phalan     }
724*55fea89dSDan Cross 
725159d09a2SMark Phalan     if ((retval = decrypt_as_reply(context, &request, as_reply, key_proc,
726159d09a2SMark Phalan 				   keyseed, decrypt_key, decrypt_proc,
727159d09a2SMark Phalan 				   decryptarg)))
728159d09a2SMark Phalan 	goto cleanup;
729159d09a2SMark Phalan 
730159d09a2SMark Phalan     if ((retval = verify_as_reply(context, time_now, &request, as_reply)))
731159d09a2SMark Phalan 	goto cleanup;
732159d09a2SMark Phalan 
733159d09a2SMark Phalan     if ((retval = stash_as_reply(context, time_now, &request, as_reply,
734159d09a2SMark Phalan 				 creds, ccache)))
735159d09a2SMark Phalan 	goto cleanup;
736159d09a2SMark Phalan 
737159d09a2SMark Phalan cleanup:
738159d09a2SMark Phalan     if (request.ktype)
739159d09a2SMark Phalan 	free(request.ktype);
740159d09a2SMark Phalan     if (!addrs && request.addresses)
741159d09a2SMark Phalan 	krb5_free_addresses(context, request.addresses);
742159d09a2SMark Phalan     if (request.padata)
743159d09a2SMark Phalan 	krb5_free_pa_data(context, request.padata);
744159d09a2SMark Phalan     if (padata)
745159d09a2SMark Phalan 	krb5_free_pa_data(context, padata);
746159d09a2SMark Phalan     if (preauth_to_use)
747159d09a2SMark Phalan 	krb5_free_pa_data(context, preauth_to_use);
748159d09a2SMark Phalan     if (decrypt_key)
749159d09a2SMark Phalan     	krb5_free_keyblock(context, decrypt_key);
750159d09a2SMark Phalan     if (as_reply) {
751159d09a2SMark Phalan 	if (ret_as_reply)
752159d09a2SMark Phalan 	    *ret_as_reply = as_reply;
753159d09a2SMark Phalan 	else
754159d09a2SMark Phalan 	    krb5_free_kdc_rep(context, as_reply);
755159d09a2SMark Phalan     }
7565e01956fSGlenn Barry     if (hostname_used)
7575e01956fSGlenn Barry         free(hostname_used);
7585e01956fSGlenn Barry 
759159d09a2SMark Phalan     return (retval);
760159d09a2SMark Phalan }
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate /* begin libdefaults parsing code.  This should almost certainly move
7637c478bd9Sstevel@tonic-gate    somewhere else, but I don't know where the correct somewhere else
7647c478bd9Sstevel@tonic-gate    is yet. */
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate /* XXX Duplicating this is annoying; try to work on a better way.*/
767505d05c7Sgtb static const char *const conf_yes[] = {
7687c478bd9Sstevel@tonic-gate     "y", "yes", "true", "t", "1", "on",
7697c478bd9Sstevel@tonic-gate     0,
7707c478bd9Sstevel@tonic-gate };
7717c478bd9Sstevel@tonic-gate 
772505d05c7Sgtb static const char *const conf_no[] = {
7737c478bd9Sstevel@tonic-gate     "n", "no", "false", "nil", "0", "off",
7747c478bd9Sstevel@tonic-gate     0,
7757c478bd9Sstevel@tonic-gate };
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate int
_krb5_conf_boolean(const char * s)778505d05c7Sgtb _krb5_conf_boolean(const char *s)
7797c478bd9Sstevel@tonic-gate {
780505d05c7Sgtb     const char *const *p;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate     for(p=conf_yes; *p; p++) {
7837c478bd9Sstevel@tonic-gate 	if (!strcasecmp(*p,s))
7847c478bd9Sstevel@tonic-gate 	    return 1;
7857c478bd9Sstevel@tonic-gate     }
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate     for(p=conf_no; *p; p++) {
7887c478bd9Sstevel@tonic-gate 	if (!strcasecmp(*p,s))
7897c478bd9Sstevel@tonic-gate 	    return 0;
7907c478bd9Sstevel@tonic-gate     }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate     /* Default to "no" */
7937c478bd9Sstevel@tonic-gate     return 0;
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate static krb5_error_code
krb5_libdefault_string(krb5_context context,const krb5_data * realm,const char * option,char ** ret_value)797505d05c7Sgtb krb5_libdefault_string(krb5_context context, const krb5_data *realm,
798505d05c7Sgtb 		       const char *option, char **ret_value)
7997c478bd9Sstevel@tonic-gate {
8007c478bd9Sstevel@tonic-gate     profile_t profile;
8017c478bd9Sstevel@tonic-gate     const char *names[5];
8027c478bd9Sstevel@tonic-gate     char **nameval = NULL;
8037c478bd9Sstevel@tonic-gate     krb5_error_code retval;
8047c478bd9Sstevel@tonic-gate     char realmstr[1024];
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate     if (realm->length > sizeof(realmstr)-1)
8077c478bd9Sstevel@tonic-gate 	return(EINVAL);
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate     strncpy(realmstr, realm->data, realm->length);
8107c478bd9Sstevel@tonic-gate     realmstr[realm->length] = '\0';
8117c478bd9Sstevel@tonic-gate 
812*55fea89dSDan Cross     if (!context || (context->magic != KV5M_CONTEXT))
8137c478bd9Sstevel@tonic-gate 	return KV5M_CONTEXT;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate     profile = context->profile;
816*55fea89dSDan Cross 
817159d09a2SMark Phalan     /* Solaris Kerberos */
8187c478bd9Sstevel@tonic-gate     names[0] = "realms";
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate     /*
8217c478bd9Sstevel@tonic-gate      * Try number one:
8227c478bd9Sstevel@tonic-gate      *
8237c478bd9Sstevel@tonic-gate      * [realms]
8247c478bd9Sstevel@tonic-gate      *		REALM = {
8257c478bd9Sstevel@tonic-gate      *			option = <boolean>
8267c478bd9Sstevel@tonic-gate      *		}
8277c478bd9Sstevel@tonic-gate      */
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate     names[1] = realmstr;
8307c478bd9Sstevel@tonic-gate     names[2] = option;
8317c478bd9Sstevel@tonic-gate     names[3] = 0;
8327c478bd9Sstevel@tonic-gate     retval = profile_get_values(profile, names, &nameval);
8337c478bd9Sstevel@tonic-gate     if (retval == 0 && nameval && nameval[0])
8347c478bd9Sstevel@tonic-gate 	goto goodbye;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate     /*
8377c478bd9Sstevel@tonic-gate      * Try number two:
8387c478bd9Sstevel@tonic-gate      *
8397c478bd9Sstevel@tonic-gate      * [libdefaults]
8407c478bd9Sstevel@tonic-gate      *		option = <boolean>
8417c478bd9Sstevel@tonic-gate      */
842*55fea89dSDan Cross 
8437c478bd9Sstevel@tonic-gate     names[0] = "libdefaults";
8447c478bd9Sstevel@tonic-gate     names[1] = option;
8457c478bd9Sstevel@tonic-gate     names[2] = 0;
8467c478bd9Sstevel@tonic-gate     retval = profile_get_values(profile, names, &nameval);
8477c478bd9Sstevel@tonic-gate     if (retval == 0 && nameval && nameval[0])
8487c478bd9Sstevel@tonic-gate 	goto goodbye;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate goodbye:
851*55fea89dSDan Cross     if (!nameval)
8527c478bd9Sstevel@tonic-gate 	return(ENOENT);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate     if (!nameval[0]) {
8557c478bd9Sstevel@tonic-gate         retval = ENOENT;
8567c478bd9Sstevel@tonic-gate     } else {
8577c478bd9Sstevel@tonic-gate         *ret_value = malloc(strlen(nameval[0]) + 1);
8587c478bd9Sstevel@tonic-gate         if (!*ret_value)
8597c478bd9Sstevel@tonic-gate             retval = ENOMEM;
8607c478bd9Sstevel@tonic-gate         else
8617c478bd9Sstevel@tonic-gate             strcpy(*ret_value, nameval[0]);
8627c478bd9Sstevel@tonic-gate     }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate     profile_free_list(nameval);
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate     return retval;
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate /* not static so verify_init_creds() can call it */
8707c478bd9Sstevel@tonic-gate /* as well as the DNS code */
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate krb5_error_code
krb5_libdefault_boolean(krb5_context context,const krb5_data * realm,const char * option,int * ret_value)873505d05c7Sgtb krb5_libdefault_boolean(krb5_context context, const krb5_data *realm,
874505d05c7Sgtb 			const char *option, int *ret_value)
8757c478bd9Sstevel@tonic-gate {
8767c478bd9Sstevel@tonic-gate     char *string = NULL;
8777c478bd9Sstevel@tonic-gate     krb5_error_code retval;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate     retval = krb5_libdefault_string(context, realm, option, &string);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate     if (retval)
8827c478bd9Sstevel@tonic-gate 	return(retval);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate     *ret_value = _krb5_conf_boolean(string);
8857c478bd9Sstevel@tonic-gate     free(string);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate     return(0);
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate 
890159d09a2SMark Phalan /* Sort a pa_data sequence so that types named in the "preferred_preauth_types"
891159d09a2SMark Phalan  * libdefaults entry are listed before any others. */
892159d09a2SMark Phalan static krb5_error_code
sort_krb5_padata_sequence(krb5_context context,krb5_data * realm,krb5_pa_data ** padata)893159d09a2SMark Phalan sort_krb5_padata_sequence(krb5_context context, krb5_data *realm,
894159d09a2SMark Phalan 			  krb5_pa_data **padata)
895159d09a2SMark Phalan {
896159d09a2SMark Phalan     int i, j, base;
897159d09a2SMark Phalan     krb5_error_code ret;
898159d09a2SMark Phalan     const char *p;
899159d09a2SMark Phalan     long l;
900159d09a2SMark Phalan     char *q, *preauth_types = NULL;
901159d09a2SMark Phalan     krb5_pa_data *tmp;
902159d09a2SMark Phalan     int need_free_string = 1;
903159d09a2SMark Phalan 
904159d09a2SMark Phalan     if ((padata == NULL) || (padata[0] == NULL)) {
905159d09a2SMark Phalan 	return 0;
906159d09a2SMark Phalan     }
907159d09a2SMark Phalan 
908159d09a2SMark Phalan     ret = krb5_libdefault_string(context, realm, "preferred_preauth_types",
909159d09a2SMark Phalan 				 &preauth_types);
910159d09a2SMark Phalan     if ((ret != 0) || (preauth_types == NULL)) {
911159d09a2SMark Phalan 	/* Try to use PKINIT first. */
912159d09a2SMark Phalan 	preauth_types = "17, 16, 15, 14";
913159d09a2SMark Phalan 	need_free_string = 0;
914159d09a2SMark Phalan     }
915159d09a2SMark Phalan 
916159d09a2SMark Phalan #ifdef DEBUG
917159d09a2SMark Phalan     fprintf (stderr, "preauth data types before sorting:");
918159d09a2SMark Phalan     for (i = 0; padata[i]; i++) {
919159d09a2SMark Phalan 	fprintf (stderr, " %d", padata[i]->pa_type);
920159d09a2SMark Phalan     }
921159d09a2SMark Phalan     fprintf (stderr, "\n");
922159d09a2SMark Phalan #endif
923159d09a2SMark Phalan 
924159d09a2SMark Phalan     base = 0;
925159d09a2SMark Phalan     for (p = preauth_types; *p != '\0';) {
926159d09a2SMark Phalan 	/* skip whitespace to find an entry */
927159d09a2SMark Phalan 	p += strspn(p, ", ");
928159d09a2SMark Phalan 	if (*p != '\0') {
929159d09a2SMark Phalan 	    /* see if we can extract a number */
930159d09a2SMark Phalan 	    l = strtol(p, &q, 10);
931159d09a2SMark Phalan 	    if ((q != NULL) && (q > p)) {
932159d09a2SMark Phalan 		/* got a valid number; search for a matchin entry */
933159d09a2SMark Phalan 		for (i = base; padata[i] != NULL; i++) {
934159d09a2SMark Phalan 		    /* bubble the matching entry to the front of the list */
935159d09a2SMark Phalan 		    if (padata[i]->pa_type == l) {
936159d09a2SMark Phalan 			tmp = padata[i];
937159d09a2SMark Phalan 			for (j = i; j > base; j--)
938159d09a2SMark Phalan 			    padata[j] = padata[j - 1];
939159d09a2SMark Phalan 			padata[base] = tmp;
940159d09a2SMark Phalan 			base++;
941159d09a2SMark Phalan 			break;
942159d09a2SMark Phalan 		    }
943159d09a2SMark Phalan 		}
944159d09a2SMark Phalan 		p = q;
945159d09a2SMark Phalan 	    } else {
946159d09a2SMark Phalan 		break;
947159d09a2SMark Phalan 	    }
948159d09a2SMark Phalan 	}
949159d09a2SMark Phalan     }
950159d09a2SMark Phalan     if (need_free_string)
951159d09a2SMark Phalan 	free(preauth_types);
952159d09a2SMark Phalan 
953159d09a2SMark Phalan #ifdef DEBUG
954159d09a2SMark Phalan     fprintf (stderr, "preauth data types after sorting:");
955159d09a2SMark Phalan     for (i = 0; padata[i]; i++)
956159d09a2SMark Phalan 	fprintf (stderr, " %d", padata[i]->pa_type);
957159d09a2SMark Phalan     fprintf (stderr, "\n");
958159d09a2SMark Phalan #endif
959159d09a2SMark Phalan 
960159d09a2SMark Phalan     return 0;
961159d09a2SMark Phalan }
962159d09a2SMark Phalan 
9635e01956fSGlenn Barry /*
9645e01956fSGlenn Barry  * Solaris Kerberos
9655e01956fSGlenn Barry  * Return 1 if any char in string is lower-case.
9665e01956fSGlenn Barry  */
9675e01956fSGlenn Barry static int
is_lower_case(char * s)9685e01956fSGlenn Barry is_lower_case(char *s)
9695e01956fSGlenn Barry {
9705e01956fSGlenn Barry     if (!s)
9715e01956fSGlenn Barry 	return 0;
9725e01956fSGlenn Barry 
9735e01956fSGlenn Barry     while (*s) {
9745e01956fSGlenn Barry 	if (islower((int)*s))
9755e01956fSGlenn Barry 	    return 1;
9765e01956fSGlenn Barry 	s++;
9775e01956fSGlenn Barry     }
9785e01956fSGlenn Barry     return 0;
9795e01956fSGlenn Barry }
9805e01956fSGlenn Barry 
981505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_get_init_creds(krb5_context context,krb5_creds * creds,krb5_principal client,krb5_prompter_fct prompter,void * prompter_data,krb5_deltat start_time,char * in_tkt_service,krb5_gic_opt_ext * options,krb5_gic_get_as_key_fct gak_fct,void * gak_data,int * use_master,krb5_kdc_rep ** as_reply)982505d05c7Sgtb krb5_get_init_creds(krb5_context context,
983505d05c7Sgtb 		    krb5_creds *creds,
984505d05c7Sgtb 		    krb5_principal client,
985505d05c7Sgtb 		    krb5_prompter_fct prompter,
986505d05c7Sgtb 		    void *prompter_data,
987505d05c7Sgtb 		    krb5_deltat start_time,
988505d05c7Sgtb 		    char *in_tkt_service,
989159d09a2SMark Phalan 		    krb5_gic_opt_ext *options,
990505d05c7Sgtb 		    krb5_gic_get_as_key_fct gak_fct,
991505d05c7Sgtb 		    void *gak_data,
992505d05c7Sgtb 		    int  *use_master,
993505d05c7Sgtb 		    krb5_kdc_rep **as_reply)
9947c478bd9Sstevel@tonic-gate {
9957c478bd9Sstevel@tonic-gate     krb5_error_code ret;
9967c478bd9Sstevel@tonic-gate     krb5_kdc_req request;
997159d09a2SMark Phalan     krb5_data *encoded_request_body, *encoded_previous_request;
998159d09a2SMark Phalan     krb5_pa_data **preauth_to_use, **kdc_padata;
9997c478bd9Sstevel@tonic-gate     int tempint;
1000505d05c7Sgtb     char *tempstr = NULL;
1001505d05c7Sgtb     krb5_deltat tkt_life;
10027c478bd9Sstevel@tonic-gate     krb5_deltat renew_life;
10037c478bd9Sstevel@tonic-gate     int loopcount;
10047c478bd9Sstevel@tonic-gate     krb5_data salt;
10057c478bd9Sstevel@tonic-gate     krb5_data s2kparams;
10067c478bd9Sstevel@tonic-gate     krb5_keyblock as_key;
10075e01956fSGlenn Barry     krb5_error *err_reply = NULL;
10087c478bd9Sstevel@tonic-gate     krb5_kdc_rep *local_as_reply;
10097c478bd9Sstevel@tonic-gate     krb5_timestamp time_now;
10107c478bd9Sstevel@tonic-gate     krb5_enctype etype = 0;
1011159d09a2SMark Phalan     krb5_preauth_client_rock get_data_rock;
10125e01956fSGlenn Barry     char *hostname_used = NULL;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate     /* initialize everything which will be freed at cleanup */
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate     s2kparams.data = NULL;
10177c478bd9Sstevel@tonic-gate     s2kparams.length = 0;
10187c478bd9Sstevel@tonic-gate     request.server = NULL;
10197c478bd9Sstevel@tonic-gate     request.ktype = NULL;
10207c478bd9Sstevel@tonic-gate     request.addresses = NULL;
10217c478bd9Sstevel@tonic-gate     request.padata = NULL;
1022159d09a2SMark Phalan     encoded_request_body = NULL;
1023159d09a2SMark Phalan     encoded_previous_request = NULL;
1024159d09a2SMark Phalan     preauth_to_use = NULL;
1025159d09a2SMark Phalan     kdc_padata = NULL;
1026159d09a2SMark Phalan     as_key.length = 0;
10277c478bd9Sstevel@tonic-gate     salt.length = 0;
10287c478bd9Sstevel@tonic-gate     salt.data = NULL;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate     (void) memset(&as_key, 0, sizeof(as_key));
10317c478bd9Sstevel@tonic-gate 
10325e01956fSGlenn Barry     local_as_reply = 0;
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate     /*
10357c478bd9Sstevel@tonic-gate      * Set up the basic request structure
10367c478bd9Sstevel@tonic-gate      */
10377c478bd9Sstevel@tonic-gate     request.magic = KV5M_KDC_REQ;
10387c478bd9Sstevel@tonic-gate     request.msg_type = KRB5_AS_REQ;
10397c478bd9Sstevel@tonic-gate 
1040159d09a2SMark Phalan     /* request.nonce is filled in when we send a request to the kdc */
1041159d09a2SMark Phalan     request.nonce = 0;
1042159d09a2SMark Phalan 
10437c478bd9Sstevel@tonic-gate     /* request.padata is filled in later */
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate     request.kdc_options = context->kdc_default_options;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate     /* forwardable */
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE))
10507c478bd9Sstevel@tonic-gate 	tempint = options->forwardable;
10517c478bd9Sstevel@tonic-gate     else if ((ret = krb5_libdefault_boolean(context, &client->realm,
10527c478bd9Sstevel@tonic-gate 					    "forwardable", &tempint)) == 0)
10537c478bd9Sstevel@tonic-gate 	/*EMPTY*/
10547c478bd9Sstevel@tonic-gate 	;
10557c478bd9Sstevel@tonic-gate     else
1056159d09a2SMark Phalan 	tempint = 0;
10577c478bd9Sstevel@tonic-gate     if (tempint)
10587c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_FORWARDABLE;
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate     /* proxiable */
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE))
10637c478bd9Sstevel@tonic-gate 	tempint = options->proxiable;
10647c478bd9Sstevel@tonic-gate     else if ((ret = krb5_libdefault_boolean(context, &client->realm,
10657c478bd9Sstevel@tonic-gate 					    "proxiable", &tempint)) == 0)
10667c478bd9Sstevel@tonic-gate 	/*EMPTY*/
10677c478bd9Sstevel@tonic-gate 	;
10687c478bd9Sstevel@tonic-gate     else
1069159d09a2SMark Phalan 	tempint = 0;
10707c478bd9Sstevel@tonic-gate     if (tempint)
10717c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_PROXIABLE;
10727c478bd9Sstevel@tonic-gate 
1073505d05c7Sgtb     /* allow_postdate */
1074*55fea89dSDan Cross 
1075505d05c7Sgtb     if (start_time > 0)
1076505d05c7Sgtb 	request.kdc_options |= (KDC_OPT_ALLOW_POSTDATE|KDC_OPT_POSTDATED);
1077*55fea89dSDan Cross 
1078505d05c7Sgtb     /* ticket lifetime */
1079*55fea89dSDan Cross 
1080505d05c7Sgtb     if ((ret = krb5_timeofday(context, &request.from)))
1081505d05c7Sgtb 	goto cleanup;
1082505d05c7Sgtb     request.from = krb5int_addint32(request.from, start_time);
1083*55fea89dSDan Cross 
1084505d05c7Sgtb     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)) {
1085505d05c7Sgtb         tkt_life = options->tkt_life;
1086505d05c7Sgtb     } else if ((ret = krb5_libdefault_string(context, &client->realm,
1087505d05c7Sgtb 					     "ticket_lifetime", &tempstr))
1088505d05c7Sgtb 	       == 0) {
1089159d09a2SMark Phalan 	ret = krb5_string_to_deltat(tempstr, &tkt_life);
1090159d09a2SMark Phalan 	free(tempstr);
1091159d09a2SMark Phalan 	if (ret) {
1092505d05c7Sgtb 	    goto cleanup;
1093505d05c7Sgtb 	}
1094505d05c7Sgtb     } else {
1095505d05c7Sgtb 	/* this used to be hardcoded in kinit.c */
1096505d05c7Sgtb 	tkt_life = 24*60*60;
1097505d05c7Sgtb     }
1098505d05c7Sgtb     request.till = krb5int_addint32(request.from, tkt_life);
1099*55fea89dSDan Cross 
1100505d05c7Sgtb     /* renewable lifetime */
1101*55fea89dSDan Cross 
11027c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) {
11037c478bd9Sstevel@tonic-gate 	renew_life = options->renew_life;
11047c478bd9Sstevel@tonic-gate     } else if ((ret = krb5_libdefault_string(context, &client->realm,
11057c478bd9Sstevel@tonic-gate 					     "renew_lifetime", &tempstr))
11067c478bd9Sstevel@tonic-gate 	       == 0) {
1107159d09a2SMark Phalan 	ret = krb5_string_to_deltat(tempstr, &renew_life);
1108159d09a2SMark Phalan 	free(tempstr);
1109159d09a2SMark Phalan 	if (ret) {
11107c478bd9Sstevel@tonic-gate 	    goto cleanup;
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate     } else {
11137c478bd9Sstevel@tonic-gate 	renew_life = 0;
11147c478bd9Sstevel@tonic-gate     }
11157c478bd9Sstevel@tonic-gate     if (renew_life > 0)
11167c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_RENEWABLE;
1117*55fea89dSDan Cross 
1118505d05c7Sgtb     if (renew_life > 0) {
1119505d05c7Sgtb 	request.rtime = krb5int_addint32(request.from, renew_life);
1120505d05c7Sgtb         if (request.rtime < request.till) {
1121505d05c7Sgtb             /* don't ask for a smaller renewable time than the lifetime */
1122505d05c7Sgtb             request.rtime = request.till;
1123505d05c7Sgtb         }
1124505d05c7Sgtb         /* we are already asking for renewable tickets so strip this option */
1125505d05c7Sgtb 	request.kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
1126505d05c7Sgtb     } else {
1127505d05c7Sgtb 	request.rtime = 0;
1128505d05c7Sgtb     }
1129*55fea89dSDan Cross 
11307c478bd9Sstevel@tonic-gate     /* client */
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate     request.client = client;
11337c478bd9Sstevel@tonic-gate 
1134505d05c7Sgtb     /* service */
1135*55fea89dSDan Cross 
11367c478bd9Sstevel@tonic-gate     if (in_tkt_service) {
11377c478bd9Sstevel@tonic-gate 	/* this is ugly, because so are the data structures involved.  I'm
11387c478bd9Sstevel@tonic-gate 	   in the library, so I'm going to manipulate the data structures
11397c478bd9Sstevel@tonic-gate 	   directly, otherwise, it will be worse. */
11407c478bd9Sstevel@tonic-gate 
1141505d05c7Sgtb         if ((ret = krb5_parse_name(context, in_tkt_service, &request.server)))
11427c478bd9Sstevel@tonic-gate 	    goto cleanup;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	/* stuff the client realm into the server principal.
11457c478bd9Sstevel@tonic-gate 	   realloc if necessary */
11467c478bd9Sstevel@tonic-gate 	if (request.server->realm.length < request.client->realm.length)
11477c478bd9Sstevel@tonic-gate 	    if ((request.server->realm.data =
11487c478bd9Sstevel@tonic-gate 		 (char *) realloc(request.server->realm.data,
11497c478bd9Sstevel@tonic-gate 				  request.client->realm.length)) == NULL) {
11507c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
11517c478bd9Sstevel@tonic-gate 		goto cleanup;
11527c478bd9Sstevel@tonic-gate 	    }
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	request.server->realm.length = request.client->realm.length;
11557c478bd9Sstevel@tonic-gate 	memcpy(request.server->realm.data, request.client->realm.data,
11567c478bd9Sstevel@tonic-gate 	       request.client->realm.length);
11577c478bd9Sstevel@tonic-gate     } else {
1158505d05c7Sgtb 	if ((ret = krb5_build_principal_ext(context, &request.server,
11597c478bd9Sstevel@tonic-gate 					   request.client->realm.length,
11607c478bd9Sstevel@tonic-gate 					   request.client->realm.data,
11617c478bd9Sstevel@tonic-gate 					   KRB5_TGS_NAME_SIZE,
11627c478bd9Sstevel@tonic-gate 					   KRB5_TGS_NAME,
11637c478bd9Sstevel@tonic-gate 					   request.client->realm.length,
11647c478bd9Sstevel@tonic-gate 					   request.client->realm.data,
1165505d05c7Sgtb 					   0)))
11667c478bd9Sstevel@tonic-gate 	    goto cleanup;
11677c478bd9Sstevel@tonic-gate     }
11687c478bd9Sstevel@tonic-gate 
1169159d09a2SMark Phalan     krb5_preauth_request_context_init(context);
1170159d09a2SMark Phalan 
1171159d09a2SMark Phalan     /* nonce is filled in by send_as_request if we don't take care of it */
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)) {
11747c478bd9Sstevel@tonic-gate 	request.ktype = options->etype_list;
11757c478bd9Sstevel@tonic-gate 	request.nktypes = options->etype_list_length;
11767c478bd9Sstevel@tonic-gate     } else if ((ret = krb5_get_default_in_tkt_ktypes(context,
11777c478bd9Sstevel@tonic-gate 						     &request.ktype)) == 0) {
11787c478bd9Sstevel@tonic-gate 	for (request.nktypes = 0;
11797c478bd9Sstevel@tonic-gate 	     request.ktype[request.nktypes];
11807c478bd9Sstevel@tonic-gate 	     request.nktypes++)
11817c478bd9Sstevel@tonic-gate 	    ;
11827c478bd9Sstevel@tonic-gate     } else {
11837c478bd9Sstevel@tonic-gate 	/* there isn't any useful default here.  ret is set from above */
11847c478bd9Sstevel@tonic-gate 	goto cleanup;
11857c478bd9Sstevel@tonic-gate     }
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)) {
11887c478bd9Sstevel@tonic-gate 	request.addresses = options->address_list;
11897c478bd9Sstevel@tonic-gate     }
11907c478bd9Sstevel@tonic-gate     /* it would be nice if this parsed out an address list, but
11917c478bd9Sstevel@tonic-gate        that would be work. */
11927c478bd9Sstevel@tonic-gate     else if (((ret = krb5_libdefault_boolean(context, &client->realm,
11937c478bd9Sstevel@tonic-gate 					    "no_addresses", &tempint)) == 0)
1194505d05c7Sgtb 	     || (tempint == 1)) {
11957c478bd9Sstevel@tonic-gate 	    /*EMPTY*/
11967c478bd9Sstevel@tonic-gate 	    ;
11977c478bd9Sstevel@tonic-gate     } else if (((ret = krb5_libdefault_boolean(context, &client->realm,
11987c478bd9Sstevel@tonic-gate 					    "noaddresses", &tempint)) == 0)
1199505d05c7Sgtb 	     || (tempint == 1)) {
12007c478bd9Sstevel@tonic-gate 	    /*EMPTY*/
12017c478bd9Sstevel@tonic-gate 	    ;
12027c478bd9Sstevel@tonic-gate     } else {
12037c478bd9Sstevel@tonic-gate 	if ((ret = krb5_os_localaddr(context, &request.addresses)))
12047c478bd9Sstevel@tonic-gate 	    goto cleanup;
12057c478bd9Sstevel@tonic-gate     }
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate     request.authorization_data.ciphertext.length = 0;
12087c478bd9Sstevel@tonic-gate     request.authorization_data.ciphertext.data = 0;
12097c478bd9Sstevel@tonic-gate     request.unenc_authdata = 0;
12107c478bd9Sstevel@tonic-gate     request.second_ticket = 0;
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate     /* set up the other state.  */
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
1215505d05c7Sgtb 	if ((ret = make_preauth_list(context, options->preauth_list,
1216159d09a2SMark Phalan 				     options->preauth_list_length,
1217159d09a2SMark Phalan 				     &preauth_to_use)))
12187c478bd9Sstevel@tonic-gate 	    goto cleanup;
12197c478bd9Sstevel@tonic-gate     }
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate     /* the salt is allocated from somewhere, unless it is from the caller,
12227c478bd9Sstevel@tonic-gate        then it is a reference */
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)) {
12257c478bd9Sstevel@tonic-gate 	salt = *options->salt;
12267c478bd9Sstevel@tonic-gate     } else {
1227159d09a2SMark Phalan 	salt.length = SALT_TYPE_AFS_LENGTH;
12287c478bd9Sstevel@tonic-gate 	salt.data = NULL;
12297c478bd9Sstevel@tonic-gate     }
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 
1232159d09a2SMark Phalan     /* set the request nonce */
1233159d09a2SMark Phalan     if ((ret = krb5_timeofday(context, &time_now)))
1234159d09a2SMark Phalan 	goto cleanup;
1235159d09a2SMark Phalan     /*
1236159d09a2SMark Phalan      * XXX we know they are the same size... and we should do
1237159d09a2SMark Phalan      * something better than just the current time
1238159d09a2SMark Phalan      */
1239159d09a2SMark Phalan     request.nonce = (krb5_int32) time_now;
1240159d09a2SMark Phalan 
1241159d09a2SMark Phalan     /* give the preauth plugins a chance to prep the request body */
1242159d09a2SMark Phalan     krb5_preauth_prepare_request(context, options, &request);
1243159d09a2SMark Phalan     ret = encode_krb5_kdc_req_body(&request, &encoded_request_body);
1244159d09a2SMark Phalan     if (ret)
1245159d09a2SMark Phalan         goto cleanup;
1246159d09a2SMark Phalan 
1247159d09a2SMark Phalan     get_data_rock.magic = CLIENT_ROCK_MAGIC;
1248159d09a2SMark Phalan     get_data_rock.as_reply = NULL;
1249159d09a2SMark Phalan 
1250159d09a2SMark Phalan     /* now, loop processing preauth data and talking to the kdc */
12517c478bd9Sstevel@tonic-gate     for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) {
12527c478bd9Sstevel@tonic-gate 	if (request.padata) {
12537c478bd9Sstevel@tonic-gate 	    krb5_free_pa_data(context, request.padata);
12547c478bd9Sstevel@tonic-gate 	    request.padata = NULL;
12557c478bd9Sstevel@tonic-gate 	}
1256159d09a2SMark Phalan 	if (!err_reply) {
1257159d09a2SMark Phalan             /* either our first attempt, or retrying after PREAUTH_NEEDED */
1258159d09a2SMark Phalan 	    if ((ret = krb5_do_preauth(context,
1259159d09a2SMark Phalan 				       &request,
1260159d09a2SMark Phalan 				       encoded_request_body,
1261159d09a2SMark Phalan 				       encoded_previous_request,
1262159d09a2SMark Phalan 				       preauth_to_use, &request.padata,
1263159d09a2SMark Phalan 				       &salt, &s2kparams, &etype, &as_key,
1264159d09a2SMark Phalan 				       prompter, prompter_data,
1265159d09a2SMark Phalan 				       gak_fct, gak_data,
1266159d09a2SMark Phalan 				       &get_data_rock, options)))
1267159d09a2SMark Phalan 	        goto cleanup;
1268159d09a2SMark Phalan 	} else {
1269159d09a2SMark Phalan 	    if (preauth_to_use != NULL) {
1270159d09a2SMark Phalan 		/*
1271159d09a2SMark Phalan 		 * Retry after an error other than PREAUTH_NEEDED,
1272159d09a2SMark Phalan 		 * using e-data to figure out what to change.
1273159d09a2SMark Phalan 		 */
1274159d09a2SMark Phalan 		ret = krb5_do_preauth_tryagain(context,
1275159d09a2SMark Phalan 					       &request,
1276159d09a2SMark Phalan 					       encoded_request_body,
1277159d09a2SMark Phalan 					       encoded_previous_request,
1278159d09a2SMark Phalan 					       preauth_to_use, &request.padata,
1279159d09a2SMark Phalan 					       err_reply,
1280159d09a2SMark Phalan 					       &salt, &s2kparams, &etype,
1281159d09a2SMark Phalan 					       &as_key,
1282159d09a2SMark Phalan 					       prompter, prompter_data,
1283159d09a2SMark Phalan 					       gak_fct, gak_data,
1284159d09a2SMark Phalan 					       &get_data_rock, options);
1285159d09a2SMark Phalan 	    } else {
1286159d09a2SMark Phalan 		/* No preauth supplied, so can't query the plug-ins. */
1287159d09a2SMark Phalan 		ret = KRB5KRB_ERR_GENERIC;
1288159d09a2SMark Phalan 	    }
1289159d09a2SMark Phalan 	    if (ret) {
1290159d09a2SMark Phalan 		/* couldn't come up with anything better */
1291159d09a2SMark Phalan 		ret = err_reply->error + ERROR_TABLE_BASE_krb5;
1292159d09a2SMark Phalan 	    }
1293159d09a2SMark Phalan 	    krb5_free_error(context, err_reply);
1294159d09a2SMark Phalan 	    err_reply = NULL;
1295159d09a2SMark Phalan 	    if (ret)
1296159d09a2SMark Phalan 		goto cleanup;
1297159d09a2SMark Phalan 	}
12987c478bd9Sstevel@tonic-gate 
1299159d09a2SMark Phalan         if (encoded_previous_request != NULL) {
1300159d09a2SMark Phalan 	    krb5_free_data(context, encoded_previous_request);
1301159d09a2SMark Phalan 	    encoded_previous_request = NULL;
1302159d09a2SMark Phalan         }
1303159d09a2SMark Phalan         ret = encode_krb5_as_req(&request, &encoded_previous_request);
1304159d09a2SMark Phalan 	if (ret)
13057c478bd9Sstevel@tonic-gate 	    goto cleanup;
13067c478bd9Sstevel@tonic-gate 
13075e01956fSGlenn Barry 	err_reply = NULL;
13087c478bd9Sstevel@tonic-gate 	local_as_reply = 0;
1309cfed4d70SMatt Barden 
1310cfed4d70SMatt Barden 	free(hostname_used);
1311cfed4d70SMatt Barden 	hostname_used = NULL;
1312cfed4d70SMatt Barden 
13135e01956fSGlenn Barry 	if ((ret = send_as_request2(context, &request, &err_reply,
13145e01956fSGlenn Barry 				    &local_as_reply, use_master,
13155e01956fSGlenn Barry 				    &hostname_used)))
13167c478bd9Sstevel@tonic-gate 	    goto cleanup;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	if (err_reply) {
13197c478bd9Sstevel@tonic-gate 	    if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
13207c478bd9Sstevel@tonic-gate 		err_reply->e_data.length > 0) {
1321159d09a2SMark Phalan 		/* reset the list of preauth types to try */
1322159d09a2SMark Phalan 		if (preauth_to_use) {
1323159d09a2SMark Phalan 		    krb5_free_pa_data(context, preauth_to_use);
1324159d09a2SMark Phalan 		    preauth_to_use = NULL;
1325159d09a2SMark Phalan 		}
13267c478bd9Sstevel@tonic-gate 		ret = decode_krb5_padata_sequence(&err_reply->e_data,
1327159d09a2SMark Phalan 						  &preauth_to_use);
13285e01956fSGlenn Barry  		krb5_free_error(context, err_reply);
13295e01956fSGlenn Barry  		err_reply = NULL;
1330159d09a2SMark Phalan 		if (ret)
1331159d09a2SMark Phalan 		    goto cleanup;
1332159d09a2SMark Phalan 		ret = sort_krb5_padata_sequence(context,
1333159d09a2SMark Phalan 						&request.server->realm,
1334159d09a2SMark Phalan 						preauth_to_use);
13357c478bd9Sstevel@tonic-gate 		if (ret)
13367c478bd9Sstevel@tonic-gate 		    goto cleanup;
1337159d09a2SMark Phalan 		/* continue to next iteration */
13387c478bd9Sstevel@tonic-gate 	    } else {
1339159d09a2SMark Phalan 		if (err_reply->e_data.length > 0) {
1340159d09a2SMark Phalan 		    /* continue to next iteration */
1341159d09a2SMark Phalan 		} else {
1342159d09a2SMark Phalan 		    /* error + no hints = give up */
1343159d09a2SMark Phalan 		    ret = (krb5_error_code) err_reply->error
1344159d09a2SMark Phalan 		          + ERROR_TABLE_BASE_krb5;
1345159d09a2SMark Phalan 		    goto cleanup;
1346159d09a2SMark Phalan 		}
13477c478bd9Sstevel@tonic-gate 	    }
13487c478bd9Sstevel@tonic-gate 	} else if (local_as_reply) {
13497c478bd9Sstevel@tonic-gate 	    break;
13507c478bd9Sstevel@tonic-gate 	} else {
13517c478bd9Sstevel@tonic-gate 	    ret = KRB5KRB_AP_ERR_MSG_TYPE;
13527c478bd9Sstevel@tonic-gate 	    goto cleanup;
13537c478bd9Sstevel@tonic-gate 	}
13547c478bd9Sstevel@tonic-gate     }
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate     if (loopcount == MAX_IN_TKT_LOOPS) {
13577c478bd9Sstevel@tonic-gate 	ret = KRB5_GET_IN_TKT_LOOP;
13585e01956fSGlenn Barry 	/* Solaris Kerberos */
13595e01956fSGlenn Barry 	{
13605e01956fSGlenn Barry             char *s_name = NULL;
13615e01956fSGlenn Barry 	    char *c_name = NULL;
13625e01956fSGlenn Barry 	    krb5_error_code serr, cerr;
13635e01956fSGlenn Barry 	    serr = krb5_unparse_name(context, creds->server, &s_name);
13645e01956fSGlenn Barry 	    cerr = krb5_unparse_name(context, creds->client, &c_name);
13655e01956fSGlenn Barry 	    krb5_set_error_message(context, ret,
13665e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
13675e01956fSGlenn Barry 					"Looping detected getting initial creds: '%s' requesting ticket '%s'. Max loops is %d.  Make sure a KDC is available"),
13685e01956fSGlenn Barry 				cerr ? "unknown" : c_name,
13695e01956fSGlenn Barry 				serr ? "unknown" : s_name,
13705e01956fSGlenn Barry 				MAX_IN_TKT_LOOPS);
13715e01956fSGlenn Barry 	    if (s_name)
13725e01956fSGlenn Barry 		krb5_free_unparsed_name(context, s_name);
13735e01956fSGlenn Barry 	    if (c_name)
13745e01956fSGlenn Barry 		krb5_free_unparsed_name(context, c_name);
13755e01956fSGlenn Barry 	}
13767c478bd9Sstevel@tonic-gate 	goto cleanup;
13777c478bd9Sstevel@tonic-gate     }
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate     /* process any preauth data in the as_reply */
1380159d09a2SMark Phalan     krb5_clear_preauth_context_use_counts(context);
1381159d09a2SMark Phalan     if ((ret = sort_krb5_padata_sequence(context, &request.server->realm,
1382159d09a2SMark Phalan 					 local_as_reply->padata)))
1383159d09a2SMark Phalan 	goto cleanup;
1384159d09a2SMark Phalan     get_data_rock.as_reply = local_as_reply;
1385159d09a2SMark Phalan     if ((ret = krb5_do_preauth(context,
1386159d09a2SMark Phalan 			       &request,
1387159d09a2SMark Phalan 			       encoded_request_body, encoded_previous_request,
1388159d09a2SMark Phalan 			       local_as_reply->padata, &kdc_padata,
1389159d09a2SMark Phalan 			       &salt, &s2kparams, &etype, &as_key, prompter,
1390159d09a2SMark Phalan 			       prompter_data, gak_fct, gak_data,
1391159d09a2SMark Phalan 			       &get_data_rock, options)))
13927c478bd9Sstevel@tonic-gate 	goto cleanup;
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate     /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
13957c478bd9Sstevel@tonic-gate        the AS_REP comes back encrypted in the user's longterm key
13967c478bd9Sstevel@tonic-gate        instead of in the SAD. If there was a SAM preauth, there
13977c478bd9Sstevel@tonic-gate        will be an as_key here which will be the SAD. If that fails,
13987c478bd9Sstevel@tonic-gate        use the gak_fct to get the password, and try again. */
1399*55fea89dSDan Cross 
14007c478bd9Sstevel@tonic-gate     /* XXX because etypes are handled poorly (particularly wrt SAM,
14017c478bd9Sstevel@tonic-gate        where the etype is fixed by the kdc), we may want to try
14027c478bd9Sstevel@tonic-gate        decrypt_as_reply twice.  If there's an as_key available, try
14037c478bd9Sstevel@tonic-gate        it.  If decrypting the as_rep fails, or if there isn't an
14047c478bd9Sstevel@tonic-gate        as_key at all yet, then use the gak_fct to get one, and try
14057c478bd9Sstevel@tonic-gate        again.  */
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate     if (as_key.length)
1408159d09a2SMark Phalan 	ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
1409159d09a2SMark Phalan 			       NULL, &as_key, krb5_kdc_rep_decrypt_proc,
1410159d09a2SMark Phalan 			       NULL);
14117c478bd9Sstevel@tonic-gate     else
14127c478bd9Sstevel@tonic-gate 	ret = -1;
1413*55fea89dSDan Cross 
14147c478bd9Sstevel@tonic-gate     if (ret) {
14157c478bd9Sstevel@tonic-gate 	/* if we haven't get gotten a key, get it now */
14167c478bd9Sstevel@tonic-gate 
1417505d05c7Sgtb 	if ((ret = ((*gak_fct)(context, request.client,
1418159d09a2SMark Phalan 			       local_as_reply->enc_part.enctype,
1419159d09a2SMark Phalan 			       prompter, prompter_data, &salt, &s2kparams,
1420159d09a2SMark Phalan 			       &as_key, gak_data))))
14217c478bd9Sstevel@tonic-gate 	    goto cleanup;
14227c478bd9Sstevel@tonic-gate 
1423159d09a2SMark Phalan 	if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
1424159d09a2SMark Phalan 				    NULL, &as_key, krb5_kdc_rep_decrypt_proc,
1425159d09a2SMark Phalan 				    NULL)))
14267c478bd9Sstevel@tonic-gate 	    goto cleanup;
14277c478bd9Sstevel@tonic-gate     }
14287c478bd9Sstevel@tonic-gate 
1429505d05c7Sgtb     if ((ret = verify_as_reply(context, time_now, &request, local_as_reply)))
14307c478bd9Sstevel@tonic-gate 	goto cleanup;
14317c478bd9Sstevel@tonic-gate 
1432159d09a2SMark Phalan     /* XXX this should be inside stash_as_reply, but as long as
1433159d09a2SMark Phalan        get_in_tkt is still around using that arg as an in/out, I can't
1434159d09a2SMark Phalan        do that */
1435159d09a2SMark Phalan 	/* Solaris Kerberos */
14367c478bd9Sstevel@tonic-gate 	(void) memset(creds, 0, sizeof(*creds));
14377c478bd9Sstevel@tonic-gate 
1438159d09a2SMark Phalan     /* Solaris Kerberos */
1439505d05c7Sgtb     if ((ret = stash_as_reply(context, time_now, &request, local_as_reply,
1440505d05c7Sgtb 			      creds, (krb5_ccache)NULL)))
14417c478bd9Sstevel@tonic-gate 	goto cleanup;
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate     /* success */
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate     ret = 0;
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate cleanup:
14485e01956fSGlenn Barry     if (ret != 0) {
14495e01956fSGlenn Barry         char *client_name = NULL;
14505e01956fSGlenn Barry         /* See if we can produce a more detailed error message.  */
14515e01956fSGlenn Barry         switch (ret) {
14525e01956fSGlenn Barry         case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
14535e01956fSGlenn Barry             if (krb5_unparse_name(context, client, &client_name) == 0) {
14545e01956fSGlenn Barry                 krb5_set_error_message(context, ret,
14555e01956fSGlenn Barry                                        dgettext(TEXT_DOMAIN,
14565e01956fSGlenn Barry 						"Client '%s' not found in Kerberos database"),
14575e01956fSGlenn Barry                                        client_name);
14585e01956fSGlenn Barry                 free(client_name);
14595e01956fSGlenn Barry             }
14605e01956fSGlenn Barry             break;
14615e01956fSGlenn Barry         /* Solaris Kerberos: spruce-up the err msg */
14625e01956fSGlenn Barry 	case KRB5_PREAUTH_FAILED:
14635e01956fSGlenn Barry 	case KRB5KDC_ERR_PREAUTH_FAILED:
14645e01956fSGlenn Barry             if (krb5_unparse_name(context, client, &client_name) == 0) {
14655e01956fSGlenn Barry                 krb5_set_error_message(context, ret,
14665e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
14675e01956fSGlenn Barry 				      "Client '%s' pre-authentication failed"),
14685e01956fSGlenn Barry                                        client_name);
14695e01956fSGlenn Barry                 free(client_name);
14705e01956fSGlenn Barry             }
14715e01956fSGlenn Barry             break;
14725e01956fSGlenn Barry 	/* Solaris Kerberos: spruce-up the err msg */
14735e01956fSGlenn Barry 	case KRB5KRB_AP_ERR_SKEW: /* KRB_AP_ERR_SKEW + ERROR_TABLE_BASE_krb5 */
14745e01956fSGlenn Barry 	    {
14755e01956fSGlenn Barry                 char *s_name = NULL;
14765e01956fSGlenn Barry 		char *c_name = NULL;
14775e01956fSGlenn Barry 		char stimestring[17];
14785e01956fSGlenn Barry 		char fill = ' ';
14795e01956fSGlenn Barry 		krb5_error_code c_err, s_err, s_time;
14805e01956fSGlenn Barry 
14815e01956fSGlenn Barry 		s_err = krb5_unparse_name(context,
14825e01956fSGlenn Barry 					err_reply->server, &s_name);
14835e01956fSGlenn Barry 		s_time = krb5_timestamp_to_sfstring(err_reply->stime,
14845e01956fSGlenn Barry 						    stimestring,
14855e01956fSGlenn Barry 						    sizeof (stimestring),
14865e01956fSGlenn Barry 						    &fill);
14875e01956fSGlenn Barry 		c_err = krb5_unparse_name(context, client, &c_name);
14885e01956fSGlenn Barry 		krb5_set_error_message(context, ret,
14895e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
14905e01956fSGlenn Barry 					    "Clock skew too great: '%s' requesting ticket '%s' from KDC '%s' (%s). Skew is %dm"),
14915e01956fSGlenn Barry 				    c_err == 0 ? c_name : "unknown",
14925e01956fSGlenn Barry 				    s_err == 0 ? s_name : "unknown",
14935e01956fSGlenn Barry 				    hostname_used ? hostname_used : "unknown",
14945e01956fSGlenn Barry 				    s_time == 0 ? stimestring : "unknown",
14955e01956fSGlenn Barry 				    (s_time != 0) ? 0 :
14965e01956fSGlenn Barry 				      (abs(err_reply->stime - time_now) / 60));
14975e01956fSGlenn Barry 		if (s_name)
14985e01956fSGlenn Barry 			krb5_free_unparsed_name(context, s_name);
14995e01956fSGlenn Barry 		if (c_name)
15005e01956fSGlenn Barry 			krb5_free_unparsed_name(context, c_name);
15015e01956fSGlenn Barry 	    }
15025e01956fSGlenn Barry 	    break;
15035e01956fSGlenn Barry 	case KRB5_KDCREP_MODIFIED:
15045e01956fSGlenn Barry             if (krb5_unparse_name(context, client, &client_name) == 0) {
15055e01956fSGlenn Barry 		/*
15065e01956fSGlenn Barry 		 * Solaris Kerberos
1507*55fea89dSDan Cross 		 * Extra err msg for common(?) case of
15085e01956fSGlenn Barry 		 * 'kinit user@lower-case-def-realm'.
15095e01956fSGlenn Barry 		 * DNS SRV recs will match (case insensitive) and trigger sendto
15105e01956fSGlenn Barry 		 * KDC and result in this error (at least w/MSFT AD KDC).
15115e01956fSGlenn Barry 		 */
15125e01956fSGlenn Barry 		char *realm = strpbrk(client_name, "@");
15135e01956fSGlenn Barry 		int set = 0;
15145e01956fSGlenn Barry 		if (realm++) {
15155e01956fSGlenn Barry 		    if (realm && realm[0] && is_lower_case(realm)) {
15165e01956fSGlenn Barry 			krb5_set_error_message(context, ret,
15175e01956fSGlenn Barry 					    dgettext(TEXT_DOMAIN,
15185e01956fSGlenn Barry 						    "KDC reply did not match expectations for client '%s': lower-case detected in realm '%s'"),
15195e01956fSGlenn Barry 					    client_name, realm);
15205e01956fSGlenn Barry 			set = 1;
15215e01956fSGlenn Barry 		    }
15225e01956fSGlenn Barry 		}
15235e01956fSGlenn Barry 		if (!set)
15245e01956fSGlenn Barry 		    krb5_set_error_message(context, ret,
15255e01956fSGlenn Barry 					dgettext(TEXT_DOMAIN,
1526*55fea89dSDan Cross 						"KDC reply did not match expectations for client '%s'"),
15275e01956fSGlenn Barry 					client_name);
15285e01956fSGlenn Barry                 free(client_name);
15295e01956fSGlenn Barry             }
15305e01956fSGlenn Barry 	    break;
15315e01956fSGlenn Barry         default:
15325e01956fSGlenn Barry             break;
15335e01956fSGlenn Barry         }
15345e01956fSGlenn Barry     }
15355e01956fSGlenn Barry     if (err_reply)
15365e01956fSGlenn Barry 	    krb5_free_error(context, err_reply);
1537159d09a2SMark Phalan     krb5_preauth_request_context_fini(context);
1538159d09a2SMark Phalan     if (encoded_previous_request != NULL) {
1539159d09a2SMark Phalan 	krb5_free_data(context, encoded_previous_request);
1540159d09a2SMark Phalan 	encoded_previous_request = NULL;
1541159d09a2SMark Phalan     }
1542159d09a2SMark Phalan     if (encoded_request_body != NULL) {
1543159d09a2SMark Phalan 	krb5_free_data(context, encoded_request_body);
1544159d09a2SMark Phalan 	encoded_request_body = NULL;
1545159d09a2SMark Phalan     }
15467c478bd9Sstevel@tonic-gate     if (request.server)
15477c478bd9Sstevel@tonic-gate 	krb5_free_principal(context, request.server);
15487c478bd9Sstevel@tonic-gate     if (request.ktype &&
15497c478bd9Sstevel@tonic-gate 	(!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))))
15507c478bd9Sstevel@tonic-gate 	free(request.ktype);
15517c478bd9Sstevel@tonic-gate     if (request.addresses &&
15527c478bd9Sstevel@tonic-gate 	(!(options &&
15537c478bd9Sstevel@tonic-gate 	   (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST))))
15547c478bd9Sstevel@tonic-gate 	krb5_free_addresses(context, request.addresses);
1555159d09a2SMark Phalan     if (preauth_to_use)
1556159d09a2SMark Phalan 	krb5_free_pa_data(context, preauth_to_use);
1557159d09a2SMark Phalan     if (kdc_padata)
1558159d09a2SMark Phalan 	krb5_free_pa_data(context, kdc_padata);
15597c478bd9Sstevel@tonic-gate     if (request.padata)
15607c478bd9Sstevel@tonic-gate 	krb5_free_pa_data(context, request.padata);
15617c478bd9Sstevel@tonic-gate     if (as_key.length)
15627c478bd9Sstevel@tonic-gate 	krb5_free_keyblock_contents(context, &as_key);
15637c478bd9Sstevel@tonic-gate     if (salt.data &&
15647c478bd9Sstevel@tonic-gate 	(!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT))))
15657c478bd9Sstevel@tonic-gate 	krb5_xfree(salt.data);
1566505d05c7Sgtb     krb5_free_data_contents(context, &s2kparams);
15677c478bd9Sstevel@tonic-gate     if (as_reply)
15687c478bd9Sstevel@tonic-gate 	*as_reply = local_as_reply;
15697c478bd9Sstevel@tonic-gate     else if (local_as_reply)
15707c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, local_as_reply);
15715e01956fSGlenn Barry     if (hostname_used)
15725e01956fSGlenn Barry         free(hostname_used);
15737c478bd9Sstevel@tonic-gate     return(ret);
15747c478bd9Sstevel@tonic-gate }
1575