xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c (revision 159d09a20817016f09b3ea28d1bdada4a336bb91)
17c478bd9Sstevel@tonic-gate /*
2*159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate  * lib/krb5/krb/get_in_tkt.c
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Copyright 1990,1991, 2003 by the Massachusetts Institute of Technology.
117c478bd9Sstevel@tonic-gate  * All Rights Reserved.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
147c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
157c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
167c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
197c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
207c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
217c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
227c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
237c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
247c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
257c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
267c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
277c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
287c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
297c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
307c478bd9Sstevel@tonic-gate  * or implied warranty.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  * krb5_get_in_tkt()
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate 
38*159d09a2SMark Phalan #include "k5-int.h"
39*159d09a2SMark Phalan #include "int-proto.h"
40*159d09a2SMark Phalan #include "os-proto.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,
497c478bd9Sstevel@tonic-gate  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 
70*159d09a2SMark 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,
84505d05c7Sgtb 						       krb5_kdc_rep * );
857c478bd9Sstevel@tonic-gate 
86505d05c7Sgtb static krb5_error_code make_preauth_list (krb5_context,
877c478bd9Sstevel@tonic-gate 						    krb5_preauthtype *,
88505d05c7Sgtb 						    int, krb5_pa_data ***);
89*159d09a2SMark Phalan static krb5_error_code sort_krb5_padata_sequence(krb5_context context,
90*159d09a2SMark Phalan 						 krb5_data *realm,
91*159d09a2SMark 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  */
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     }
106505d05c7Sgtb 
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
117505d05c7Sgtb send_as_request(krb5_context 		context,
118505d05c7Sgtb 		krb5_kdc_req		*request,
119505d05c7Sgtb 		krb5_error ** 		ret_err_reply,
120505d05c7Sgtb 		krb5_kdc_rep ** 	ret_as_reply,
121505d05c7Sgtb 		int 			    *use_master)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate     krb5_kdc_rep *as_reply = 0;
1247c478bd9Sstevel@tonic-gate     krb5_error_code retval;
1257c478bd9Sstevel@tonic-gate     krb5_data *packet = 0;
1267c478bd9Sstevel@tonic-gate     krb5_data reply;
1277c478bd9Sstevel@tonic-gate     char k4_version;		/* same type as *(krb5_data::data) */
1287c478bd9Sstevel@tonic-gate     int tcp_only = 0;
129*159d09a2SMark Phalan     krb5_timestamp time_now;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate     reply.data = 0;
1327c478bd9Sstevel@tonic-gate 
133*159d09a2SMark Phalan     /* set the nonce if the caller expects us to do it */
134*159d09a2SMark Phalan     if (request->nonce == 0) {
135*159d09a2SMark Phalan         if ((retval = krb5_timeofday(context, &time_now)))
1367c478bd9Sstevel@tonic-gate 	    goto cleanup;
137*159d09a2SMark Phalan         request->nonce = (krb5_int32) time_now;
138*159d09a2SMark Phalan     }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate     /* encode & send to KDC */
1417c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_as_req(request, &packet)) != 0)
1427c478bd9Sstevel@tonic-gate 	goto cleanup;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate     k4_version = packet->data[0];
1457c478bd9Sstevel@tonic-gate send_again:
1467c478bd9Sstevel@tonic-gate     retval = krb5_sendto_kdc(context, packet,
1477c478bd9Sstevel@tonic-gate 			     krb5_princ_realm(context, request->client),
1487c478bd9Sstevel@tonic-gate 			     &reply, use_master, tcp_only);
1497c478bd9Sstevel@tonic-gate     if (retval)
1507c478bd9Sstevel@tonic-gate 	goto cleanup;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate     /* now decode the reply...could be error or as_rep */
1537c478bd9Sstevel@tonic-gate     if (krb5_is_krb_error(&reply)) {
1547c478bd9Sstevel@tonic-gate 	krb5_error *err_reply;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	if ((retval = decode_krb5_error(&reply, &err_reply)))
1577c478bd9Sstevel@tonic-gate 	    /* some other error code--??? */
1587c478bd9Sstevel@tonic-gate 	    goto cleanup;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if (ret_err_reply) {
1617c478bd9Sstevel@tonic-gate 	    if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG
1627c478bd9Sstevel@tonic-gate 		&& tcp_only == 0) {
1637c478bd9Sstevel@tonic-gate 		tcp_only = 1;
1647c478bd9Sstevel@tonic-gate 		krb5_free_error(context, err_reply);
1657c478bd9Sstevel@tonic-gate 		free(reply.data);
1667c478bd9Sstevel@tonic-gate 		reply.data = 0;
1677c478bd9Sstevel@tonic-gate 		goto send_again;
1687c478bd9Sstevel@tonic-gate 	    }
1697c478bd9Sstevel@tonic-gate 	    *ret_err_reply = err_reply;
1707c478bd9Sstevel@tonic-gate 	} else
1717c478bd9Sstevel@tonic-gate 	    krb5_free_error(context, err_reply);
1727c478bd9Sstevel@tonic-gate 	goto cleanup;
1737c478bd9Sstevel@tonic-gate     }
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate     /*
1767c478bd9Sstevel@tonic-gate      * Check to make sure it isn't a V4 reply.
1777c478bd9Sstevel@tonic-gate      */
1787c478bd9Sstevel@tonic-gate     if (!krb5_is_as_rep(&reply)) {
1797c478bd9Sstevel@tonic-gate /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
1807c478bd9Sstevel@tonic-gate #define V4_KRB_PROT_VERSION	4
1817c478bd9Sstevel@tonic-gate #define V4_AUTH_MSG_ERR_REPLY	(5<<1)
1827c478bd9Sstevel@tonic-gate 	/* check here for V4 reply */
1837c478bd9Sstevel@tonic-gate 	unsigned int t_switch;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	/* From v4 g_in_tkt.c: This used to be
1867c478bd9Sstevel@tonic-gate 	   switch (pkt_msg_type(rpkt) & ~1) {
1877c478bd9Sstevel@tonic-gate 	   but SCO 3.2v4 cc compiled that incorrectly.  */
1887c478bd9Sstevel@tonic-gate 	t_switch = reply.data[1];
1897c478bd9Sstevel@tonic-gate 	t_switch &= ~1;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (t_switch == V4_AUTH_MSG_ERR_REPLY
1927c478bd9Sstevel@tonic-gate 	    && (reply.data[0] == V4_KRB_PROT_VERSION
1937c478bd9Sstevel@tonic-gate 		|| reply.data[0] == k4_version)) {
1947c478bd9Sstevel@tonic-gate 	    retval = KRB5KRB_AP_ERR_V4_REPLY;
1957c478bd9Sstevel@tonic-gate 	} else {
1967c478bd9Sstevel@tonic-gate 	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 	goto cleanup;
1997c478bd9Sstevel@tonic-gate     }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate     /* It must be a KRB_AS_REP message, or an bad returned packet */
2027c478bd9Sstevel@tonic-gate     if ((retval = decode_krb5_as_rep(&reply, &as_reply)))
2037c478bd9Sstevel@tonic-gate 	/* some other error code ??? */
2047c478bd9Sstevel@tonic-gate 	goto cleanup;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate     if (as_reply->msg_type != KRB5_AS_REP) {
2077c478bd9Sstevel@tonic-gate 	retval = KRB5KRB_AP_ERR_MSG_TYPE;
2087c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, as_reply);
2097c478bd9Sstevel@tonic-gate 	goto cleanup;
2107c478bd9Sstevel@tonic-gate     }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate     if (ret_as_reply)
2137c478bd9Sstevel@tonic-gate 	*ret_as_reply = as_reply;
2147c478bd9Sstevel@tonic-gate     else
2157c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, as_reply);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate cleanup:
2187c478bd9Sstevel@tonic-gate     if (packet)
2197c478bd9Sstevel@tonic-gate 	krb5_free_data(context, packet);
2207c478bd9Sstevel@tonic-gate     if (reply.data)
2217c478bd9Sstevel@tonic-gate 	free(reply.data);
2227c478bd9Sstevel@tonic-gate     return retval;
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate static krb5_error_code
226505d05c7Sgtb decrypt_as_reply(krb5_context 		context,
227505d05c7Sgtb 		 krb5_kdc_req		*request,
228505d05c7Sgtb 		 krb5_kdc_rep		*as_reply,
229505d05c7Sgtb 		 git_key_proc 		key_proc,
230505d05c7Sgtb 		 krb5_const_pointer 	keyseed,
231505d05c7Sgtb 		 krb5_keyblock *	key,
232505d05c7Sgtb 		 git_decrypt_proc 	decrypt_proc,
233505d05c7Sgtb 		 krb5_const_pointer 	decryptarg)
2347c478bd9Sstevel@tonic-gate {
2357c478bd9Sstevel@tonic-gate     krb5_error_code		retval;
2367c478bd9Sstevel@tonic-gate     krb5_keyblock *		decrypt_key = 0;
2377c478bd9Sstevel@tonic-gate     krb5_data 			salt;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate     if (as_reply->enc_part2)
2407c478bd9Sstevel@tonic-gate 	return 0;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate     if (key)
2437c478bd9Sstevel@tonic-gate 	    decrypt_key = key;
244*159d09a2SMark Phalan     /* Solaris Kerberos */
2457c478bd9Sstevel@tonic-gate     else if (request != NULL) {
2467c478bd9Sstevel@tonic-gate 	if ((retval = krb5_principal2salt(context, request->client, &salt)))
2477c478bd9Sstevel@tonic-gate 	    return(retval);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	retval = (*key_proc)(context, as_reply->enc_part.enctype,
2507c478bd9Sstevel@tonic-gate 			     &salt, keyseed, &decrypt_key);
2517c478bd9Sstevel@tonic-gate 	krb5_xfree(salt.data);
2527c478bd9Sstevel@tonic-gate 	if (retval)
2537c478bd9Sstevel@tonic-gate 	    goto cleanup;
2547c478bd9Sstevel@tonic-gate     } else {
2557c478bd9Sstevel@tonic-gate 	KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, "
2567c478bd9Sstevel@tonic-gate 		"error key == NULL and request == NULL");
2577c478bd9Sstevel@tonic-gate 	return (EINVAL);
2587c478bd9Sstevel@tonic-gate     }
2597c478bd9Sstevel@tonic-gate 
260*159d09a2SMark Phalan     /*
261*159d09a2SMark Phalan      * Solaris kerberos: Overwriting the decrypt_key->enctype because the
2627c478bd9Sstevel@tonic-gate      * decrypt key's enctype may not be an exact match with the enctype that the
2637c478bd9Sstevel@tonic-gate      * KDC used to encrypt this part of the AS reply.  This assumes the
2647c478bd9Sstevel@tonic-gate      * as_reply->enc_part.enctype has been validated which is done by checking
2657c478bd9Sstevel@tonic-gate      * to see if the enctype that the KDC sent back in the as_reply is one of
2667c478bd9Sstevel@tonic-gate      * the enctypes originally requested.  Note, if request is NULL then the
2677c478bd9Sstevel@tonic-gate      * as_reply->enc_part.enctype could not be validated.
2687c478bd9Sstevel@tonic-gate      */
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate     if (request != NULL) {
2717c478bd9Sstevel@tonic-gate         if (is_in_keytype(request->ktype, request->nktypes,
2727c478bd9Sstevel@tonic-gate                 as_reply->enc_part.enctype)) {
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	    decrypt_key->enctype = as_reply->enc_part.enctype;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	} else {
2777c478bd9Sstevel@tonic-gate 	    KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, "
2787c478bd9Sstevel@tonic-gate 		    "error is_in_keytype() returned false");
2797c478bd9Sstevel@tonic-gate 	    retval = KRB5_BAD_ENCTYPE;
2807c478bd9Sstevel@tonic-gate 	    goto cleanup;
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate     }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate     if ((retval = (*decrypt_proc)(context, decrypt_key, decryptarg, as_reply))){
2857c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "decrypt_as_reply() error (*decrypt_proc)() retval "
2867c478bd9Sstevel@tonic-gate 			    "= %d", retval);
2877c478bd9Sstevel@tonic-gate 	goto cleanup;
2887c478bd9Sstevel@tonic-gate     }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate cleanup:
2917c478bd9Sstevel@tonic-gate     if (!key && decrypt_key)
2927c478bd9Sstevel@tonic-gate 	krb5_free_keyblock(context, decrypt_key);
2937c478bd9Sstevel@tonic-gate     return (retval);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate static krb5_error_code
297505d05c7Sgtb verify_as_reply(krb5_context 		context,
298505d05c7Sgtb 		krb5_timestamp 		time_now,
299505d05c7Sgtb 		krb5_kdc_req		*request,
300505d05c7Sgtb 		krb5_kdc_rep		*as_reply)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate     krb5_error_code		retval;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate     /* check the contents for sanity: */
3057c478bd9Sstevel@tonic-gate     if (!as_reply->enc_part2->times.starttime)
3067c478bd9Sstevel@tonic-gate 	as_reply->enc_part2->times.starttime =
3077c478bd9Sstevel@tonic-gate 	    as_reply->enc_part2->times.authtime;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate     if (!krb5_principal_compare(context, as_reply->client, request->client)
3107c478bd9Sstevel@tonic-gate 	|| !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)
3117c478bd9Sstevel@tonic-gate 	|| !krb5_principal_compare(context, as_reply->ticket->server, request->server)
3127c478bd9Sstevel@tonic-gate 	|| (request->nonce != as_reply->enc_part2->nonce)
3137c478bd9Sstevel@tonic-gate 	/* XXX check for extraneous flags */
3147c478bd9Sstevel@tonic-gate 	/* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
3157c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_POSTDATED) &&
3167c478bd9Sstevel@tonic-gate 	    (request->from != 0) &&
3177c478bd9Sstevel@tonic-gate 	    (request->from != as_reply->enc_part2->times.starttime))
3187c478bd9Sstevel@tonic-gate 	|| ((request->till != 0) &&
3197c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.endtime > request->till))
3207c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_RENEWABLE) &&
3213441f6a1Ssemery 	    /*
3223441f6a1Ssemery 	     * Solaris Kerberos: Here we error only if renewable_ok was not set.
3233441f6a1Ssemery 	     */
3243441f6a1Ssemery 	    !(request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
3253441f6a1Ssemery 	    (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
3267c478bd9Sstevel@tonic-gate 	    (request->rtime != 0) &&
3277c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.renew_till > request->rtime))
3287c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
3297c478bd9Sstevel@tonic-gate 	    !(request->kdc_options & KDC_OPT_RENEWABLE) &&
3307c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
3317c478bd9Sstevel@tonic-gate 	    (request->till != 0) &&
3327c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.renew_till > request->till))
3333441f6a1Ssemery 	    /*
3343441f6a1Ssemery 	     * Solaris Kerberos: renew_till should never be greater than till or
3353441f6a1Ssemery 	     * rtime.
3363441f6a1Ssemery 	     */
3373441f6a1Ssemery 	|| ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
3383441f6a1Ssemery 	    (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
3393441f6a1Ssemery 	    (request->till != 0) &&
3403441f6a1Ssemery 	    (request->rtime != 0) &&
3413441f6a1Ssemery 	    (as_reply->enc_part2->times.renew_till > max(request->till,
3423441f6a1Ssemery 	     request->rtime)))
3437c478bd9Sstevel@tonic-gate 	)
3447c478bd9Sstevel@tonic-gate 	return KRB5_KDCREP_MODIFIED;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate     if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
3477c478bd9Sstevel@tonic-gate 	retval = krb5_set_real_time(context,
3487c478bd9Sstevel@tonic-gate 				    as_reply->enc_part2->times.authtime, 0);
3497c478bd9Sstevel@tonic-gate 	if (retval)
3507c478bd9Sstevel@tonic-gate 	    return retval;
3517c478bd9Sstevel@tonic-gate     } else {
3527c478bd9Sstevel@tonic-gate 	if ((request->from == 0) &&
3537c478bd9Sstevel@tonic-gate 	    (labs(as_reply->enc_part2->times.starttime - time_now)
3547c478bd9Sstevel@tonic-gate 	     > context->clockskew))
3557c478bd9Sstevel@tonic-gate 	    return (KRB5_KDCREP_SKEW);
3567c478bd9Sstevel@tonic-gate     }
3577c478bd9Sstevel@tonic-gate     return 0;
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3617c478bd9Sstevel@tonic-gate static krb5_error_code
362505d05c7Sgtb stash_as_reply(krb5_context 		context,
363505d05c7Sgtb 	       krb5_timestamp 		time_now,
364505d05c7Sgtb 	       krb5_kdc_req		*request,
365505d05c7Sgtb 	       krb5_kdc_rep		*as_reply,
366505d05c7Sgtb 	       krb5_creds * 		creds,
367505d05c7Sgtb 	       krb5_ccache 		ccache)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate     krb5_error_code 		retval;
3707c478bd9Sstevel@tonic-gate     krb5_data *			packet;
3717c478bd9Sstevel@tonic-gate     krb5_principal		client;
3727c478bd9Sstevel@tonic-gate     krb5_principal		server;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate     client = NULL;
3757c478bd9Sstevel@tonic-gate     server = NULL;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate     if (!creds->client)
378505d05c7Sgtb         if ((retval = krb5_copy_principal(context, as_reply->client, &client)))
3797c478bd9Sstevel@tonic-gate 	    goto cleanup;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate     if (!creds->server)
382505d05c7Sgtb 	if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server,
383505d05c7Sgtb 					  &server)))
3847c478bd9Sstevel@tonic-gate 	    goto cleanup;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate     /* fill in the credentials */
3877c478bd9Sstevel@tonic-gate     if ((retval = krb5_copy_keyblock_contents(context,
3887c478bd9Sstevel@tonic-gate 					      as_reply->enc_part2->session,
3897c478bd9Sstevel@tonic-gate 					      &creds->keyblock)))
3907c478bd9Sstevel@tonic-gate 	goto cleanup;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate     creds->times = as_reply->enc_part2->times;
3937c478bd9Sstevel@tonic-gate     creds->is_skey = FALSE;		/* this is an AS_REQ, so cannot
3947c478bd9Sstevel@tonic-gate 					   be encrypted in skey */
3957c478bd9Sstevel@tonic-gate     creds->ticket_flags = as_reply->enc_part2->flags;
3967c478bd9Sstevel@tonic-gate     if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs,
3977c478bd9Sstevel@tonic-gate 				      &creds->addresses)))
3987c478bd9Sstevel@tonic-gate 	goto cleanup;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate     creds->second_ticket.length = 0;
4017c478bd9Sstevel@tonic-gate     creds->second_ticket.data = 0;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_ticket(as_reply->ticket, &packet)))
4047c478bd9Sstevel@tonic-gate 	goto cleanup;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate     creds->ticket = *packet;
4077c478bd9Sstevel@tonic-gate     krb5_xfree(packet);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate     /* store it in the ccache! */
410*159d09a2SMark Phalan     if (ccache) /* Solaris Kerberos */
4117c478bd9Sstevel@tonic-gate 	if ((retval = krb5_cc_store_cred(context, ccache, creds)) !=0)
4127c478bd9Sstevel@tonic-gate 	    goto cleanup;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate     if (!creds->client)
4157c478bd9Sstevel@tonic-gate 	creds->client = client;
4167c478bd9Sstevel@tonic-gate     if (!creds->server)
4177c478bd9Sstevel@tonic-gate 	creds->server = server;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate cleanup:
4207c478bd9Sstevel@tonic-gate     if (retval) {
4217c478bd9Sstevel@tonic-gate 	if (client)
4227c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, client);
4237c478bd9Sstevel@tonic-gate 	if (server)
4247c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, server);
4257c478bd9Sstevel@tonic-gate 	if (creds->keyblock.contents) {
4267c478bd9Sstevel@tonic-gate 	    memset((char *)creds->keyblock.contents, 0,
4277c478bd9Sstevel@tonic-gate 		   creds->keyblock.length);
4287c478bd9Sstevel@tonic-gate 	    krb5_xfree(creds->keyblock.contents);
4297c478bd9Sstevel@tonic-gate 	    creds->keyblock.contents = 0;
4307c478bd9Sstevel@tonic-gate 	    creds->keyblock.length = 0;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 	if (creds->ticket.data) {
4337c478bd9Sstevel@tonic-gate 	    krb5_xfree(creds->ticket.data);
4347c478bd9Sstevel@tonic-gate 	    creds->ticket.data = 0;
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 	if (creds->addresses) {
4377c478bd9Sstevel@tonic-gate 	    krb5_free_addresses(context, creds->addresses);
4387c478bd9Sstevel@tonic-gate 	    creds->addresses = 0;
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate     }
4417c478bd9Sstevel@tonic-gate     return (retval);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4457c478bd9Sstevel@tonic-gate static krb5_error_code
446505d05c7Sgtb make_preauth_list(krb5_context	context,
447505d05c7Sgtb 		  krb5_preauthtype *	ptypes,
448505d05c7Sgtb 		  int			nptypes,
449505d05c7Sgtb 		  krb5_pa_data ***	ret_list)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate     krb5_preauthtype *		ptypep;
4527c478bd9Sstevel@tonic-gate     krb5_pa_data **		preauthp;
4537c478bd9Sstevel@tonic-gate     int				i;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate     if (nptypes < 0) {
4567c478bd9Sstevel@tonic-gate  	for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++)
4577c478bd9Sstevel@tonic-gate  	    ;
4587c478bd9Sstevel@tonic-gate     }
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate     /* allocate space for a NULL to terminate the list */
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate     if ((preauthp =
4637c478bd9Sstevel@tonic-gate  	 (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
4647c478bd9Sstevel@tonic-gate  	return(ENOMEM);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate     for (i=0; i<nptypes; i++) {
4677c478bd9Sstevel@tonic-gate  	if ((preauthp[i] =
4687c478bd9Sstevel@tonic-gate  	     (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
4697c478bd9Sstevel@tonic-gate  	    for (; i>=0; i++)
4707c478bd9Sstevel@tonic-gate  		free(preauthp[i]);
4717c478bd9Sstevel@tonic-gate  	    free(preauthp);
4727c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate  	preauthp[i]->magic = KV5M_PA_DATA;
4757c478bd9Sstevel@tonic-gate  	preauthp[i]->pa_type = ptypes[i];
4767c478bd9Sstevel@tonic-gate  	preauthp[i]->length = 0;
4777c478bd9Sstevel@tonic-gate  	preauthp[i]->contents = 0;
4787c478bd9Sstevel@tonic-gate     }
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate     /* fill in the terminating NULL */
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate     preauthp[nptypes] = NULL;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate     *ret_list = preauthp;
4857c478bd9Sstevel@tonic-gate     return 0;
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate #define MAX_IN_TKT_LOOPS 16
489505d05c7Sgtb static const krb5_enctype get_in_tkt_enctypes[] = {
490505d05c7Sgtb     ENCTYPE_DES3_CBC_SHA1,
491505d05c7Sgtb     ENCTYPE_ARCFOUR_HMAC,
492505d05c7Sgtb     ENCTYPE_DES_CBC_MD5,
493505d05c7Sgtb     ENCTYPE_DES_CBC_MD4,
494505d05c7Sgtb     ENCTYPE_DES_CBC_CRC,
495505d05c7Sgtb     0
496505d05c7Sgtb };
497*159d09a2SMark Phalan 
498*159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV
499*159d09a2SMark Phalan krb5_get_in_tkt(krb5_context context,
500*159d09a2SMark Phalan 		const krb5_flags options,
501*159d09a2SMark Phalan 		krb5_address * const * addrs,
502*159d09a2SMark Phalan 		krb5_enctype * ktypes,
503*159d09a2SMark Phalan 		krb5_preauthtype * ptypes,
504*159d09a2SMark Phalan 		git_key_proc key_proc,
505*159d09a2SMark Phalan 		krb5_const_pointer keyseed,
506*159d09a2SMark Phalan 		git_decrypt_proc decrypt_proc,
507*159d09a2SMark Phalan 		krb5_const_pointer decryptarg,
508*159d09a2SMark Phalan 		krb5_creds * creds,
509*159d09a2SMark Phalan 		krb5_ccache ccache,
510*159d09a2SMark Phalan 		krb5_kdc_rep ** ret_as_reply)
511*159d09a2SMark Phalan {
512*159d09a2SMark Phalan     krb5_error_code	retval;
513*159d09a2SMark Phalan     krb5_timestamp	time_now;
514*159d09a2SMark Phalan     krb5_keyblock *	decrypt_key = 0;
515*159d09a2SMark Phalan     krb5_kdc_req	request;
516*159d09a2SMark Phalan     krb5_pa_data	**padata = 0;
517*159d09a2SMark Phalan     krb5_error *	err_reply;
518*159d09a2SMark Phalan     krb5_kdc_rep *	as_reply = 0;
519*159d09a2SMark Phalan     krb5_pa_data  **	preauth_to_use = 0;
520*159d09a2SMark Phalan     int			loopcount = 0;
521*159d09a2SMark Phalan     krb5_int32		do_more = 0;
522*159d09a2SMark Phalan     int             use_master = 0;
523*159d09a2SMark Phalan 
524*159d09a2SMark Phalan     if (! krb5_realm_compare(context, creds->client, creds->server))
525*159d09a2SMark Phalan 	return KRB5_IN_TKT_REALM_MISMATCH;
526*159d09a2SMark Phalan 
527*159d09a2SMark Phalan     if (ret_as_reply)
528*159d09a2SMark Phalan 	*ret_as_reply = 0;
529*159d09a2SMark Phalan 
530*159d09a2SMark Phalan     /*
531*159d09a2SMark Phalan      * Set up the basic request structure
532*159d09a2SMark Phalan      */
533*159d09a2SMark Phalan     request.magic = KV5M_KDC_REQ;
534*159d09a2SMark Phalan     request.msg_type = KRB5_AS_REQ;
535*159d09a2SMark Phalan     request.addresses = 0;
536*159d09a2SMark Phalan     request.ktype = 0;
537*159d09a2SMark Phalan     request.padata = 0;
538*159d09a2SMark Phalan     if (addrs)
539*159d09a2SMark Phalan 	request.addresses = (krb5_address **) addrs;
540*159d09a2SMark Phalan     else
541*159d09a2SMark Phalan 	if ((retval = krb5_os_localaddr(context, &request.addresses)))
542*159d09a2SMark Phalan 	    goto cleanup;
543*159d09a2SMark Phalan     request.kdc_options = options;
544*159d09a2SMark Phalan     request.client = creds->client;
545*159d09a2SMark Phalan     request.server = creds->server;
546*159d09a2SMark Phalan     request.nonce = 0;
547*159d09a2SMark Phalan     request.from = creds->times.starttime;
548*159d09a2SMark Phalan     request.till = creds->times.endtime;
549*159d09a2SMark Phalan     request.rtime = creds->times.renew_till;
550*159d09a2SMark Phalan 
551*159d09a2SMark Phalan     request.ktype = malloc (sizeof(get_in_tkt_enctypes));
552*159d09a2SMark Phalan     if (request.ktype == NULL) {
553*159d09a2SMark Phalan 	retval = ENOMEM;
554*159d09a2SMark Phalan 	goto cleanup;
555*159d09a2SMark Phalan     }
556*159d09a2SMark Phalan     memcpy(request.ktype, get_in_tkt_enctypes, sizeof(get_in_tkt_enctypes));
557*159d09a2SMark Phalan     for (request.nktypes = 0;request.ktype[request.nktypes];request.nktypes++);
558*159d09a2SMark Phalan     if (ktypes) {
559*159d09a2SMark Phalan 	int i, req, next = 0;
560*159d09a2SMark Phalan 	for (req = 0; ktypes[req]; req++) {
561*159d09a2SMark Phalan 	    if (ktypes[req] == request.ktype[next]) {
562*159d09a2SMark Phalan 		next++;
563*159d09a2SMark Phalan 		continue;
564*159d09a2SMark Phalan 	    }
565*159d09a2SMark Phalan 	    for (i = next + 1; i < request.nktypes; i++)
566*159d09a2SMark Phalan 		if (ktypes[req] == request.ktype[i]) {
567*159d09a2SMark Phalan 		    /* Found the enctype we want, but not in the
568*159d09a2SMark Phalan 		       position we want.  Move it, but keep the old
569*159d09a2SMark Phalan 		       one from the desired slot around in case it's
570*159d09a2SMark Phalan 		       later in our requested-ktypes list.  */
571*159d09a2SMark Phalan 		    krb5_enctype t;
572*159d09a2SMark Phalan 		    t = request.ktype[next];
573*159d09a2SMark Phalan 		    request.ktype[next] = request.ktype[i];
574*159d09a2SMark Phalan 		    request.ktype[i] = t;
575*159d09a2SMark Phalan 		    next++;
576*159d09a2SMark Phalan 		    break;
577*159d09a2SMark Phalan 		}
578*159d09a2SMark Phalan 	    /* If we didn't find it, don't do anything special, just
579*159d09a2SMark Phalan 	       drop it.  */
580*159d09a2SMark Phalan 	}
581*159d09a2SMark Phalan 	request.ktype[next] = 0;
582*159d09a2SMark Phalan 	request.nktypes = next;
583*159d09a2SMark Phalan     }
584*159d09a2SMark Phalan     request.authorization_data.ciphertext.length = 0;
585*159d09a2SMark Phalan     request.authorization_data.ciphertext.data = 0;
586*159d09a2SMark Phalan     request.unenc_authdata = 0;
587*159d09a2SMark Phalan     request.second_ticket = 0;
588*159d09a2SMark Phalan 
589*159d09a2SMark Phalan     /*
590*159d09a2SMark Phalan      * If a list of preauth types are passed in, convert it to a
591*159d09a2SMark Phalan      * preauth_to_use list.
592*159d09a2SMark Phalan      */
593*159d09a2SMark Phalan     if (ptypes) {
594*159d09a2SMark Phalan 	retval = make_preauth_list(context, ptypes, -1, &preauth_to_use);
595*159d09a2SMark Phalan 	if (retval)
596*159d09a2SMark Phalan 	    goto cleanup;
597*159d09a2SMark Phalan     }
598*159d09a2SMark Phalan 
599*159d09a2SMark Phalan     while (1) {
600*159d09a2SMark Phalan 	if (loopcount++ > MAX_IN_TKT_LOOPS) {
601*159d09a2SMark Phalan 	    retval = KRB5_GET_IN_TKT_LOOP;
602*159d09a2SMark Phalan 	    goto cleanup;
603*159d09a2SMark Phalan 	}
604*159d09a2SMark Phalan 
605*159d09a2SMark Phalan 	if ((retval = krb5_obtain_padata(context, preauth_to_use, key_proc,
606*159d09a2SMark Phalan 					 keyseed, creds, &request)) != 0)
607*159d09a2SMark Phalan 	    goto cleanup;
608*159d09a2SMark Phalan 	if (preauth_to_use)
609*159d09a2SMark Phalan 	    krb5_free_pa_data(context, preauth_to_use);
610*159d09a2SMark Phalan 	preauth_to_use = 0;
611*159d09a2SMark Phalan 
612*159d09a2SMark Phalan 	err_reply = 0;
613*159d09a2SMark Phalan 	as_reply = 0;
614*159d09a2SMark Phalan 
615*159d09a2SMark Phalan         if ((retval = krb5_timeofday(context, &time_now)))
616*159d09a2SMark Phalan 	    goto cleanup;
617*159d09a2SMark Phalan 
618*159d09a2SMark Phalan         /*
619*159d09a2SMark Phalan          * XXX we know they are the same size... and we should do
620*159d09a2SMark Phalan          * something better than just the current time
621*159d09a2SMark Phalan          */
622*159d09a2SMark Phalan 	request.nonce = (krb5_int32) time_now;
623*159d09a2SMark Phalan 
624*159d09a2SMark Phalan 	if ((retval = send_as_request(context, &request, &err_reply,
625*159d09a2SMark Phalan 				      &as_reply, &use_master)))
626*159d09a2SMark Phalan 	    goto cleanup;
627*159d09a2SMark Phalan 
628*159d09a2SMark Phalan 	if (err_reply) {
629*159d09a2SMark Phalan 	    if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
630*159d09a2SMark Phalan 		err_reply->e_data.length > 0) {
631*159d09a2SMark Phalan 		retval = decode_krb5_padata_sequence(&err_reply->e_data,
632*159d09a2SMark Phalan 						     &preauth_to_use);
633*159d09a2SMark Phalan 		krb5_free_error(context, err_reply);
634*159d09a2SMark Phalan 		if (retval)
635*159d09a2SMark Phalan 		    goto cleanup;
636*159d09a2SMark Phalan                 retval = sort_krb5_padata_sequence(context,
637*159d09a2SMark Phalan 						   &request.server->realm,
638*159d09a2SMark Phalan 						   padata);
639*159d09a2SMark Phalan 		if (retval)
640*159d09a2SMark Phalan 		    goto cleanup;
641*159d09a2SMark Phalan 		continue;
642*159d09a2SMark Phalan 	    } else {
643*159d09a2SMark Phalan 		retval = (krb5_error_code) err_reply->error
644*159d09a2SMark Phalan 		    + ERROR_TABLE_BASE_krb5;
645*159d09a2SMark Phalan 		krb5_free_error(context, err_reply);
646*159d09a2SMark Phalan 		goto cleanup;
647*159d09a2SMark Phalan 	    }
648*159d09a2SMark Phalan 	} else if (!as_reply) {
649*159d09a2SMark Phalan 	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
650*159d09a2SMark Phalan 	    goto cleanup;
651*159d09a2SMark Phalan 	}
652*159d09a2SMark Phalan 	if ((retval = krb5_process_padata(context, &request, as_reply,
653*159d09a2SMark Phalan 					  key_proc, keyseed, decrypt_proc,
654*159d09a2SMark Phalan 					  &decrypt_key, creds,
655*159d09a2SMark Phalan 					  &do_more)) != 0)
656*159d09a2SMark Phalan 	    goto cleanup;
657*159d09a2SMark Phalan 
658*159d09a2SMark Phalan 	if (!do_more)
659*159d09a2SMark Phalan 	    break;
660*159d09a2SMark Phalan     }
661*159d09a2SMark Phalan 
662*159d09a2SMark Phalan     if ((retval = decrypt_as_reply(context, &request, as_reply, key_proc,
663*159d09a2SMark Phalan 				   keyseed, decrypt_key, decrypt_proc,
664*159d09a2SMark Phalan 				   decryptarg)))
665*159d09a2SMark Phalan 	goto cleanup;
666*159d09a2SMark Phalan 
667*159d09a2SMark Phalan     if ((retval = verify_as_reply(context, time_now, &request, as_reply)))
668*159d09a2SMark Phalan 	goto cleanup;
669*159d09a2SMark Phalan 
670*159d09a2SMark Phalan     if ((retval = stash_as_reply(context, time_now, &request, as_reply,
671*159d09a2SMark Phalan 				 creds, ccache)))
672*159d09a2SMark Phalan 	goto cleanup;
673*159d09a2SMark Phalan 
674*159d09a2SMark Phalan cleanup:
675*159d09a2SMark Phalan     if (request.ktype)
676*159d09a2SMark Phalan 	free(request.ktype);
677*159d09a2SMark Phalan     if (!addrs && request.addresses)
678*159d09a2SMark Phalan 	krb5_free_addresses(context, request.addresses);
679*159d09a2SMark Phalan     if (request.padata)
680*159d09a2SMark Phalan 	krb5_free_pa_data(context, request.padata);
681*159d09a2SMark Phalan     if (padata)
682*159d09a2SMark Phalan 	krb5_free_pa_data(context, padata);
683*159d09a2SMark Phalan     if (preauth_to_use)
684*159d09a2SMark Phalan 	krb5_free_pa_data(context, preauth_to_use);
685*159d09a2SMark Phalan     if (decrypt_key)
686*159d09a2SMark Phalan     	krb5_free_keyblock(context, decrypt_key);
687*159d09a2SMark Phalan     if (as_reply) {
688*159d09a2SMark Phalan 	if (ret_as_reply)
689*159d09a2SMark Phalan 	    *ret_as_reply = as_reply;
690*159d09a2SMark Phalan 	else
691*159d09a2SMark Phalan 	    krb5_free_kdc_rep(context, as_reply);
692*159d09a2SMark Phalan     }
693*159d09a2SMark Phalan     return (retval);
694*159d09a2SMark Phalan }
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate /* begin libdefaults parsing code.  This should almost certainly move
6977c478bd9Sstevel@tonic-gate    somewhere else, but I don't know where the correct somewhere else
6987c478bd9Sstevel@tonic-gate    is yet. */
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate /* XXX Duplicating this is annoying; try to work on a better way.*/
701505d05c7Sgtb static const char *const conf_yes[] = {
7027c478bd9Sstevel@tonic-gate     "y", "yes", "true", "t", "1", "on",
7037c478bd9Sstevel@tonic-gate     0,
7047c478bd9Sstevel@tonic-gate };
7057c478bd9Sstevel@tonic-gate 
706505d05c7Sgtb static const char *const conf_no[] = {
7077c478bd9Sstevel@tonic-gate     "n", "no", "false", "nil", "0", "off",
7087c478bd9Sstevel@tonic-gate     0,
7097c478bd9Sstevel@tonic-gate };
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate int
712505d05c7Sgtb _krb5_conf_boolean(const char *s)
7137c478bd9Sstevel@tonic-gate {
714505d05c7Sgtb     const char *const *p;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate     for(p=conf_yes; *p; p++) {
7177c478bd9Sstevel@tonic-gate 	if (!strcasecmp(*p,s))
7187c478bd9Sstevel@tonic-gate 	    return 1;
7197c478bd9Sstevel@tonic-gate     }
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate     for(p=conf_no; *p; p++) {
7227c478bd9Sstevel@tonic-gate 	if (!strcasecmp(*p,s))
7237c478bd9Sstevel@tonic-gate 	    return 0;
7247c478bd9Sstevel@tonic-gate     }
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate     /* Default to "no" */
7277c478bd9Sstevel@tonic-gate     return 0;
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate static krb5_error_code
731505d05c7Sgtb krb5_libdefault_string(krb5_context context, const krb5_data *realm,
732505d05c7Sgtb 		       const char *option, char **ret_value)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate     profile_t profile;
7357c478bd9Sstevel@tonic-gate     const char *names[5];
7367c478bd9Sstevel@tonic-gate     char **nameval = NULL;
7377c478bd9Sstevel@tonic-gate     krb5_error_code retval;
7387c478bd9Sstevel@tonic-gate     char realmstr[1024];
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate     if (realm->length > sizeof(realmstr)-1)
7417c478bd9Sstevel@tonic-gate 	return(EINVAL);
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate     strncpy(realmstr, realm->data, realm->length);
7447c478bd9Sstevel@tonic-gate     realmstr[realm->length] = '\0';
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate     if (!context || (context->magic != KV5M_CONTEXT))
7477c478bd9Sstevel@tonic-gate 	return KV5M_CONTEXT;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate     profile = context->profile;
7507c478bd9Sstevel@tonic-gate 
751*159d09a2SMark Phalan     /* Solaris Kerberos */
7527c478bd9Sstevel@tonic-gate     names[0] = "realms";
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate     /*
7557c478bd9Sstevel@tonic-gate      * Try number one:
7567c478bd9Sstevel@tonic-gate      *
7577c478bd9Sstevel@tonic-gate      * [realms]
7587c478bd9Sstevel@tonic-gate      *		REALM = {
7597c478bd9Sstevel@tonic-gate      *			option = <boolean>
7607c478bd9Sstevel@tonic-gate      *		}
7617c478bd9Sstevel@tonic-gate      */
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate     names[1] = realmstr;
7647c478bd9Sstevel@tonic-gate     names[2] = option;
7657c478bd9Sstevel@tonic-gate     names[3] = 0;
7667c478bd9Sstevel@tonic-gate     retval = profile_get_values(profile, names, &nameval);
7677c478bd9Sstevel@tonic-gate     if (retval == 0 && nameval && nameval[0])
7687c478bd9Sstevel@tonic-gate 	goto goodbye;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate     /*
7717c478bd9Sstevel@tonic-gate      * Try number two:
7727c478bd9Sstevel@tonic-gate      *
7737c478bd9Sstevel@tonic-gate      * [libdefaults]
7747c478bd9Sstevel@tonic-gate      *		option = <boolean>
7757c478bd9Sstevel@tonic-gate      */
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate     names[0] = "libdefaults";
7787c478bd9Sstevel@tonic-gate     names[1] = option;
7797c478bd9Sstevel@tonic-gate     names[2] = 0;
7807c478bd9Sstevel@tonic-gate     retval = profile_get_values(profile, names, &nameval);
7817c478bd9Sstevel@tonic-gate     if (retval == 0 && nameval && nameval[0])
7827c478bd9Sstevel@tonic-gate 	goto goodbye;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate goodbye:
7857c478bd9Sstevel@tonic-gate     if (!nameval)
7867c478bd9Sstevel@tonic-gate 	return(ENOENT);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate     if (!nameval[0]) {
7897c478bd9Sstevel@tonic-gate         retval = ENOENT;
7907c478bd9Sstevel@tonic-gate     } else {
7917c478bd9Sstevel@tonic-gate         *ret_value = malloc(strlen(nameval[0]) + 1);
7927c478bd9Sstevel@tonic-gate         if (!*ret_value)
7937c478bd9Sstevel@tonic-gate             retval = ENOMEM;
7947c478bd9Sstevel@tonic-gate         else
7957c478bd9Sstevel@tonic-gate             strcpy(*ret_value, nameval[0]);
7967c478bd9Sstevel@tonic-gate     }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate     profile_free_list(nameval);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate     return retval;
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate /* not static so verify_init_creds() can call it */
8047c478bd9Sstevel@tonic-gate /* as well as the DNS code */
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate krb5_error_code
807505d05c7Sgtb krb5_libdefault_boolean(krb5_context context, const krb5_data *realm,
808505d05c7Sgtb 			const char *option, int *ret_value)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate     char *string = NULL;
8117c478bd9Sstevel@tonic-gate     krb5_error_code retval;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate     retval = krb5_libdefault_string(context, realm, option, &string);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate     if (retval)
8167c478bd9Sstevel@tonic-gate 	return(retval);
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate     *ret_value = _krb5_conf_boolean(string);
8197c478bd9Sstevel@tonic-gate     free(string);
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate     return(0);
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate 
824*159d09a2SMark Phalan /* Sort a pa_data sequence so that types named in the "preferred_preauth_types"
825*159d09a2SMark Phalan  * libdefaults entry are listed before any others. */
826*159d09a2SMark Phalan static krb5_error_code
827*159d09a2SMark Phalan sort_krb5_padata_sequence(krb5_context context, krb5_data *realm,
828*159d09a2SMark Phalan 			  krb5_pa_data **padata)
829*159d09a2SMark Phalan {
830*159d09a2SMark Phalan     int i, j, base;
831*159d09a2SMark Phalan     krb5_error_code ret;
832*159d09a2SMark Phalan     const char *p;
833*159d09a2SMark Phalan     long l;
834*159d09a2SMark Phalan     char *q, *preauth_types = NULL;
835*159d09a2SMark Phalan     krb5_pa_data *tmp;
836*159d09a2SMark Phalan     int need_free_string = 1;
837*159d09a2SMark Phalan 
838*159d09a2SMark Phalan     if ((padata == NULL) || (padata[0] == NULL)) {
839*159d09a2SMark Phalan 	return 0;
840*159d09a2SMark Phalan     }
841*159d09a2SMark Phalan 
842*159d09a2SMark Phalan     ret = krb5_libdefault_string(context, realm, "preferred_preauth_types",
843*159d09a2SMark Phalan 				 &preauth_types);
844*159d09a2SMark Phalan     if ((ret != 0) || (preauth_types == NULL)) {
845*159d09a2SMark Phalan 	/* Try to use PKINIT first. */
846*159d09a2SMark Phalan 	preauth_types = "17, 16, 15, 14";
847*159d09a2SMark Phalan 	need_free_string = 0;
848*159d09a2SMark Phalan     }
849*159d09a2SMark Phalan 
850*159d09a2SMark Phalan #ifdef DEBUG
851*159d09a2SMark Phalan     fprintf (stderr, "preauth data types before sorting:");
852*159d09a2SMark Phalan     for (i = 0; padata[i]; i++) {
853*159d09a2SMark Phalan 	fprintf (stderr, " %d", padata[i]->pa_type);
854*159d09a2SMark Phalan     }
855*159d09a2SMark Phalan     fprintf (stderr, "\n");
856*159d09a2SMark Phalan #endif
857*159d09a2SMark Phalan 
858*159d09a2SMark Phalan     base = 0;
859*159d09a2SMark Phalan     for (p = preauth_types; *p != '\0';) {
860*159d09a2SMark Phalan 	/* skip whitespace to find an entry */
861*159d09a2SMark Phalan 	p += strspn(p, ", ");
862*159d09a2SMark Phalan 	if (*p != '\0') {
863*159d09a2SMark Phalan 	    /* see if we can extract a number */
864*159d09a2SMark Phalan 	    l = strtol(p, &q, 10);
865*159d09a2SMark Phalan 	    if ((q != NULL) && (q > p)) {
866*159d09a2SMark Phalan 		/* got a valid number; search for a matchin entry */
867*159d09a2SMark Phalan 		for (i = base; padata[i] != NULL; i++) {
868*159d09a2SMark Phalan 		    /* bubble the matching entry to the front of the list */
869*159d09a2SMark Phalan 		    if (padata[i]->pa_type == l) {
870*159d09a2SMark Phalan 			tmp = padata[i];
871*159d09a2SMark Phalan 			for (j = i; j > base; j--)
872*159d09a2SMark Phalan 			    padata[j] = padata[j - 1];
873*159d09a2SMark Phalan 			padata[base] = tmp;
874*159d09a2SMark Phalan 			base++;
875*159d09a2SMark Phalan 			break;
876*159d09a2SMark Phalan 		    }
877*159d09a2SMark Phalan 		}
878*159d09a2SMark Phalan 		p = q;
879*159d09a2SMark Phalan 	    } else {
880*159d09a2SMark Phalan 		break;
881*159d09a2SMark Phalan 	    }
882*159d09a2SMark Phalan 	}
883*159d09a2SMark Phalan     }
884*159d09a2SMark Phalan     if (need_free_string)
885*159d09a2SMark Phalan 	free(preauth_types);
886*159d09a2SMark Phalan 
887*159d09a2SMark Phalan #ifdef DEBUG
888*159d09a2SMark Phalan     fprintf (stderr, "preauth data types after sorting:");
889*159d09a2SMark Phalan     for (i = 0; padata[i]; i++)
890*159d09a2SMark Phalan 	fprintf (stderr, " %d", padata[i]->pa_type);
891*159d09a2SMark Phalan     fprintf (stderr, "\n");
892*159d09a2SMark Phalan #endif
893*159d09a2SMark Phalan 
894*159d09a2SMark Phalan     return 0;
895*159d09a2SMark Phalan }
896*159d09a2SMark Phalan 
897505d05c7Sgtb krb5_error_code KRB5_CALLCONV
898505d05c7Sgtb krb5_get_init_creds(krb5_context context,
899505d05c7Sgtb 		    krb5_creds *creds,
900505d05c7Sgtb 		    krb5_principal client,
901505d05c7Sgtb 		    krb5_prompter_fct prompter,
902505d05c7Sgtb 		    void *prompter_data,
903505d05c7Sgtb 		    krb5_deltat start_time,
904505d05c7Sgtb 		    char *in_tkt_service,
905*159d09a2SMark Phalan 		    krb5_gic_opt_ext *options,
906505d05c7Sgtb 		    krb5_gic_get_as_key_fct gak_fct,
907505d05c7Sgtb 		    void *gak_data,
908505d05c7Sgtb 		    int  *use_master,
909505d05c7Sgtb 		    krb5_kdc_rep **as_reply)
9107c478bd9Sstevel@tonic-gate {
9117c478bd9Sstevel@tonic-gate     krb5_error_code ret;
9127c478bd9Sstevel@tonic-gate     krb5_kdc_req request;
913*159d09a2SMark Phalan     krb5_data *encoded_request_body, *encoded_previous_request;
914*159d09a2SMark Phalan     krb5_pa_data **preauth_to_use, **kdc_padata;
9157c478bd9Sstevel@tonic-gate     int tempint;
916505d05c7Sgtb     char *tempstr = NULL;
917505d05c7Sgtb     krb5_deltat tkt_life;
9187c478bd9Sstevel@tonic-gate     krb5_deltat renew_life;
9197c478bd9Sstevel@tonic-gate     int loopcount;
9207c478bd9Sstevel@tonic-gate     krb5_data salt;
9217c478bd9Sstevel@tonic-gate     krb5_data s2kparams;
9227c478bd9Sstevel@tonic-gate     krb5_keyblock as_key;
9237c478bd9Sstevel@tonic-gate     krb5_error *err_reply;
9247c478bd9Sstevel@tonic-gate     krb5_kdc_rep *local_as_reply;
9257c478bd9Sstevel@tonic-gate     krb5_timestamp time_now;
9267c478bd9Sstevel@tonic-gate     krb5_enctype etype = 0;
927*159d09a2SMark Phalan     krb5_preauth_client_rock get_data_rock;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate     /* initialize everything which will be freed at cleanup */
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate     s2kparams.data = NULL;
9327c478bd9Sstevel@tonic-gate     s2kparams.length = 0;
9337c478bd9Sstevel@tonic-gate     request.server = NULL;
9347c478bd9Sstevel@tonic-gate     request.ktype = NULL;
9357c478bd9Sstevel@tonic-gate     request.addresses = NULL;
9367c478bd9Sstevel@tonic-gate     request.padata = NULL;
937*159d09a2SMark Phalan     encoded_request_body = NULL;
938*159d09a2SMark Phalan     encoded_previous_request = NULL;
939*159d09a2SMark Phalan     preauth_to_use = NULL;
940*159d09a2SMark Phalan     kdc_padata = NULL;
941*159d09a2SMark Phalan     as_key.length = 0;
9427c478bd9Sstevel@tonic-gate     salt.length = 0;
9437c478bd9Sstevel@tonic-gate     salt.data = NULL;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate     (void) memset(&as_key, 0, sizeof(as_key));
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	local_as_reply = 0;
9487c478bd9Sstevel@tonic-gate 
949*159d09a2SMark Phalan     err_reply = NULL;
950*159d09a2SMark Phalan 
9517c478bd9Sstevel@tonic-gate     /*
9527c478bd9Sstevel@tonic-gate      * Set up the basic request structure
9537c478bd9Sstevel@tonic-gate      */
9547c478bd9Sstevel@tonic-gate     request.magic = KV5M_KDC_REQ;
9557c478bd9Sstevel@tonic-gate     request.msg_type = KRB5_AS_REQ;
9567c478bd9Sstevel@tonic-gate 
957*159d09a2SMark Phalan     /* request.nonce is filled in when we send a request to the kdc */
958*159d09a2SMark Phalan     request.nonce = 0;
959*159d09a2SMark Phalan 
9607c478bd9Sstevel@tonic-gate     /* request.padata is filled in later */
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate     request.kdc_options = context->kdc_default_options;
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate     /* forwardable */
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE))
9677c478bd9Sstevel@tonic-gate 	tempint = options->forwardable;
9687c478bd9Sstevel@tonic-gate     else if ((ret = krb5_libdefault_boolean(context, &client->realm,
9697c478bd9Sstevel@tonic-gate 					    "forwardable", &tempint)) == 0)
9707c478bd9Sstevel@tonic-gate 	/*EMPTY*/
9717c478bd9Sstevel@tonic-gate 	;
9727c478bd9Sstevel@tonic-gate     else
9737c478bd9Sstevel@tonic-gate 	tempint = 0;
9747c478bd9Sstevel@tonic-gate     if (tempint)
9757c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_FORWARDABLE;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate     /* proxiable */
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE))
9807c478bd9Sstevel@tonic-gate 	tempint = options->proxiable;
9817c478bd9Sstevel@tonic-gate     else if ((ret = krb5_libdefault_boolean(context, &client->realm,
9827c478bd9Sstevel@tonic-gate 					    "proxiable", &tempint)) == 0)
9837c478bd9Sstevel@tonic-gate 	/*EMPTY*/
9847c478bd9Sstevel@tonic-gate 	;
9857c478bd9Sstevel@tonic-gate     else
9867c478bd9Sstevel@tonic-gate 	tempint = 0;
9877c478bd9Sstevel@tonic-gate     if (tempint)
9887c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_PROXIABLE;
9897c478bd9Sstevel@tonic-gate 
990505d05c7Sgtb     /* allow_postdate */
991505d05c7Sgtb 
992505d05c7Sgtb     if (start_time > 0)
993505d05c7Sgtb 	request.kdc_options |= (KDC_OPT_ALLOW_POSTDATE|KDC_OPT_POSTDATED);
994505d05c7Sgtb 
995505d05c7Sgtb     /* ticket lifetime */
996505d05c7Sgtb 
997505d05c7Sgtb     if ((ret = krb5_timeofday(context, &request.from)))
998505d05c7Sgtb 	goto cleanup;
999505d05c7Sgtb     request.from = krb5int_addint32(request.from, start_time);
1000505d05c7Sgtb 
1001505d05c7Sgtb     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)) {
1002505d05c7Sgtb         tkt_life = options->tkt_life;
1003505d05c7Sgtb     } else if ((ret = krb5_libdefault_string(context, &client->realm,
1004505d05c7Sgtb 					     "ticket_lifetime", &tempstr))
1005505d05c7Sgtb 	       == 0) {
1006*159d09a2SMark Phalan 	ret = krb5_string_to_deltat(tempstr, &tkt_life);
1007505d05c7Sgtb 	free(tempstr);
1008*159d09a2SMark Phalan 	if (ret) {
1009505d05c7Sgtb 	    goto cleanup;
1010505d05c7Sgtb 	}
1011505d05c7Sgtb     } else {
1012505d05c7Sgtb 	/* this used to be hardcoded in kinit.c */
1013505d05c7Sgtb 	tkt_life = 24*60*60;
1014505d05c7Sgtb     }
1015505d05c7Sgtb     request.till = krb5int_addint32(request.from, tkt_life);
1016505d05c7Sgtb 
1017505d05c7Sgtb     /* renewable lifetime */
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) {
10207c478bd9Sstevel@tonic-gate 	renew_life = options->renew_life;
10217c478bd9Sstevel@tonic-gate     } else if ((ret = krb5_libdefault_string(context, &client->realm,
10227c478bd9Sstevel@tonic-gate 					     "renew_lifetime", &tempstr))
10237c478bd9Sstevel@tonic-gate 	       == 0) {
1024*159d09a2SMark Phalan 	ret = krb5_string_to_deltat(tempstr, &renew_life);
10257c478bd9Sstevel@tonic-gate 	free(tempstr);
1026*159d09a2SMark Phalan 	if (ret) {
10277c478bd9Sstevel@tonic-gate 	    goto cleanup;
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate     } else {
10307c478bd9Sstevel@tonic-gate 	renew_life = 0;
10317c478bd9Sstevel@tonic-gate     }
10327c478bd9Sstevel@tonic-gate     if (renew_life > 0)
10337c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_RENEWABLE;
10347c478bd9Sstevel@tonic-gate 
1035505d05c7Sgtb     if (renew_life > 0) {
1036505d05c7Sgtb 	request.rtime = krb5int_addint32(request.from, renew_life);
1037505d05c7Sgtb         if (request.rtime < request.till) {
1038505d05c7Sgtb             /* don't ask for a smaller renewable time than the lifetime */
1039505d05c7Sgtb             request.rtime = request.till;
1040505d05c7Sgtb         }
1041505d05c7Sgtb         /* we are already asking for renewable tickets so strip this option */
1042505d05c7Sgtb 	request.kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
1043505d05c7Sgtb     } else {
1044505d05c7Sgtb 	request.rtime = 0;
1045505d05c7Sgtb     }
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate     /* client */
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate     request.client = client;
10507c478bd9Sstevel@tonic-gate 
1051505d05c7Sgtb     /* service */
1052505d05c7Sgtb 
10537c478bd9Sstevel@tonic-gate     if (in_tkt_service) {
10547c478bd9Sstevel@tonic-gate 	/* this is ugly, because so are the data structures involved.  I'm
10557c478bd9Sstevel@tonic-gate 	   in the library, so I'm going to manipulate the data structures
10567c478bd9Sstevel@tonic-gate 	   directly, otherwise, it will be worse. */
10577c478bd9Sstevel@tonic-gate 
1058505d05c7Sgtb         if ((ret = krb5_parse_name(context, in_tkt_service, &request.server)))
10597c478bd9Sstevel@tonic-gate 	    goto cleanup;
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	/* stuff the client realm into the server principal.
10627c478bd9Sstevel@tonic-gate 	   realloc if necessary */
10637c478bd9Sstevel@tonic-gate 	if (request.server->realm.length < request.client->realm.length)
10647c478bd9Sstevel@tonic-gate 	    if ((request.server->realm.data =
10657c478bd9Sstevel@tonic-gate 		 (char *) realloc(request.server->realm.data,
10667c478bd9Sstevel@tonic-gate 				  request.client->realm.length)) == NULL) {
10677c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
10687c478bd9Sstevel@tonic-gate 		goto cleanup;
10697c478bd9Sstevel@tonic-gate 	    }
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	request.server->realm.length = request.client->realm.length;
10727c478bd9Sstevel@tonic-gate 	memcpy(request.server->realm.data, request.client->realm.data,
10737c478bd9Sstevel@tonic-gate 	       request.client->realm.length);
10747c478bd9Sstevel@tonic-gate     } else {
1075505d05c7Sgtb 	if ((ret = krb5_build_principal_ext(context, &request.server,
10767c478bd9Sstevel@tonic-gate 					   request.client->realm.length,
10777c478bd9Sstevel@tonic-gate 					   request.client->realm.data,
10787c478bd9Sstevel@tonic-gate 					   KRB5_TGS_NAME_SIZE,
10797c478bd9Sstevel@tonic-gate 					   KRB5_TGS_NAME,
10807c478bd9Sstevel@tonic-gate 					   request.client->realm.length,
10817c478bd9Sstevel@tonic-gate 					   request.client->realm.data,
1082505d05c7Sgtb 					   0)))
10837c478bd9Sstevel@tonic-gate 	    goto cleanup;
10847c478bd9Sstevel@tonic-gate     }
10857c478bd9Sstevel@tonic-gate 
1086*159d09a2SMark Phalan     krb5_preauth_request_context_init(context);
1087*159d09a2SMark Phalan 
1088*159d09a2SMark Phalan     /* nonce is filled in by send_as_request if we don't take care of it */
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)) {
10917c478bd9Sstevel@tonic-gate 	request.ktype = options->etype_list;
10927c478bd9Sstevel@tonic-gate 	request.nktypes = options->etype_list_length;
10937c478bd9Sstevel@tonic-gate     } else if ((ret = krb5_get_default_in_tkt_ktypes(context,
10947c478bd9Sstevel@tonic-gate 						     &request.ktype)) == 0) {
10957c478bd9Sstevel@tonic-gate 	for (request.nktypes = 0;
10967c478bd9Sstevel@tonic-gate 	     request.ktype[request.nktypes];
10977c478bd9Sstevel@tonic-gate 	     request.nktypes++)
10987c478bd9Sstevel@tonic-gate 	    ;
10997c478bd9Sstevel@tonic-gate     } else {
11007c478bd9Sstevel@tonic-gate 	/* there isn't any useful default here.  ret is set from above */
11017c478bd9Sstevel@tonic-gate 	goto cleanup;
11027c478bd9Sstevel@tonic-gate     }
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)) {
11057c478bd9Sstevel@tonic-gate 	request.addresses = options->address_list;
11067c478bd9Sstevel@tonic-gate     }
11077c478bd9Sstevel@tonic-gate     /* it would be nice if this parsed out an address list, but
11087c478bd9Sstevel@tonic-gate        that would be work. */
11097c478bd9Sstevel@tonic-gate     else if (((ret = krb5_libdefault_boolean(context, &client->realm,
11107c478bd9Sstevel@tonic-gate 					    "no_addresses", &tempint)) == 0)
1111505d05c7Sgtb 	     || (tempint == 1)) {
11127c478bd9Sstevel@tonic-gate 	    /*EMPTY*/
11137c478bd9Sstevel@tonic-gate 	    ;
11147c478bd9Sstevel@tonic-gate     } else if (((ret = krb5_libdefault_boolean(context, &client->realm,
11157c478bd9Sstevel@tonic-gate 					    "noaddresses", &tempint)) == 0)
1116505d05c7Sgtb 	     || (tempint == 1)) {
11177c478bd9Sstevel@tonic-gate 	    /*EMPTY*/
11187c478bd9Sstevel@tonic-gate 	    ;
11197c478bd9Sstevel@tonic-gate     } else {
11207c478bd9Sstevel@tonic-gate 	if ((ret = krb5_os_localaddr(context, &request.addresses)))
11217c478bd9Sstevel@tonic-gate 	    goto cleanup;
11227c478bd9Sstevel@tonic-gate     }
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate     request.authorization_data.ciphertext.length = 0;
11257c478bd9Sstevel@tonic-gate     request.authorization_data.ciphertext.data = 0;
11267c478bd9Sstevel@tonic-gate     request.unenc_authdata = 0;
11277c478bd9Sstevel@tonic-gate     request.second_ticket = 0;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate     /* set up the other state.  */
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
1132505d05c7Sgtb 	if ((ret = make_preauth_list(context, options->preauth_list,
11337c478bd9Sstevel@tonic-gate 				     options->preauth_list_length,
1134*159d09a2SMark Phalan 				     &preauth_to_use)))
11357c478bd9Sstevel@tonic-gate 	    goto cleanup;
11367c478bd9Sstevel@tonic-gate     }
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate     /* the salt is allocated from somewhere, unless it is from the caller,
11397c478bd9Sstevel@tonic-gate        then it is a reference */
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)) {
11427c478bd9Sstevel@tonic-gate 	salt = *options->salt;
11437c478bd9Sstevel@tonic-gate     } else {
1144*159d09a2SMark Phalan 	salt.length = SALT_TYPE_AFS_LENGTH;
11457c478bd9Sstevel@tonic-gate 	salt.data = NULL;
11467c478bd9Sstevel@tonic-gate     }
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 
1149*159d09a2SMark Phalan     /* set the request nonce */
1150*159d09a2SMark Phalan     if ((ret = krb5_timeofday(context, &time_now)))
1151*159d09a2SMark Phalan 	goto cleanup;
1152*159d09a2SMark Phalan     /*
1153*159d09a2SMark Phalan      * XXX we know they are the same size... and we should do
1154*159d09a2SMark Phalan      * something better than just the current time
1155*159d09a2SMark Phalan      */
1156*159d09a2SMark Phalan     request.nonce = (krb5_int32) time_now;
1157*159d09a2SMark Phalan 
1158*159d09a2SMark Phalan     /* give the preauth plugins a chance to prep the request body */
1159*159d09a2SMark Phalan     krb5_preauth_prepare_request(context, options, &request);
1160*159d09a2SMark Phalan     ret = encode_krb5_kdc_req_body(&request, &encoded_request_body);
1161*159d09a2SMark Phalan     if (ret)
1162*159d09a2SMark Phalan         goto cleanup;
1163*159d09a2SMark Phalan 
1164*159d09a2SMark Phalan     get_data_rock.magic = CLIENT_ROCK_MAGIC;
1165*159d09a2SMark Phalan     get_data_rock.as_reply = NULL;
1166*159d09a2SMark Phalan 
1167*159d09a2SMark Phalan     /* now, loop processing preauth data and talking to the kdc */
11687c478bd9Sstevel@tonic-gate     for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) {
11697c478bd9Sstevel@tonic-gate 	if (request.padata) {
11707c478bd9Sstevel@tonic-gate 	    krb5_free_pa_data(context, request.padata);
11717c478bd9Sstevel@tonic-gate 	    request.padata = NULL;
11727c478bd9Sstevel@tonic-gate 	}
1173*159d09a2SMark Phalan 	if (!err_reply) {
1174*159d09a2SMark Phalan             /* either our first attempt, or retrying after PREAUTH_NEEDED */
1175*159d09a2SMark Phalan 	    if ((ret = krb5_do_preauth(context,
1176*159d09a2SMark Phalan 				       &request,
1177*159d09a2SMark Phalan 				       encoded_request_body,
1178*159d09a2SMark Phalan 				       encoded_previous_request,
1179*159d09a2SMark Phalan 				       preauth_to_use, &request.padata,
1180*159d09a2SMark Phalan 				       &salt, &s2kparams, &etype, &as_key,
1181*159d09a2SMark Phalan 				       prompter, prompter_data,
1182*159d09a2SMark Phalan 				       gak_fct, gak_data,
1183*159d09a2SMark Phalan 				       &get_data_rock, options)))
11847c478bd9Sstevel@tonic-gate 	        goto cleanup;
1185*159d09a2SMark Phalan 	} else {
1186*159d09a2SMark Phalan 	    if (preauth_to_use != NULL) {
1187*159d09a2SMark Phalan 		/*
1188*159d09a2SMark Phalan 		 * Retry after an error other than PREAUTH_NEEDED,
1189*159d09a2SMark Phalan 		 * using e-data to figure out what to change.
1190*159d09a2SMark Phalan 		 */
1191*159d09a2SMark Phalan 		ret = krb5_do_preauth_tryagain(context,
1192*159d09a2SMark Phalan 					       &request,
1193*159d09a2SMark Phalan 					       encoded_request_body,
1194*159d09a2SMark Phalan 					       encoded_previous_request,
1195*159d09a2SMark Phalan 					       preauth_to_use, &request.padata,
1196*159d09a2SMark Phalan 					       err_reply,
1197*159d09a2SMark Phalan 					       &salt, &s2kparams, &etype,
1198*159d09a2SMark Phalan 					       &as_key,
1199*159d09a2SMark Phalan 					       prompter, prompter_data,
1200*159d09a2SMark Phalan 					       gak_fct, gak_data,
1201*159d09a2SMark Phalan 					       &get_data_rock, options);
1202*159d09a2SMark Phalan 	    } else {
1203*159d09a2SMark Phalan 		/* No preauth supplied, so can't query the plug-ins. */
1204*159d09a2SMark Phalan 		ret = KRB5KRB_ERR_GENERIC;
12057c478bd9Sstevel@tonic-gate 	    }
1206*159d09a2SMark Phalan 	    if (ret) {
1207*159d09a2SMark Phalan 		/* couldn't come up with anything better */
1208*159d09a2SMark Phalan 		ret = err_reply->error + ERROR_TABLE_BASE_krb5;
1209*159d09a2SMark Phalan 	    }
1210*159d09a2SMark Phalan 	    krb5_free_error(context, err_reply);
1211*159d09a2SMark Phalan 	    err_reply = NULL;
1212*159d09a2SMark Phalan 	    if (ret)
1213*159d09a2SMark Phalan 		goto cleanup;
1214*159d09a2SMark Phalan 	}
1215*159d09a2SMark Phalan 
1216*159d09a2SMark Phalan         if (encoded_previous_request != NULL) {
1217*159d09a2SMark Phalan 	    krb5_free_data(context, encoded_previous_request);
1218*159d09a2SMark Phalan 	    encoded_previous_request = NULL;
1219*159d09a2SMark Phalan         }
1220*159d09a2SMark Phalan         ret = encode_krb5_as_req(&request, &encoded_previous_request);
1221*159d09a2SMark Phalan 	if (ret)
1222*159d09a2SMark Phalan 	    goto cleanup;
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	err_reply = 0;
12257c478bd9Sstevel@tonic-gate 	local_as_reply = 0;
1226*159d09a2SMark Phalan 	if ((ret = send_as_request(context, &request, &err_reply,
12277c478bd9Sstevel@tonic-gate 				   &local_as_reply, use_master)))
12287c478bd9Sstevel@tonic-gate 	    goto cleanup;
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	if (err_reply) {
12317c478bd9Sstevel@tonic-gate 	    if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
12327c478bd9Sstevel@tonic-gate 		err_reply->e_data.length > 0) {
1233*159d09a2SMark Phalan 		/* reset the list of preauth types to try */
1234*159d09a2SMark Phalan 		if (preauth_to_use) {
1235*159d09a2SMark Phalan 		    krb5_free_pa_data(context, preauth_to_use);
1236*159d09a2SMark Phalan 		    preauth_to_use = NULL;
1237*159d09a2SMark Phalan 		}
12387c478bd9Sstevel@tonic-gate 		ret = decode_krb5_padata_sequence(&err_reply->e_data,
1239*159d09a2SMark Phalan 						  &preauth_to_use);
12407c478bd9Sstevel@tonic-gate 		krb5_free_error(context, err_reply);
1241*159d09a2SMark Phalan 		err_reply = NULL;
12427c478bd9Sstevel@tonic-gate 		if (ret)
12437c478bd9Sstevel@tonic-gate 		    goto cleanup;
1244*159d09a2SMark Phalan 		ret = sort_krb5_padata_sequence(context,
1245*159d09a2SMark Phalan 						&request.server->realm,
1246*159d09a2SMark Phalan 						preauth_to_use);
1247*159d09a2SMark Phalan 		if (ret)
1248*159d09a2SMark Phalan 		    goto cleanup;
1249*159d09a2SMark Phalan 		/* continue to next iteration */
12507c478bd9Sstevel@tonic-gate 	    } else {
1251*159d09a2SMark Phalan 		if (err_reply->e_data.length > 0) {
1252*159d09a2SMark Phalan 		    /* continue to next iteration */
1253*159d09a2SMark Phalan 		} else {
1254*159d09a2SMark Phalan 		    /* error + no hints = give up */
1255505d05c7Sgtb 		    ret = (krb5_error_code) err_reply->error
1256505d05c7Sgtb 		          + ERROR_TABLE_BASE_krb5;
12577c478bd9Sstevel@tonic-gate 		    krb5_free_error(context, err_reply);
12587c478bd9Sstevel@tonic-gate 		    goto cleanup;
12597c478bd9Sstevel@tonic-gate 		}
1260*159d09a2SMark Phalan 	    }
12617c478bd9Sstevel@tonic-gate 	} else if (local_as_reply) {
12627c478bd9Sstevel@tonic-gate 	    break;
12637c478bd9Sstevel@tonic-gate 	} else {
12647c478bd9Sstevel@tonic-gate 	    ret = KRB5KRB_AP_ERR_MSG_TYPE;
12657c478bd9Sstevel@tonic-gate 	    goto cleanup;
12667c478bd9Sstevel@tonic-gate 	}
12677c478bd9Sstevel@tonic-gate     }
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate     if (loopcount == MAX_IN_TKT_LOOPS) {
12707c478bd9Sstevel@tonic-gate 	ret = KRB5_GET_IN_TKT_LOOP;
12717c478bd9Sstevel@tonic-gate 	goto cleanup;
12727c478bd9Sstevel@tonic-gate     }
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate     /* process any preauth data in the as_reply */
1275*159d09a2SMark Phalan     krb5_clear_preauth_context_use_counts(context);
1276*159d09a2SMark Phalan     if ((ret = sort_krb5_padata_sequence(context, &request.server->realm,
1277*159d09a2SMark Phalan 					 local_as_reply->padata)))
12787c478bd9Sstevel@tonic-gate 	goto cleanup;
1279*159d09a2SMark Phalan     get_data_rock.as_reply = local_as_reply;
1280*159d09a2SMark Phalan     if ((ret = krb5_do_preauth(context,
1281*159d09a2SMark Phalan 			       &request,
1282*159d09a2SMark Phalan 			       encoded_request_body, encoded_previous_request,
1283*159d09a2SMark Phalan 			       local_as_reply->padata, &kdc_padata,
1284*159d09a2SMark Phalan 			       &salt, &s2kparams, &etype, &as_key, prompter,
1285*159d09a2SMark Phalan 			       prompter_data, gak_fct, gak_data,
1286*159d09a2SMark Phalan 			       &get_data_rock, options)))
1287*159d09a2SMark Phalan 	goto cleanup;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate     /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
12907c478bd9Sstevel@tonic-gate        the AS_REP comes back encrypted in the user's longterm key
12917c478bd9Sstevel@tonic-gate        instead of in the SAD. If there was a SAM preauth, there
12927c478bd9Sstevel@tonic-gate        will be an as_key here which will be the SAD. If that fails,
12937c478bd9Sstevel@tonic-gate        use the gak_fct to get the password, and try again. */
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate     /* XXX because etypes are handled poorly (particularly wrt SAM,
12967c478bd9Sstevel@tonic-gate        where the etype is fixed by the kdc), we may want to try
12977c478bd9Sstevel@tonic-gate        decrypt_as_reply twice.  If there's an as_key available, try
12987c478bd9Sstevel@tonic-gate        it.  If decrypting the as_rep fails, or if there isn't an
12997c478bd9Sstevel@tonic-gate        as_key at all yet, then use the gak_fct to get one, and try
13007c478bd9Sstevel@tonic-gate        again.  */
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate     if (as_key.length)
1303*159d09a2SMark Phalan 	ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
1304*159d09a2SMark Phalan 			       NULL, &as_key, krb5_kdc_rep_decrypt_proc,
1305*159d09a2SMark Phalan 			       NULL);
13067c478bd9Sstevel@tonic-gate     else
13077c478bd9Sstevel@tonic-gate 	ret = -1;
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate     if (ret) {
13107c478bd9Sstevel@tonic-gate 	/* if we haven't get gotten a key, get it now */
13117c478bd9Sstevel@tonic-gate 
1312505d05c7Sgtb 	if ((ret = ((*gak_fct)(context, request.client,
13137c478bd9Sstevel@tonic-gate 			       local_as_reply->enc_part.enctype,
13147c478bd9Sstevel@tonic-gate 			       prompter, prompter_data, &salt, &s2kparams,
1315505d05c7Sgtb 			       &as_key, gak_data))))
13167c478bd9Sstevel@tonic-gate 	    goto cleanup;
13177c478bd9Sstevel@tonic-gate 
1318*159d09a2SMark Phalan 	if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
1319*159d09a2SMark Phalan 				    NULL, &as_key, krb5_kdc_rep_decrypt_proc,
1320*159d09a2SMark Phalan 				    NULL)))
13217c478bd9Sstevel@tonic-gate 	    goto cleanup;
13227c478bd9Sstevel@tonic-gate     }
13237c478bd9Sstevel@tonic-gate 
1324505d05c7Sgtb     if ((ret = verify_as_reply(context, time_now, &request, local_as_reply)))
13257c478bd9Sstevel@tonic-gate 	goto cleanup;
13267c478bd9Sstevel@tonic-gate 
1327*159d09a2SMark Phalan     /* XXX this should be inside stash_as_reply, but as long as
1328*159d09a2SMark Phalan        get_in_tkt is still around using that arg as an in/out, I can't
1329*159d09a2SMark Phalan        do that */
1330*159d09a2SMark Phalan 	/* Solaris Kerberos */
13317c478bd9Sstevel@tonic-gate 	(void) memset(creds, 0, sizeof(*creds));
13327c478bd9Sstevel@tonic-gate 
1333*159d09a2SMark Phalan     /* Solaris Kerberos */
1334505d05c7Sgtb     if ((ret = stash_as_reply(context, time_now, &request, local_as_reply,
1335505d05c7Sgtb 			      creds, (krb5_ccache)NULL)))
13367c478bd9Sstevel@tonic-gate 	goto cleanup;
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate     /* success */
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate     ret = 0;
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate cleanup:
1343*159d09a2SMark Phalan     krb5_preauth_request_context_fini(context);
1344*159d09a2SMark Phalan     if (encoded_previous_request != NULL) {
1345*159d09a2SMark Phalan 	krb5_free_data(context, encoded_previous_request);
1346*159d09a2SMark Phalan 	encoded_previous_request = NULL;
1347*159d09a2SMark Phalan     }
1348*159d09a2SMark Phalan     if (encoded_request_body != NULL) {
1349*159d09a2SMark Phalan 	krb5_free_data(context, encoded_request_body);
1350*159d09a2SMark Phalan 	encoded_request_body = NULL;
1351*159d09a2SMark Phalan     }
13527c478bd9Sstevel@tonic-gate     if (request.server)
13537c478bd9Sstevel@tonic-gate 	krb5_free_principal(context, request.server);
13547c478bd9Sstevel@tonic-gate     if (request.ktype &&
13557c478bd9Sstevel@tonic-gate 	(!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))))
13567c478bd9Sstevel@tonic-gate 	free(request.ktype);
13577c478bd9Sstevel@tonic-gate     if (request.addresses &&
13587c478bd9Sstevel@tonic-gate 	(!(options &&
13597c478bd9Sstevel@tonic-gate 	   (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST))))
13607c478bd9Sstevel@tonic-gate 	krb5_free_addresses(context, request.addresses);
1361*159d09a2SMark Phalan     if (preauth_to_use)
1362*159d09a2SMark Phalan 	krb5_free_pa_data(context, preauth_to_use);
1363*159d09a2SMark Phalan     if (kdc_padata)
1364*159d09a2SMark Phalan 	krb5_free_pa_data(context, kdc_padata);
13657c478bd9Sstevel@tonic-gate     if (request.padata)
13667c478bd9Sstevel@tonic-gate 	krb5_free_pa_data(context, request.padata);
13677c478bd9Sstevel@tonic-gate     if (as_key.length)
13687c478bd9Sstevel@tonic-gate 	krb5_free_keyblock_contents(context, &as_key);
13697c478bd9Sstevel@tonic-gate     if (salt.data &&
13707c478bd9Sstevel@tonic-gate 	(!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT))))
13717c478bd9Sstevel@tonic-gate 	krb5_xfree(salt.data);
1372505d05c7Sgtb     krb5_free_data_contents(context, &s2kparams);
13737c478bd9Sstevel@tonic-gate     if (as_reply)
13747c478bd9Sstevel@tonic-gate 	*as_reply = local_as_reply;
13757c478bd9Sstevel@tonic-gate     else if (local_as_reply)
13767c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, local_as_reply);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate     return(ret);
13797c478bd9Sstevel@tonic-gate }
1380