xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/get_in_tkt.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate /*
9*7c478bd9Sstevel@tonic-gate  * lib/krb5/krb/get_in_tkt.c
10*7c478bd9Sstevel@tonic-gate  *
11*7c478bd9Sstevel@tonic-gate  * Copyright 1990,1991, 2003 by the Massachusetts Institute of Technology.
12*7c478bd9Sstevel@tonic-gate  * All Rights Reserved.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
15*7c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
16*7c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
17*7c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
18*7c478bd9Sstevel@tonic-gate  *
19*7c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20*7c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
21*7c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
22*7c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
23*7c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
24*7c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
25*7c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
26*7c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
27*7c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
28*7c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
29*7c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
30*7c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
31*7c478bd9Sstevel@tonic-gate  * or implied warranty.
32*7c478bd9Sstevel@tonic-gate  *
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * krb5_get_in_tkt()
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <string.h>
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <k5-int.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate /*
42*7c478bd9Sstevel@tonic-gate  All-purpose initial ticket routine, usually called via
43*7c478bd9Sstevel@tonic-gate  krb5_get_in_tkt_with_password or krb5_get_in_tkt_with_skey.
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate  Attempts to get an initial ticket for creds->client to use server
46*7c478bd9Sstevel@tonic-gate  creds->server, (realm is taken from creds->client), with options
47*7c478bd9Sstevel@tonic-gate  options, and using creds->times.starttime, creds->times.endtime,
48*7c478bd9Sstevel@tonic-gate  creds->times.renew_till as from, till, and rtime.
49*7c478bd9Sstevel@tonic-gate  creds->times.renew_till is ignored unless the RENEWABLE option is requested.
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate  key_proc is called to fill in the key to be used for decryption.
52*7c478bd9Sstevel@tonic-gate  keyseed is passed on to key_proc.
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate  decrypt_proc is called to perform the decryption of the response (the
55*7c478bd9Sstevel@tonic-gate  encrypted part is in dec_rep->enc_part; the decrypted part should be
56*7c478bd9Sstevel@tonic-gate  allocated and filled into dec_rep->enc_part2
57*7c478bd9Sstevel@tonic-gate  arg is passed on to decrypt_proc.
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate  If addrs is non-NULL, it is used for the addresses requested.  If it is
60*7c478bd9Sstevel@tonic-gate  null, the system standard addresses are used.
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate  A succesful call will place the ticket in the credentials cache ccache
63*7c478bd9Sstevel@tonic-gate  and fill in creds with the ticket information used/returned..
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate  returns system errors, encryption errors
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate /* some typedef's for the function args to make things look a bit cleaner */
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate typedef krb5_error_code (*git_key_proc) PROTOTYPE((krb5_context,
73*7c478bd9Sstevel@tonic-gate 						   const krb5_enctype,
74*7c478bd9Sstevel@tonic-gate 						   krb5_data *,
75*7c478bd9Sstevel@tonic-gate 						   krb5_const_pointer,
76*7c478bd9Sstevel@tonic-gate 						   krb5_keyblock **));
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate typedef krb5_error_code (*git_decrypt_proc) PROTOTYPE((krb5_context,
79*7c478bd9Sstevel@tonic-gate 						       const krb5_keyblock *,
80*7c478bd9Sstevel@tonic-gate 						       krb5_const_pointer,
81*7c478bd9Sstevel@tonic-gate 						       krb5_kdc_rep * ));
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate static krb5_error_code make_preauth_list PROTOTYPE((krb5_context,
84*7c478bd9Sstevel@tonic-gate 						    krb5_preauthtype *,
85*7c478bd9Sstevel@tonic-gate 						    int, krb5_pa_data ***));
86*7c478bd9Sstevel@tonic-gate /*
87*7c478bd9Sstevel@tonic-gate  * This function sends a request to the KDC, and gets back a response;
88*7c478bd9Sstevel@tonic-gate  * the response is parsed into ret_err_reply or ret_as_reply if the
89*7c478bd9Sstevel@tonic-gate  * reponse is a KRB_ERROR or a KRB_AS_REP packet.  If it is some other
90*7c478bd9Sstevel@tonic-gate  * unexpected response, an error is returned.
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate static krb5_error_code
93*7c478bd9Sstevel@tonic-gate send_as_request(context, request, time_now, ret_err_reply, ret_as_reply,
94*7c478bd9Sstevel@tonic-gate 		use_master)
95*7c478bd9Sstevel@tonic-gate     krb5_context 		context;
96*7c478bd9Sstevel@tonic-gate     krb5_kdc_req		*request;
97*7c478bd9Sstevel@tonic-gate     krb5_timestamp 		*time_now;
98*7c478bd9Sstevel@tonic-gate     krb5_error ** 		ret_err_reply;
99*7c478bd9Sstevel@tonic-gate     krb5_kdc_rep ** 		ret_as_reply;
100*7c478bd9Sstevel@tonic-gate     int 			use_master;
101*7c478bd9Sstevel@tonic-gate {
102*7c478bd9Sstevel@tonic-gate     krb5_kdc_rep *as_reply = 0;
103*7c478bd9Sstevel@tonic-gate     krb5_error_code retval;
104*7c478bd9Sstevel@tonic-gate     krb5_data *packet = 0;
105*7c478bd9Sstevel@tonic-gate     krb5_data reply;
106*7c478bd9Sstevel@tonic-gate     char k4_version;		/* same type as *(krb5_data::data) */
107*7c478bd9Sstevel@tonic-gate     int tcp_only = 0;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate     reply.data = 0;
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate     if ((retval = krb5_timeofday(context, time_now)))
112*7c478bd9Sstevel@tonic-gate 	goto cleanup;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate     /*
115*7c478bd9Sstevel@tonic-gate      * XXX we know they are the same size... and we should do
116*7c478bd9Sstevel@tonic-gate      * something better than just the current time
117*7c478bd9Sstevel@tonic-gate      */
118*7c478bd9Sstevel@tonic-gate     request->nonce = (krb5_int32) *time_now;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate     /* encode & send to KDC */
121*7c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_as_req(request, &packet)) != 0)
122*7c478bd9Sstevel@tonic-gate 	goto cleanup;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate     k4_version = packet->data[0];
125*7c478bd9Sstevel@tonic-gate send_again:
126*7c478bd9Sstevel@tonic-gate     retval = krb5_sendto_kdc(context, packet,
127*7c478bd9Sstevel@tonic-gate 			     krb5_princ_realm(context, request->client),
128*7c478bd9Sstevel@tonic-gate 			     &reply, use_master, tcp_only);
129*7c478bd9Sstevel@tonic-gate     if (retval)
130*7c478bd9Sstevel@tonic-gate 	goto cleanup;
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate     /* now decode the reply...could be error or as_rep */
133*7c478bd9Sstevel@tonic-gate     if (krb5_is_krb_error(&reply)) {
134*7c478bd9Sstevel@tonic-gate 	krb5_error *err_reply;
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	if ((retval = decode_krb5_error(&reply, &err_reply)))
137*7c478bd9Sstevel@tonic-gate 	    /* some other error code--??? */
138*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	if (ret_err_reply) {
141*7c478bd9Sstevel@tonic-gate 	    if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG
142*7c478bd9Sstevel@tonic-gate 		&& tcp_only == 0) {
143*7c478bd9Sstevel@tonic-gate 		tcp_only = 1;
144*7c478bd9Sstevel@tonic-gate 		krb5_free_error(context, err_reply);
145*7c478bd9Sstevel@tonic-gate 		free(reply.data);
146*7c478bd9Sstevel@tonic-gate 		reply.data = 0;
147*7c478bd9Sstevel@tonic-gate 		goto send_again;
148*7c478bd9Sstevel@tonic-gate 	    }
149*7c478bd9Sstevel@tonic-gate 	    *ret_err_reply = err_reply;
150*7c478bd9Sstevel@tonic-gate 	} else
151*7c478bd9Sstevel@tonic-gate 	    krb5_free_error(context, err_reply);
152*7c478bd9Sstevel@tonic-gate 	goto cleanup;
153*7c478bd9Sstevel@tonic-gate     }
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate     /*
156*7c478bd9Sstevel@tonic-gate      * Check to make sure it isn't a V4 reply.
157*7c478bd9Sstevel@tonic-gate      */
158*7c478bd9Sstevel@tonic-gate     if (!krb5_is_as_rep(&reply)) {
159*7c478bd9Sstevel@tonic-gate /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
160*7c478bd9Sstevel@tonic-gate #define V4_KRB_PROT_VERSION	4
161*7c478bd9Sstevel@tonic-gate #define V4_AUTH_MSG_ERR_REPLY	(5<<1)
162*7c478bd9Sstevel@tonic-gate 	/* check here for V4 reply */
163*7c478bd9Sstevel@tonic-gate 	unsigned int t_switch;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	/* From v4 g_in_tkt.c: This used to be
166*7c478bd9Sstevel@tonic-gate 	   switch (pkt_msg_type(rpkt) & ~1) {
167*7c478bd9Sstevel@tonic-gate 	   but SCO 3.2v4 cc compiled that incorrectly.  */
168*7c478bd9Sstevel@tonic-gate 	t_switch = reply.data[1];
169*7c478bd9Sstevel@tonic-gate 	t_switch &= ~1;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	if (t_switch == V4_AUTH_MSG_ERR_REPLY
172*7c478bd9Sstevel@tonic-gate 	    && (reply.data[0] == V4_KRB_PROT_VERSION
173*7c478bd9Sstevel@tonic-gate 		|| reply.data[0] == k4_version)) {
174*7c478bd9Sstevel@tonic-gate 	    retval = KRB5KRB_AP_ERR_V4_REPLY;
175*7c478bd9Sstevel@tonic-gate 	} else {
176*7c478bd9Sstevel@tonic-gate 	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
177*7c478bd9Sstevel@tonic-gate 	}
178*7c478bd9Sstevel@tonic-gate 	goto cleanup;
179*7c478bd9Sstevel@tonic-gate     }
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate     /* It must be a KRB_AS_REP message, or an bad returned packet */
182*7c478bd9Sstevel@tonic-gate     if ((retval = decode_krb5_as_rep(&reply, &as_reply)))
183*7c478bd9Sstevel@tonic-gate 	/* some other error code ??? */
184*7c478bd9Sstevel@tonic-gate 	goto cleanup;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate     if (as_reply->msg_type != KRB5_AS_REP) {
187*7c478bd9Sstevel@tonic-gate 	retval = KRB5KRB_AP_ERR_MSG_TYPE;
188*7c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, as_reply);
189*7c478bd9Sstevel@tonic-gate 	goto cleanup;
190*7c478bd9Sstevel@tonic-gate     }
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate     if (ret_as_reply)
193*7c478bd9Sstevel@tonic-gate 	*ret_as_reply = as_reply;
194*7c478bd9Sstevel@tonic-gate     else
195*7c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, as_reply);
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate cleanup:
198*7c478bd9Sstevel@tonic-gate     if (packet)
199*7c478bd9Sstevel@tonic-gate 	krb5_free_data(context, packet);
200*7c478bd9Sstevel@tonic-gate     if (reply.data)
201*7c478bd9Sstevel@tonic-gate 	free(reply.data);
202*7c478bd9Sstevel@tonic-gate     return retval;
203*7c478bd9Sstevel@tonic-gate }
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate static krb5_error_code
206*7c478bd9Sstevel@tonic-gate decrypt_as_reply(context, request, as_reply, key_proc, keyseed, key,
207*7c478bd9Sstevel@tonic-gate 		 decrypt_proc, decryptarg)
208*7c478bd9Sstevel@tonic-gate     krb5_context 		context;
209*7c478bd9Sstevel@tonic-gate     krb5_kdc_req		*request;
210*7c478bd9Sstevel@tonic-gate     krb5_kdc_rep		*as_reply;
211*7c478bd9Sstevel@tonic-gate     git_key_proc 		key_proc;
212*7c478bd9Sstevel@tonic-gate     krb5_const_pointer 		keyseed;
213*7c478bd9Sstevel@tonic-gate     krb5_keyblock *		key;
214*7c478bd9Sstevel@tonic-gate     git_decrypt_proc 		decrypt_proc;
215*7c478bd9Sstevel@tonic-gate     krb5_const_pointer 		decryptarg;
216*7c478bd9Sstevel@tonic-gate {
217*7c478bd9Sstevel@tonic-gate     krb5_error_code		retval;
218*7c478bd9Sstevel@tonic-gate     krb5_keyblock *		decrypt_key = 0;
219*7c478bd9Sstevel@tonic-gate     krb5_data 			salt;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "decrypt_as_reply() start");
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate     if (as_reply->enc_part2)
224*7c478bd9Sstevel@tonic-gate 	return 0;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate     if (key)
227*7c478bd9Sstevel@tonic-gate 	    decrypt_key = key;
228*7c478bd9Sstevel@tonic-gate     else if (request != NULL) {
229*7c478bd9Sstevel@tonic-gate 	if ((retval = krb5_principal2salt(context, request->client, &salt)))
230*7c478bd9Sstevel@tonic-gate 	    return(retval);
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	retval = (*key_proc)(context, as_reply->enc_part.enctype,
233*7c478bd9Sstevel@tonic-gate 			     &salt, keyseed, &decrypt_key);
234*7c478bd9Sstevel@tonic-gate 	krb5_xfree(salt.data);
235*7c478bd9Sstevel@tonic-gate 	if (retval)
236*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
237*7c478bd9Sstevel@tonic-gate     } else {
238*7c478bd9Sstevel@tonic-gate 	KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, "
239*7c478bd9Sstevel@tonic-gate 		"error key == NULL and request == NULL");
240*7c478bd9Sstevel@tonic-gate 	return (EINVAL);
241*7c478bd9Sstevel@tonic-gate     }
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate     /* Solaris kerberos: Overwriting the decrypt_key->enctype because the
244*7c478bd9Sstevel@tonic-gate      * decrypt key's enctype may not be an exact match with the enctype that the
245*7c478bd9Sstevel@tonic-gate      * KDC used to encrypt this part of the AS reply.  This assumes the
246*7c478bd9Sstevel@tonic-gate      * as_reply->enc_part.enctype has been validated which is done by checking
247*7c478bd9Sstevel@tonic-gate      * to see if the enctype that the KDC sent back in the as_reply is one of
248*7c478bd9Sstevel@tonic-gate      * the enctypes originally requested.  Note, if request is NULL then the
249*7c478bd9Sstevel@tonic-gate      * as_reply->enc_part.enctype could not be validated.
250*7c478bd9Sstevel@tonic-gate      */
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate     if (request != NULL) {
253*7c478bd9Sstevel@tonic-gate         if (is_in_keytype(request->ktype, request->nktypes,
254*7c478bd9Sstevel@tonic-gate                 as_reply->enc_part.enctype)) {
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	    decrypt_key->enctype = as_reply->enc_part.enctype;
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	} else {
259*7c478bd9Sstevel@tonic-gate 	    KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, "
260*7c478bd9Sstevel@tonic-gate 		    "error is_in_keytype() returned false");
261*7c478bd9Sstevel@tonic-gate 	    retval = KRB5_BAD_ENCTYPE;
262*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate     }
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate     if ((retval = (*decrypt_proc)(context, decrypt_key, decryptarg, as_reply))){
267*7c478bd9Sstevel@tonic-gate 	KRB5_LOG(KRB5_ERR, "decrypt_as_reply() error (*decrypt_proc)() retval "
268*7c478bd9Sstevel@tonic-gate 			    "= %d", retval);
269*7c478bd9Sstevel@tonic-gate 	goto cleanup;
270*7c478bd9Sstevel@tonic-gate     }
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate cleanup:
273*7c478bd9Sstevel@tonic-gate     if (!key && decrypt_key)
274*7c478bd9Sstevel@tonic-gate 	krb5_free_keyblock(context, decrypt_key);
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate     KRB5_LOG(KRB5_INFO, "decrypt_as_reply() end, retval = %d", retval);
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate     return (retval);
279*7c478bd9Sstevel@tonic-gate }
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate static krb5_error_code
282*7c478bd9Sstevel@tonic-gate verify_as_reply(context, time_now, request, as_reply)
283*7c478bd9Sstevel@tonic-gate     krb5_context 		context;
284*7c478bd9Sstevel@tonic-gate     krb5_timestamp 		time_now;
285*7c478bd9Sstevel@tonic-gate     krb5_kdc_req		*request;
286*7c478bd9Sstevel@tonic-gate     krb5_kdc_rep		*as_reply;
287*7c478bd9Sstevel@tonic-gate {
288*7c478bd9Sstevel@tonic-gate     krb5_error_code		retval;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate     /* check the contents for sanity: */
291*7c478bd9Sstevel@tonic-gate     if (!as_reply->enc_part2->times.starttime)
292*7c478bd9Sstevel@tonic-gate 	as_reply->enc_part2->times.starttime =
293*7c478bd9Sstevel@tonic-gate 	    as_reply->enc_part2->times.authtime;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate     if (!krb5_principal_compare(context, as_reply->client, request->client)
296*7c478bd9Sstevel@tonic-gate 	|| !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)
297*7c478bd9Sstevel@tonic-gate 	|| !krb5_principal_compare(context, as_reply->ticket->server, request->server)
298*7c478bd9Sstevel@tonic-gate 	|| (request->nonce != as_reply->enc_part2->nonce)
299*7c478bd9Sstevel@tonic-gate 	/* XXX check for extraneous flags */
300*7c478bd9Sstevel@tonic-gate 	/* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
301*7c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_POSTDATED) &&
302*7c478bd9Sstevel@tonic-gate 	    (request->from != 0) &&
303*7c478bd9Sstevel@tonic-gate 	    (request->from != as_reply->enc_part2->times.starttime))
304*7c478bd9Sstevel@tonic-gate 	|| ((request->till != 0) &&
305*7c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.endtime > request->till))
306*7c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_RENEWABLE) &&
307*7c478bd9Sstevel@tonic-gate 	    (request->rtime != 0) &&
308*7c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.renew_till > request->rtime))
309*7c478bd9Sstevel@tonic-gate 	|| ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
310*7c478bd9Sstevel@tonic-gate 	    !(request->kdc_options & KDC_OPT_RENEWABLE) &&
311*7c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
312*7c478bd9Sstevel@tonic-gate 	    (request->till != 0) &&
313*7c478bd9Sstevel@tonic-gate 	    (as_reply->enc_part2->times.renew_till > request->till))
314*7c478bd9Sstevel@tonic-gate 	)
315*7c478bd9Sstevel@tonic-gate 	return KRB5_KDCREP_MODIFIED;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate     if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
318*7c478bd9Sstevel@tonic-gate 	retval = krb5_set_real_time(context,
319*7c478bd9Sstevel@tonic-gate 				    as_reply->enc_part2->times.authtime, 0);
320*7c478bd9Sstevel@tonic-gate 	if (retval)
321*7c478bd9Sstevel@tonic-gate 	    return retval;
322*7c478bd9Sstevel@tonic-gate     } else {
323*7c478bd9Sstevel@tonic-gate 	if ((request->from == 0) &&
324*7c478bd9Sstevel@tonic-gate 	    (labs(as_reply->enc_part2->times.starttime - time_now)
325*7c478bd9Sstevel@tonic-gate 	     > context->clockskew))
326*7c478bd9Sstevel@tonic-gate 	    return (KRB5_KDCREP_SKEW);
327*7c478bd9Sstevel@tonic-gate     }
328*7c478bd9Sstevel@tonic-gate     return 0;
329*7c478bd9Sstevel@tonic-gate }
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
332*7c478bd9Sstevel@tonic-gate static krb5_error_code
333*7c478bd9Sstevel@tonic-gate stash_as_reply(context, time_now, request, as_reply, creds, ccache)
334*7c478bd9Sstevel@tonic-gate     krb5_context 		context;
335*7c478bd9Sstevel@tonic-gate     krb5_timestamp 		time_now;
336*7c478bd9Sstevel@tonic-gate     krb5_kdc_req		*request;
337*7c478bd9Sstevel@tonic-gate     krb5_kdc_rep		*as_reply;
338*7c478bd9Sstevel@tonic-gate     krb5_creds * 		creds;
339*7c478bd9Sstevel@tonic-gate     krb5_ccache 		ccache;
340*7c478bd9Sstevel@tonic-gate {
341*7c478bd9Sstevel@tonic-gate     krb5_error_code 		retval;
342*7c478bd9Sstevel@tonic-gate     krb5_data *			packet;
343*7c478bd9Sstevel@tonic-gate     krb5_principal		client;
344*7c478bd9Sstevel@tonic-gate     krb5_principal		server;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate     client = NULL;
347*7c478bd9Sstevel@tonic-gate     server = NULL;
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate     if (!creds->client)
350*7c478bd9Sstevel@tonic-gate         if (retval = krb5_copy_principal(context, as_reply->client, &client))
351*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate     if (!creds->server)
354*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_copy_principal(context, as_reply->enc_part2->server,
355*7c478bd9Sstevel@tonic-gate 					  &server))
356*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate     /* fill in the credentials */
359*7c478bd9Sstevel@tonic-gate     if ((retval = krb5_copy_keyblock_contents(context,
360*7c478bd9Sstevel@tonic-gate 					      as_reply->enc_part2->session,
361*7c478bd9Sstevel@tonic-gate 					      &creds->keyblock)))
362*7c478bd9Sstevel@tonic-gate 	goto cleanup;
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate     creds->times = as_reply->enc_part2->times;
365*7c478bd9Sstevel@tonic-gate     creds->is_skey = FALSE;		/* this is an AS_REQ, so cannot
366*7c478bd9Sstevel@tonic-gate 					   be encrypted in skey */
367*7c478bd9Sstevel@tonic-gate     creds->ticket_flags = as_reply->enc_part2->flags;
368*7c478bd9Sstevel@tonic-gate     if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs,
369*7c478bd9Sstevel@tonic-gate 				      &creds->addresses)))
370*7c478bd9Sstevel@tonic-gate 	goto cleanup;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate     creds->second_ticket.length = 0;
373*7c478bd9Sstevel@tonic-gate     creds->second_ticket.data = 0;
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_ticket(as_reply->ticket, &packet)))
376*7c478bd9Sstevel@tonic-gate 	goto cleanup;
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate     creds->ticket = *packet;
379*7c478bd9Sstevel@tonic-gate     krb5_xfree(packet);
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate     /* store it in the ccache! */
382*7c478bd9Sstevel@tonic-gate     if (ccache)
383*7c478bd9Sstevel@tonic-gate 	if ((retval = krb5_cc_store_cred(context, ccache, creds)) !=0)
384*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate     if (!creds->client)
387*7c478bd9Sstevel@tonic-gate 	creds->client = client;
388*7c478bd9Sstevel@tonic-gate     if (!creds->server)
389*7c478bd9Sstevel@tonic-gate 	creds->server = server;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate cleanup:
392*7c478bd9Sstevel@tonic-gate     if (retval) {
393*7c478bd9Sstevel@tonic-gate 	if (client)
394*7c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, client);
395*7c478bd9Sstevel@tonic-gate 	if (server)
396*7c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, server);
397*7c478bd9Sstevel@tonic-gate 	if (creds->keyblock.contents) {
398*7c478bd9Sstevel@tonic-gate 	    memset((char *)creds->keyblock.contents, 0,
399*7c478bd9Sstevel@tonic-gate 		   creds->keyblock.length);
400*7c478bd9Sstevel@tonic-gate 	    krb5_xfree(creds->keyblock.contents);
401*7c478bd9Sstevel@tonic-gate 	    creds->keyblock.contents = 0;
402*7c478bd9Sstevel@tonic-gate 	    creds->keyblock.length = 0;
403*7c478bd9Sstevel@tonic-gate 	}
404*7c478bd9Sstevel@tonic-gate 	if (creds->ticket.data) {
405*7c478bd9Sstevel@tonic-gate 	    krb5_xfree(creds->ticket.data);
406*7c478bd9Sstevel@tonic-gate 	    creds->ticket.data = 0;
407*7c478bd9Sstevel@tonic-gate 	}
408*7c478bd9Sstevel@tonic-gate 	if (creds->addresses) {
409*7c478bd9Sstevel@tonic-gate 	    krb5_free_addresses(context, creds->addresses);
410*7c478bd9Sstevel@tonic-gate 	    creds->addresses = 0;
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate     }
413*7c478bd9Sstevel@tonic-gate     return (retval);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
417*7c478bd9Sstevel@tonic-gate static krb5_error_code
418*7c478bd9Sstevel@tonic-gate make_preauth_list(context, ptypes, nptypes, ret_list)
419*7c478bd9Sstevel@tonic-gate     krb5_context	context;
420*7c478bd9Sstevel@tonic-gate     krb5_preauthtype *	ptypes;
421*7c478bd9Sstevel@tonic-gate     int			nptypes;
422*7c478bd9Sstevel@tonic-gate     krb5_pa_data ***	ret_list;
423*7c478bd9Sstevel@tonic-gate {
424*7c478bd9Sstevel@tonic-gate     krb5_preauthtype *		ptypep;
425*7c478bd9Sstevel@tonic-gate     krb5_pa_data **		preauthp;
426*7c478bd9Sstevel@tonic-gate     int				i;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate     if (nptypes < 0) {
429*7c478bd9Sstevel@tonic-gate  	for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++)
430*7c478bd9Sstevel@tonic-gate  	    ;
431*7c478bd9Sstevel@tonic-gate     }
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate     /* allocate space for a NULL to terminate the list */
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate     if ((preauthp =
436*7c478bd9Sstevel@tonic-gate  	 (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
437*7c478bd9Sstevel@tonic-gate  	return(ENOMEM);
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate     for (i=0; i<nptypes; i++) {
440*7c478bd9Sstevel@tonic-gate  	if ((preauthp[i] =
441*7c478bd9Sstevel@tonic-gate  	     (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
442*7c478bd9Sstevel@tonic-gate  	    for (; i>=0; i++)
443*7c478bd9Sstevel@tonic-gate  		free(preauthp[i]);
444*7c478bd9Sstevel@tonic-gate  	    free(preauthp);
445*7c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate  	preauthp[i]->magic = KV5M_PA_DATA;
448*7c478bd9Sstevel@tonic-gate  	preauthp[i]->pa_type = ptypes[i];
449*7c478bd9Sstevel@tonic-gate  	preauthp[i]->length = 0;
450*7c478bd9Sstevel@tonic-gate  	preauthp[i]->contents = 0;
451*7c478bd9Sstevel@tonic-gate     }
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate     /* fill in the terminating NULL */
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate     preauthp[nptypes] = NULL;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate     *ret_list = preauthp;
458*7c478bd9Sstevel@tonic-gate     return 0;
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate #define MAX_IN_TKT_LOOPS 16
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate /* begin libdefaults parsing code.  This should almost certainly move
464*7c478bd9Sstevel@tonic-gate    somewhere else, but I don't know where the correct somewhere else
465*7c478bd9Sstevel@tonic-gate    is yet. */
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate /* XXX Duplicating this is annoying; try to work on a better way.*/
468*7c478bd9Sstevel@tonic-gate static char *conf_yes[] = {
469*7c478bd9Sstevel@tonic-gate     "y", "yes", "true", "t", "1", "on",
470*7c478bd9Sstevel@tonic-gate     0,
471*7c478bd9Sstevel@tonic-gate };
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate static char *conf_no[] = {
474*7c478bd9Sstevel@tonic-gate     "n", "no", "false", "nil", "0", "off",
475*7c478bd9Sstevel@tonic-gate     0,
476*7c478bd9Sstevel@tonic-gate };
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate int
479*7c478bd9Sstevel@tonic-gate _krb5_conf_boolean(s)
480*7c478bd9Sstevel@tonic-gate      char *s;
481*7c478bd9Sstevel@tonic-gate {
482*7c478bd9Sstevel@tonic-gate     char **p;
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate     for(p=conf_yes; *p; p++) {
485*7c478bd9Sstevel@tonic-gate 	if (!strcasecmp(*p,s))
486*7c478bd9Sstevel@tonic-gate 	    return 1;
487*7c478bd9Sstevel@tonic-gate     }
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate     for(p=conf_no; *p; p++) {
490*7c478bd9Sstevel@tonic-gate 	if (!strcasecmp(*p,s))
491*7c478bd9Sstevel@tonic-gate 	    return 0;
492*7c478bd9Sstevel@tonic-gate     }
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate     /* Default to "no" */
495*7c478bd9Sstevel@tonic-gate     return 0;
496*7c478bd9Sstevel@tonic-gate }
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate static krb5_error_code
499*7c478bd9Sstevel@tonic-gate krb5_libdefault_string(context, realm, option, ret_value)
500*7c478bd9Sstevel@tonic-gate      krb5_context context;
501*7c478bd9Sstevel@tonic-gate      const krb5_data *realm;
502*7c478bd9Sstevel@tonic-gate      const char *option;
503*7c478bd9Sstevel@tonic-gate      char **ret_value;
504*7c478bd9Sstevel@tonic-gate {
505*7c478bd9Sstevel@tonic-gate     profile_t profile;
506*7c478bd9Sstevel@tonic-gate     const char *names[5];
507*7c478bd9Sstevel@tonic-gate     char **nameval = NULL;
508*7c478bd9Sstevel@tonic-gate     krb5_error_code retval;
509*7c478bd9Sstevel@tonic-gate     char realmstr[1024];
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate     if (realm->length > sizeof(realmstr)-1)
512*7c478bd9Sstevel@tonic-gate 	return(EINVAL);
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate     strncpy(realmstr, realm->data, realm->length);
515*7c478bd9Sstevel@tonic-gate     realmstr[realm->length] = '\0';
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate     if (!context || (context->magic != KV5M_CONTEXT))
518*7c478bd9Sstevel@tonic-gate 	return KV5M_CONTEXT;
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate     profile = context->profile;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate     names[0] = "realms";
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate     /*
525*7c478bd9Sstevel@tonic-gate      * Try number one:
526*7c478bd9Sstevel@tonic-gate      *
527*7c478bd9Sstevel@tonic-gate      * [realms]
528*7c478bd9Sstevel@tonic-gate      *		REALM = {
529*7c478bd9Sstevel@tonic-gate      *			option = <boolean>
530*7c478bd9Sstevel@tonic-gate      *		}
531*7c478bd9Sstevel@tonic-gate      */
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate     names[1] = realmstr;
534*7c478bd9Sstevel@tonic-gate     names[2] = option;
535*7c478bd9Sstevel@tonic-gate     names[3] = 0;
536*7c478bd9Sstevel@tonic-gate     retval = profile_get_values(profile, names, &nameval);
537*7c478bd9Sstevel@tonic-gate     if (retval == 0 && nameval && nameval[0])
538*7c478bd9Sstevel@tonic-gate 	goto goodbye;
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate     /*
541*7c478bd9Sstevel@tonic-gate      * Try number two:
542*7c478bd9Sstevel@tonic-gate      *
543*7c478bd9Sstevel@tonic-gate      * [libdefaults]
544*7c478bd9Sstevel@tonic-gate      *		option = <boolean>
545*7c478bd9Sstevel@tonic-gate      */
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate     names[0] = "libdefaults";
548*7c478bd9Sstevel@tonic-gate     names[1] = option;
549*7c478bd9Sstevel@tonic-gate     names[2] = 0;
550*7c478bd9Sstevel@tonic-gate     retval = profile_get_values(profile, names, &nameval);
551*7c478bd9Sstevel@tonic-gate     if (retval == 0 && nameval && nameval[0])
552*7c478bd9Sstevel@tonic-gate 	goto goodbye;
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate goodbye:
555*7c478bd9Sstevel@tonic-gate     if (!nameval)
556*7c478bd9Sstevel@tonic-gate 	return(ENOENT);
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate     if (!nameval[0]) {
559*7c478bd9Sstevel@tonic-gate         retval = ENOENT;
560*7c478bd9Sstevel@tonic-gate     } else {
561*7c478bd9Sstevel@tonic-gate         *ret_value = malloc(strlen(nameval[0]) + 1);
562*7c478bd9Sstevel@tonic-gate         if (!*ret_value)
563*7c478bd9Sstevel@tonic-gate             retval = ENOMEM;
564*7c478bd9Sstevel@tonic-gate         else
565*7c478bd9Sstevel@tonic-gate             strcpy(*ret_value, nameval[0]);
566*7c478bd9Sstevel@tonic-gate     }
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate     profile_free_list(nameval);
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate     return retval;
571*7c478bd9Sstevel@tonic-gate }
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate /* not static so verify_init_creds() can call it */
574*7c478bd9Sstevel@tonic-gate /* as well as the DNS code */
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate krb5_error_code
577*7c478bd9Sstevel@tonic-gate krb5_libdefault_boolean(context, realm, option, ret_value)
578*7c478bd9Sstevel@tonic-gate      krb5_context context;
579*7c478bd9Sstevel@tonic-gate      const char *option;
580*7c478bd9Sstevel@tonic-gate      const krb5_data *realm;
581*7c478bd9Sstevel@tonic-gate      int *ret_value;
582*7c478bd9Sstevel@tonic-gate {
583*7c478bd9Sstevel@tonic-gate     char *string = NULL;
584*7c478bd9Sstevel@tonic-gate     krb5_error_code retval;
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate     retval = krb5_libdefault_string(context, realm, option, &string);
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate     if (retval)
589*7c478bd9Sstevel@tonic-gate 	return(retval);
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate     *ret_value = _krb5_conf_boolean(string);
592*7c478bd9Sstevel@tonic-gate     free(string);
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate     return(0);
595*7c478bd9Sstevel@tonic-gate }
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
598*7c478bd9Sstevel@tonic-gate krb5_get_init_creds(context, creds, client, prompter, prompter_data,
599*7c478bd9Sstevel@tonic-gate 		    start_time, in_tkt_service, options, gak_fct, gak_data,
600*7c478bd9Sstevel@tonic-gate 		    use_master, as_reply)
601*7c478bd9Sstevel@tonic-gate      krb5_context context;
602*7c478bd9Sstevel@tonic-gate      krb5_creds *creds;
603*7c478bd9Sstevel@tonic-gate      krb5_principal client;
604*7c478bd9Sstevel@tonic-gate      krb5_prompter_fct prompter;
605*7c478bd9Sstevel@tonic-gate      void *prompter_data;
606*7c478bd9Sstevel@tonic-gate      krb5_deltat start_time;
607*7c478bd9Sstevel@tonic-gate      char *in_tkt_service;
608*7c478bd9Sstevel@tonic-gate      krb5_get_init_creds_opt *options;
609*7c478bd9Sstevel@tonic-gate      krb5_gic_get_as_key_fct gak_fct;
610*7c478bd9Sstevel@tonic-gate      void *gak_data;
611*7c478bd9Sstevel@tonic-gate      int  use_master;
612*7c478bd9Sstevel@tonic-gate      krb5_kdc_rep **as_reply;
613*7c478bd9Sstevel@tonic-gate {
614*7c478bd9Sstevel@tonic-gate     krb5_error_code ret;
615*7c478bd9Sstevel@tonic-gate     krb5_kdc_req request;
616*7c478bd9Sstevel@tonic-gate     krb5_pa_data **padata;
617*7c478bd9Sstevel@tonic-gate     int tempint;
618*7c478bd9Sstevel@tonic-gate     char *tempstr;
619*7c478bd9Sstevel@tonic-gate     krb5_deltat renew_life;
620*7c478bd9Sstevel@tonic-gate     krb5_deltat max_life;
621*7c478bd9Sstevel@tonic-gate     int loopcount;
622*7c478bd9Sstevel@tonic-gate     krb5_data salt;
623*7c478bd9Sstevel@tonic-gate     krb5_data s2kparams;
624*7c478bd9Sstevel@tonic-gate     krb5_keyblock as_key;
625*7c478bd9Sstevel@tonic-gate     krb5_error *err_reply;
626*7c478bd9Sstevel@tonic-gate     krb5_kdc_rep *local_as_reply;
627*7c478bd9Sstevel@tonic-gate     krb5_timestamp time_now;
628*7c478bd9Sstevel@tonic-gate     krb5_enctype etype = 0;
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate     /* initialize everything which will be freed at cleanup */
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate     s2kparams.data = NULL;
633*7c478bd9Sstevel@tonic-gate     s2kparams.length = 0;
634*7c478bd9Sstevel@tonic-gate     request.server = NULL;
635*7c478bd9Sstevel@tonic-gate     request.ktype = NULL;
636*7c478bd9Sstevel@tonic-gate     request.addresses = NULL;
637*7c478bd9Sstevel@tonic-gate     request.padata = NULL;
638*7c478bd9Sstevel@tonic-gate     padata = NULL;
639*7c478bd9Sstevel@tonic-gate     salt.length = 0;
640*7c478bd9Sstevel@tonic-gate     salt.data = NULL;
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate     (void) memset(&as_key, 0, sizeof(as_key));
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate     local_as_reply = 0;
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate     /*
647*7c478bd9Sstevel@tonic-gate      * Set up the basic request structure
648*7c478bd9Sstevel@tonic-gate      */
649*7c478bd9Sstevel@tonic-gate     request.magic = KV5M_KDC_REQ;
650*7c478bd9Sstevel@tonic-gate     request.msg_type = KRB5_AS_REQ;
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate     /* request.padata is filled in later */
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate     request.kdc_options = context->kdc_default_options;
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate     /* forwardable */
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE))
659*7c478bd9Sstevel@tonic-gate 	tempint = options->forwardable;
660*7c478bd9Sstevel@tonic-gate     else if ((ret = krb5_libdefault_boolean(context, &client->realm,
661*7c478bd9Sstevel@tonic-gate 					    "forwardable", &tempint)) == 0)
662*7c478bd9Sstevel@tonic-gate 	/*EMPTY*/
663*7c478bd9Sstevel@tonic-gate 	;
664*7c478bd9Sstevel@tonic-gate     else
665*7c478bd9Sstevel@tonic-gate 	    tempint = 0;
666*7c478bd9Sstevel@tonic-gate     if (tempint)
667*7c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_FORWARDABLE;
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate     /* proxiable */
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE))
672*7c478bd9Sstevel@tonic-gate 	tempint = options->proxiable;
673*7c478bd9Sstevel@tonic-gate     else if ((ret = krb5_libdefault_boolean(context, &client->realm,
674*7c478bd9Sstevel@tonic-gate 					    "proxiable", &tempint)) == 0)
675*7c478bd9Sstevel@tonic-gate 	/*EMPTY*/
676*7c478bd9Sstevel@tonic-gate 	;
677*7c478bd9Sstevel@tonic-gate     else
678*7c478bd9Sstevel@tonic-gate 	    tempint = 0;
679*7c478bd9Sstevel@tonic-gate     if (tempint)
680*7c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_PROXIABLE;
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate     /* renewable */
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) {
685*7c478bd9Sstevel@tonic-gate 	renew_life = options->renew_life;
686*7c478bd9Sstevel@tonic-gate     } else if ((ret = krb5_libdefault_string(context, &client->realm,
687*7c478bd9Sstevel@tonic-gate 					     "renew_lifetime", &tempstr))
688*7c478bd9Sstevel@tonic-gate 	       == 0) {
689*7c478bd9Sstevel@tonic-gate 	if (ret = krb5_string_to_deltat(tempstr, &renew_life)) {
690*7c478bd9Sstevel@tonic-gate 	    free(tempstr);
691*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
692*7c478bd9Sstevel@tonic-gate 	}
693*7c478bd9Sstevel@tonic-gate     } else {
694*7c478bd9Sstevel@tonic-gate 	renew_life = 0;
695*7c478bd9Sstevel@tonic-gate     }
696*7c478bd9Sstevel@tonic-gate     if (renew_life > 0)
697*7c478bd9Sstevel@tonic-gate 	request.kdc_options |= KDC_OPT_RENEWABLE;
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate     /* allow_postdate */
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate     if (start_time > 0)
702*7c478bd9Sstevel@tonic-gate 	request.kdc_options |= (KDC_OPT_ALLOW_POSTDATE|KDC_OPT_POSTDATED);
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate     /* client */
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate     request.client = client;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate     if (in_tkt_service) {
709*7c478bd9Sstevel@tonic-gate 	/* this is ugly, because so are the data structures involved.  I'm
710*7c478bd9Sstevel@tonic-gate 	   in the library, so I'm going to manipulate the data structures
711*7c478bd9Sstevel@tonic-gate 	   directly, otherwise, it will be worse. */
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 	if (ret = krb5_parse_name(context, in_tkt_service, &request.server))
714*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	/* stuff the client realm into the server principal.
717*7c478bd9Sstevel@tonic-gate 	   realloc if necessary */
718*7c478bd9Sstevel@tonic-gate 	if (request.server->realm.length < request.client->realm.length)
719*7c478bd9Sstevel@tonic-gate 	    if ((request.server->realm.data =
720*7c478bd9Sstevel@tonic-gate 		 (char *) realloc(request.server->realm.data,
721*7c478bd9Sstevel@tonic-gate 				  request.client->realm.length)) == NULL) {
722*7c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
723*7c478bd9Sstevel@tonic-gate 		goto cleanup;
724*7c478bd9Sstevel@tonic-gate 	    }
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	request.server->realm.length = request.client->realm.length;
727*7c478bd9Sstevel@tonic-gate 	memcpy(request.server->realm.data, request.client->realm.data,
728*7c478bd9Sstevel@tonic-gate 	       request.client->realm.length);
729*7c478bd9Sstevel@tonic-gate     } else {
730*7c478bd9Sstevel@tonic-gate 	if (ret = krb5_build_principal_ext(context, &request.server,
731*7c478bd9Sstevel@tonic-gate 					   request.client->realm.length,
732*7c478bd9Sstevel@tonic-gate 					   request.client->realm.data,
733*7c478bd9Sstevel@tonic-gate 					   KRB5_TGS_NAME_SIZE,
734*7c478bd9Sstevel@tonic-gate 					   KRB5_TGS_NAME,
735*7c478bd9Sstevel@tonic-gate 					   request.client->realm.length,
736*7c478bd9Sstevel@tonic-gate 					   request.client->realm.data,
737*7c478bd9Sstevel@tonic-gate 					   0))
738*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
739*7c478bd9Sstevel@tonic-gate     }
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate     if (ret = krb5_timeofday(context, &request.from))
742*7c478bd9Sstevel@tonic-gate 	goto cleanup;
743*7c478bd9Sstevel@tonic-gate     request.from += start_time;
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate     request.till = request.from;
746*7c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE))
747*7c478bd9Sstevel@tonic-gate 	request.till += options->tkt_life;
748*7c478bd9Sstevel@tonic-gate     else if ((ret = krb5_libdefault_string(context, &client->realm,
749*7c478bd9Sstevel@tonic-gate 					     "max_lifetime", &tempstr)) == 0) {
750*7c478bd9Sstevel@tonic-gate 	/* Solaris Kerberos: max_lifetime parameter support (tkt lifetime) */
751*7c478bd9Sstevel@tonic-gate 	if (ret = krb5_string_to_deltat(tempstr, &max_life)) {
752*7c478bd9Sstevel@tonic-gate 	    free(tempstr);
753*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
754*7c478bd9Sstevel@tonic-gate 	}
755*7c478bd9Sstevel@tonic-gate 	request.till += max_life;
756*7c478bd9Sstevel@tonic-gate     } else {
757*7c478bd9Sstevel@tonic-gate 	/* Solaris Kerberos: defaulting to infinity.  Note 0 == infinity (ASN1
758*7c478bd9Sstevel@tonic-gate 	 * encoding will do the right thing).
759*7c478bd9Sstevel@tonic-gate 	 */
760*7c478bd9Sstevel@tonic-gate 	request.till = 0;
761*7c478bd9Sstevel@tonic-gate     }
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate     if (renew_life > 0) {
764*7c478bd9Sstevel@tonic-gate 	request.rtime = request.from;
765*7c478bd9Sstevel@tonic-gate 	request.rtime += renew_life;
766*7c478bd9Sstevel@tonic-gate     } else {
767*7c478bd9Sstevel@tonic-gate 	request.rtime = 0;
768*7c478bd9Sstevel@tonic-gate     }
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate     /* nonce is filled in by send_as_request */
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)) {
773*7c478bd9Sstevel@tonic-gate 	request.ktype = options->etype_list;
774*7c478bd9Sstevel@tonic-gate 	request.nktypes = options->etype_list_length;
775*7c478bd9Sstevel@tonic-gate     } else if ((ret = krb5_get_default_in_tkt_ktypes(context,
776*7c478bd9Sstevel@tonic-gate 						     &request.ktype)) == 0) {
777*7c478bd9Sstevel@tonic-gate 	for (request.nktypes = 0;
778*7c478bd9Sstevel@tonic-gate 	     request.ktype[request.nktypes];
779*7c478bd9Sstevel@tonic-gate 	     request.nktypes++)
780*7c478bd9Sstevel@tonic-gate 	    ;
781*7c478bd9Sstevel@tonic-gate     } else {
782*7c478bd9Sstevel@tonic-gate 	/* there isn't any useful default here.  ret is set from above */
783*7c478bd9Sstevel@tonic-gate 	goto cleanup;
784*7c478bd9Sstevel@tonic-gate     }
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)) {
787*7c478bd9Sstevel@tonic-gate 	request.addresses = options->address_list;
788*7c478bd9Sstevel@tonic-gate     }
789*7c478bd9Sstevel@tonic-gate     /* it would be nice if this parsed out an address list, but
790*7c478bd9Sstevel@tonic-gate        that would be work. */
791*7c478bd9Sstevel@tonic-gate     else if (((ret = krb5_libdefault_boolean(context, &client->realm,
792*7c478bd9Sstevel@tonic-gate 					    "no_addresses", &tempint)) == 0)
793*7c478bd9Sstevel@tonic-gate 	     && tempint) {
794*7c478bd9Sstevel@tonic-gate 	    /*EMPTY*/
795*7c478bd9Sstevel@tonic-gate 	    ;
796*7c478bd9Sstevel@tonic-gate     } else if (((ret = krb5_libdefault_boolean(context, &client->realm,
797*7c478bd9Sstevel@tonic-gate 					    "noaddresses", &tempint)) == 0)
798*7c478bd9Sstevel@tonic-gate 	     && tempint) {
799*7c478bd9Sstevel@tonic-gate 	    /*EMPTY*/
800*7c478bd9Sstevel@tonic-gate 	    ;
801*7c478bd9Sstevel@tonic-gate     } else {
802*7c478bd9Sstevel@tonic-gate 	if ((ret = krb5_os_localaddr(context, &request.addresses)))
803*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
804*7c478bd9Sstevel@tonic-gate     }
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate     request.authorization_data.ciphertext.length = 0;
807*7c478bd9Sstevel@tonic-gate     request.authorization_data.ciphertext.data = 0;
808*7c478bd9Sstevel@tonic-gate     request.unenc_authdata = 0;
809*7c478bd9Sstevel@tonic-gate     request.second_ticket = 0;
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate     /* set up the other state.  */
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
814*7c478bd9Sstevel@tonic-gate 	if (ret = make_preauth_list(context, options->preauth_list,
815*7c478bd9Sstevel@tonic-gate 				    options->preauth_list_length,
816*7c478bd9Sstevel@tonic-gate 				    &padata))
817*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
818*7c478bd9Sstevel@tonic-gate     }
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate     /* the salt is allocated from somewhere, unless it is from the caller,
821*7c478bd9Sstevel@tonic-gate        then it is a reference */
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate     if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)) {
824*7c478bd9Sstevel@tonic-gate 	salt = *options->salt;
825*7c478bd9Sstevel@tonic-gate     } else {
826*7c478bd9Sstevel@tonic-gate 	salt.length = (unsigned int)-1;
827*7c478bd9Sstevel@tonic-gate 	salt.data = NULL;
828*7c478bd9Sstevel@tonic-gate     }
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate     /* now, loop processing preauth data and talking to the kdc */
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate     for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) {
833*7c478bd9Sstevel@tonic-gate 	if (request.padata) {
834*7c478bd9Sstevel@tonic-gate 	    krb5_free_pa_data(context, request.padata);
835*7c478bd9Sstevel@tonic-gate 	    request.padata = NULL;
836*7c478bd9Sstevel@tonic-gate 	}
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	if (ret = krb5_do_preauth(context, &request,
839*7c478bd9Sstevel@tonic-gate 			  padata, &request.padata,
840*7c478bd9Sstevel@tonic-gate 			  &salt, &s2kparams, &etype, &as_key, prompter,
841*7c478bd9Sstevel@tonic-gate 			  prompter_data, gak_fct, gak_data))
842*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	if (padata) {
845*7c478bd9Sstevel@tonic-gate 	    krb5_free_pa_data(context, padata);
846*7c478bd9Sstevel@tonic-gate 	    padata = 0;
847*7c478bd9Sstevel@tonic-gate 	}
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	err_reply = 0;
850*7c478bd9Sstevel@tonic-gate 	local_as_reply = 0;
851*7c478bd9Sstevel@tonic-gate 	if ((ret = send_as_request(context, &request, &time_now, &err_reply,
852*7c478bd9Sstevel@tonic-gate 				   &local_as_reply, use_master)))
853*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	if (err_reply) {
856*7c478bd9Sstevel@tonic-gate 	    if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
857*7c478bd9Sstevel@tonic-gate 		err_reply->e_data.length > 0) {
858*7c478bd9Sstevel@tonic-gate 		ret = decode_krb5_padata_sequence(&err_reply->e_data,
859*7c478bd9Sstevel@tonic-gate 						  &padata);
860*7c478bd9Sstevel@tonic-gate 		krb5_free_error(context, err_reply);
861*7c478bd9Sstevel@tonic-gate 		if (ret)
862*7c478bd9Sstevel@tonic-gate 		    goto cleanup;
863*7c478bd9Sstevel@tonic-gate 	    } else {
864*7c478bd9Sstevel@tonic-gate 		ret = err_reply->error + ERROR_TABLE_BASE_krb5;
865*7c478bd9Sstevel@tonic-gate 		krb5_free_error(context, err_reply);
866*7c478bd9Sstevel@tonic-gate 		goto cleanup;
867*7c478bd9Sstevel@tonic-gate 	    }
868*7c478bd9Sstevel@tonic-gate 	} else if (local_as_reply) {
869*7c478bd9Sstevel@tonic-gate 	    break;
870*7c478bd9Sstevel@tonic-gate 	} else {
871*7c478bd9Sstevel@tonic-gate 	    ret = KRB5KRB_AP_ERR_MSG_TYPE;
872*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
873*7c478bd9Sstevel@tonic-gate 	}
874*7c478bd9Sstevel@tonic-gate     }
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate     if (loopcount == MAX_IN_TKT_LOOPS) {
877*7c478bd9Sstevel@tonic-gate 	ret = KRB5_GET_IN_TKT_LOOP;
878*7c478bd9Sstevel@tonic-gate 	goto cleanup;
879*7c478bd9Sstevel@tonic-gate     }
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate     /* process any preauth data in the as_reply */
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate     if (ret = krb5_do_preauth(context, &request,
884*7c478bd9Sstevel@tonic-gate 		      local_as_reply->padata, &padata,
885*7c478bd9Sstevel@tonic-gate 		      &salt, &s2kparams, &etype, &as_key, prompter,
886*7c478bd9Sstevel@tonic-gate 		      prompter_data, gak_fct, gak_data))
887*7c478bd9Sstevel@tonic-gate 	goto cleanup;
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate     /* XXX if there's padata on output, something is wrong, but it's
890*7c478bd9Sstevel@tonic-gate        not obviously an error */
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate     /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
893*7c478bd9Sstevel@tonic-gate        the AS_REP comes back encrypted in the user's longterm key
894*7c478bd9Sstevel@tonic-gate        instead of in the SAD. If there was a SAM preauth, there
895*7c478bd9Sstevel@tonic-gate        will be an as_key here which will be the SAD. If that fails,
896*7c478bd9Sstevel@tonic-gate        use the gak_fct to get the password, and try again. */
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate     /* XXX because etypes are handled poorly (particularly wrt SAM,
899*7c478bd9Sstevel@tonic-gate        where the etype is fixed by the kdc), we may want to try
900*7c478bd9Sstevel@tonic-gate        decrypt_as_reply twice.  If there's an as_key available, try
901*7c478bd9Sstevel@tonic-gate        it.  If decrypting the as_rep fails, or if there isn't an
902*7c478bd9Sstevel@tonic-gate        as_key at all yet, then use the gak_fct to get one, and try
903*7c478bd9Sstevel@tonic-gate        again.  */
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate     if (as_key.length)
906*7c478bd9Sstevel@tonic-gate 	ret = decrypt_as_reply(context, (krb5_kdc_req *)NULL, local_as_reply,
907*7c478bd9Sstevel@tonic-gate 			       (git_key_proc)NULL, (krb5_const_pointer)NULL,
908*7c478bd9Sstevel@tonic-gate 			       &as_key, krb5_kdc_rep_decrypt_proc,
909*7c478bd9Sstevel@tonic-gate 			       (krb5_const_pointer)NULL);
910*7c478bd9Sstevel@tonic-gate     else
911*7c478bd9Sstevel@tonic-gate 	ret = -1;
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate     if (ret) {
914*7c478bd9Sstevel@tonic-gate 	/* if we haven't get gotten a key, get it now */
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	if (ret = ((*gak_fct)(context, request.client,
917*7c478bd9Sstevel@tonic-gate 			      local_as_reply->enc_part.enctype,
918*7c478bd9Sstevel@tonic-gate 			      prompter, prompter_data, &salt, &s2kparams,
919*7c478bd9Sstevel@tonic-gate 			      &as_key, gak_data)))
920*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	if (ret=decrypt_as_reply(context, (krb5_kdc_req *)NULL, local_as_reply,
923*7c478bd9Sstevel@tonic-gate 				   (git_key_proc)NULL, (krb5_const_pointer)NULL,
924*7c478bd9Sstevel@tonic-gate 				   &as_key, krb5_kdc_rep_decrypt_proc,
925*7c478bd9Sstevel@tonic-gate 				   (krb5_const_pointer)NULL))
926*7c478bd9Sstevel@tonic-gate 	    goto cleanup;
927*7c478bd9Sstevel@tonic-gate     }
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate     if (ret = verify_as_reply(context, time_now, &request, local_as_reply))
930*7c478bd9Sstevel@tonic-gate 	goto cleanup;
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	/*
933*7c478bd9Sstevel@tonic-gate 	 * XXX this should be inside stash_as_reply, but as long as
934*7c478bd9Sstevel@tonic-gate 	 * get_in_tkt is still around using that arg as an in/out, I can't
935*7c478bd9Sstevel@tonic-gate 	 * do that
936*7c478bd9Sstevel@tonic-gate 	 */
937*7c478bd9Sstevel@tonic-gate 	(void) memset(creds, 0, sizeof(*creds));
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate     if (ret = stash_as_reply(context, time_now, &request, local_as_reply,
940*7c478bd9Sstevel@tonic-gate 			     creds, (krb5_ccache)NULL))
941*7c478bd9Sstevel@tonic-gate 	goto cleanup;
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate     /* success */
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate     ret = 0;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate cleanup:
948*7c478bd9Sstevel@tonic-gate     if (request.server)
949*7c478bd9Sstevel@tonic-gate 	krb5_free_principal(context, request.server);
950*7c478bd9Sstevel@tonic-gate     if (request.ktype &&
951*7c478bd9Sstevel@tonic-gate 	(!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))))
952*7c478bd9Sstevel@tonic-gate 	free(request.ktype);
953*7c478bd9Sstevel@tonic-gate     if (request.addresses &&
954*7c478bd9Sstevel@tonic-gate 	(!(options &&
955*7c478bd9Sstevel@tonic-gate 	   (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST))))
956*7c478bd9Sstevel@tonic-gate 	krb5_free_addresses(context, request.addresses);
957*7c478bd9Sstevel@tonic-gate     if (padata)
958*7c478bd9Sstevel@tonic-gate 	krb5_free_pa_data(context, padata);
959*7c478bd9Sstevel@tonic-gate     if (request.padata)
960*7c478bd9Sstevel@tonic-gate 	krb5_free_pa_data(context, request.padata);
961*7c478bd9Sstevel@tonic-gate     if (as_key.length)
962*7c478bd9Sstevel@tonic-gate 	krb5_free_keyblock_contents(context, &as_key);
963*7c478bd9Sstevel@tonic-gate     if (salt.data &&
964*7c478bd9Sstevel@tonic-gate 	(!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT))))
965*7c478bd9Sstevel@tonic-gate 	krb5_xfree(salt.data);
966*7c478bd9Sstevel@tonic-gate     if (as_reply)
967*7c478bd9Sstevel@tonic-gate 	*as_reply = local_as_reply;
968*7c478bd9Sstevel@tonic-gate     else if (local_as_reply)
969*7c478bd9Sstevel@tonic-gate 	krb5_free_kdc_rep(context, local_as_reply);
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate     return(ret);
972*7c478bd9Sstevel@tonic-gate }
973