xref: /freebsd/crypto/heimdal/lib/krb5/get_cred.c (revision f74fc686)
1b528cefcSMark Murray /*
2ae771770SStanislav Sedov  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6ae771770SStanislav Sedov  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7ae771770SStanislav Sedov  *
8b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
9b528cefcSMark Murray  * modification, are permitted provided that the following conditions
10b528cefcSMark Murray  * are met:
11b528cefcSMark Murray  *
12b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
13b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
14b528cefcSMark Murray  *
15b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
16b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
17b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
18b528cefcSMark Murray  *
19b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
20b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
21b528cefcSMark Murray  *    without specific prior written permission.
22b528cefcSMark Murray  *
23b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33b528cefcSMark Murray  * SUCH DAMAGE.
34b528cefcSMark Murray  */
35b528cefcSMark Murray 
36ae771770SStanislav Sedov #include "krb5_locl.h"
37ae771770SStanislav Sedov #include <assert.h>
38b528cefcSMark Murray 
39ae771770SStanislav Sedov static krb5_error_code
40ae771770SStanislav Sedov get_cred_kdc_capath(krb5_context, krb5_kdc_flags,
41ae771770SStanislav Sedov 		    krb5_ccache, krb5_creds *, krb5_principal,
42ae771770SStanislav Sedov 		    Ticket *, krb5_creds **, krb5_creds ***);
43b528cefcSMark Murray 
44b528cefcSMark Murray /*
45b528cefcSMark Murray  * Take the `body' and encode it into `padata' using the credentials
46b528cefcSMark Murray  * in `creds'.
47b528cefcSMark Murray  */
48b528cefcSMark Murray 
49b528cefcSMark Murray static krb5_error_code
make_pa_tgs_req(krb5_context context,krb5_auth_context ac,KDC_REQ_BODY * body,PA_DATA * padata,krb5_creds * creds)50b528cefcSMark Murray make_pa_tgs_req(krb5_context context,
51b528cefcSMark Murray 		krb5_auth_context ac,
52b528cefcSMark Murray 		KDC_REQ_BODY *body,
53b528cefcSMark Murray 		PA_DATA *padata,
54ae771770SStanislav Sedov 		krb5_creds *creds)
55b528cefcSMark Murray {
56b528cefcSMark Murray     u_char *buf;
57b528cefcSMark Murray     size_t buf_size;
58ae771770SStanislav Sedov     size_t len = 0;
59b528cefcSMark Murray     krb5_data in_data;
60b528cefcSMark Murray     krb5_error_code ret;
61b528cefcSMark Murray 
620cadf2f4SJacques Vidrine     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
630cadf2f4SJacques Vidrine     if (ret)
64b528cefcSMark Murray 	goto out;
650cadf2f4SJacques Vidrine     if(buf_size != len)
660cadf2f4SJacques Vidrine 	krb5_abortx(context, "internal error in ASN.1 encoder");
67b528cefcSMark Murray 
68b528cefcSMark Murray     in_data.length = len;
690cadf2f4SJacques Vidrine     in_data.data   = buf;
70c19800e8SDoug Rabson     ret = _krb5_mk_req_internal(context, &ac, 0, &in_data, creds,
71b528cefcSMark Murray 				&padata->padata_value,
725e9cd1aeSAssar Westerlund 				KRB5_KU_TGS_REQ_AUTH_CKSUM,
73ae771770SStanislav Sedov 				KRB5_KU_TGS_REQ_AUTH);
74b528cefcSMark Murray  out:
75b528cefcSMark Murray     free (buf);
76b528cefcSMark Murray     if(ret)
77b528cefcSMark Murray 	return ret;
785e9cd1aeSAssar Westerlund     padata->padata_type = KRB5_PADATA_TGS_REQ;
79b528cefcSMark Murray     return 0;
80b528cefcSMark Murray }
81b528cefcSMark Murray 
82b528cefcSMark Murray /*
83b528cefcSMark Murray  * Set the `enc-authorization-data' in `req_body' based on `authdata'
84b528cefcSMark Murray  */
85b528cefcSMark Murray 
86b528cefcSMark Murray static krb5_error_code
set_auth_data(krb5_context context,KDC_REQ_BODY * req_body,krb5_authdata * authdata,krb5_keyblock * subkey)87b528cefcSMark Murray set_auth_data (krb5_context context,
88b528cefcSMark Murray 	       KDC_REQ_BODY *req_body,
89b528cefcSMark Murray 	       krb5_authdata *authdata,
90ae771770SStanislav Sedov 	       krb5_keyblock *subkey)
91b528cefcSMark Murray {
92b528cefcSMark Murray     if(authdata->len) {
93ae771770SStanislav Sedov 	size_t len = 0, buf_size;
94b528cefcSMark Murray 	unsigned char *buf;
95b528cefcSMark Murray 	krb5_crypto crypto;
96b528cefcSMark Murray 	krb5_error_code ret;
97b528cefcSMark Murray 
98c19800e8SDoug Rabson 	ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata,
99c19800e8SDoug Rabson 			   &len, ret);
1000cadf2f4SJacques Vidrine 	if (ret)
101b528cefcSMark Murray 	    return ret;
102c19800e8SDoug Rabson 	if (buf_size != len)
103c19800e8SDoug Rabson 	    krb5_abortx(context, "internal error in ASN.1 encoder");
104b528cefcSMark Murray 
105b528cefcSMark Murray 	ALLOC(req_body->enc_authorization_data, 1);
106b528cefcSMark Murray 	if (req_body->enc_authorization_data == NULL) {
107b528cefcSMark Murray 	    free (buf);
108ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM,
109ae771770SStanislav Sedov 				   N_("malloc: out of memory", ""));
110adb0ddaeSAssar Westerlund 	    return ENOMEM;
111b528cefcSMark Murray 	}
112ae771770SStanislav Sedov 	ret = krb5_crypto_init(context, subkey, 0, &crypto);
113b528cefcSMark Murray 	if (ret) {
114b528cefcSMark Murray 	    free (buf);
115b528cefcSMark Murray 	    free (req_body->enc_authorization_data);
116c19800e8SDoug Rabson 	    req_body->enc_authorization_data = NULL;
117b528cefcSMark Murray 	    return ret;
118b528cefcSMark Murray 	}
119b528cefcSMark Murray 	krb5_encrypt_EncryptedData(context,
120b528cefcSMark Murray 				   crypto,
121b528cefcSMark Murray 				   KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
122b528cefcSMark Murray 				   buf,
123b528cefcSMark Murray 				   len,
124b528cefcSMark Murray 				   0,
125b528cefcSMark Murray 				   req_body->enc_authorization_data);
126b528cefcSMark Murray 	free (buf);
127b528cefcSMark Murray 	krb5_crypto_destroy(context, crypto);
128b528cefcSMark Murray     } else {
129b528cefcSMark Murray 	req_body->enc_authorization_data = NULL;
130b528cefcSMark Murray     }
131b528cefcSMark Murray     return 0;
132b528cefcSMark Murray }
133b528cefcSMark Murray 
134b528cefcSMark Murray /*
135b528cefcSMark Murray  * Create a tgs-req in `t' with `addresses', `flags', `second_ticket'
136b528cefcSMark Murray  * (if not-NULL), `in_creds', `krbtgt', and returning the generated
137b528cefcSMark Murray  * subkey in `subkey'.
138b528cefcSMark Murray  */
139b528cefcSMark Murray 
140b528cefcSMark Murray static krb5_error_code
init_tgs_req(krb5_context context,krb5_ccache ccache,krb5_addresses * addresses,krb5_kdc_flags flags,Ticket * second_ticket,krb5_creds * in_creds,krb5_creds * krbtgt,unsigned nonce,const METHOD_DATA * padata,krb5_keyblock ** subkey,TGS_REQ * t)141b528cefcSMark Murray init_tgs_req (krb5_context context,
142b528cefcSMark Murray 	      krb5_ccache ccache,
143b528cefcSMark Murray 	      krb5_addresses *addresses,
144b528cefcSMark Murray 	      krb5_kdc_flags flags,
145b528cefcSMark Murray 	      Ticket *second_ticket,
146b528cefcSMark Murray 	      krb5_creds *in_creds,
147b528cefcSMark Murray 	      krb5_creds *krbtgt,
148b528cefcSMark Murray 	      unsigned nonce,
149c19800e8SDoug Rabson 	      const METHOD_DATA *padata,
150b528cefcSMark Murray 	      krb5_keyblock **subkey,
151ae771770SStanislav Sedov 	      TGS_REQ *t)
152b528cefcSMark Murray {
153ae771770SStanislav Sedov     krb5_auth_context ac = NULL;
1540cadf2f4SJacques Vidrine     krb5_error_code ret = 0;
155b528cefcSMark Murray 
156b528cefcSMark Murray     memset(t, 0, sizeof(*t));
157b528cefcSMark Murray     t->pvno = 5;
158b528cefcSMark Murray     t->msg_type = krb_tgs_req;
159b528cefcSMark Murray     if (in_creds->session.keytype) {
1600cadf2f4SJacques Vidrine 	ALLOC_SEQ(&t->req_body.etype, 1);
1610cadf2f4SJacques Vidrine 	if(t->req_body.etype.val == NULL) {
1620cadf2f4SJacques Vidrine 	    ret = ENOMEM;
163ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
164ae771770SStanislav Sedov 				   N_("malloc: out of memory", ""));
1650cadf2f4SJacques Vidrine 	    goto fail;
1660cadf2f4SJacques Vidrine 	}
1670cadf2f4SJacques Vidrine 	t->req_body.etype.val[0] = in_creds->session.keytype;
168b528cefcSMark Murray     } else {
169ae771770SStanislav Sedov 	ret = _krb5_init_etype(context,
170ae771770SStanislav Sedov 			       KRB5_PDU_TGS_REQUEST,
171b528cefcSMark Murray 			       &t->req_body.etype.len,
172b528cefcSMark Murray 			       &t->req_body.etype.val,
173b528cefcSMark Murray 			       NULL);
174b528cefcSMark Murray     }
175b528cefcSMark Murray     if (ret)
176b528cefcSMark Murray 	goto fail;
177b528cefcSMark Murray     t->req_body.addresses = addresses;
178b528cefcSMark Murray     t->req_body.kdc_options = flags.b;
179b528cefcSMark Murray     ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm);
180b528cefcSMark Murray     if (ret)
181b528cefcSMark Murray 	goto fail;
182b528cefcSMark Murray     ALLOC(t->req_body.sname, 1);
183b528cefcSMark Murray     if (t->req_body.sname == NULL) {
184b528cefcSMark Murray 	ret = ENOMEM;
185ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
186b528cefcSMark Murray 	goto fail;
187b528cefcSMark Murray     }
1885e9cd1aeSAssar Westerlund 
1895e9cd1aeSAssar Westerlund     /* some versions of some code might require that the client be
1905e9cd1aeSAssar Westerlund        present in TGS-REQs, but this is clearly against the spec */
1915e9cd1aeSAssar Westerlund 
192b528cefcSMark Murray     ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname);
193b528cefcSMark Murray     if (ret)
194b528cefcSMark Murray 	goto fail;
195b528cefcSMark Murray 
196b528cefcSMark Murray     /* req_body.till should be NULL if there is no endtime specified,
197b528cefcSMark Murray        but old MIT code (like DCE secd) doesn't like that */
198b528cefcSMark Murray     ALLOC(t->req_body.till, 1);
199b528cefcSMark Murray     if(t->req_body.till == NULL){
200b528cefcSMark Murray 	ret = ENOMEM;
201ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
202b528cefcSMark Murray 	goto fail;
203b528cefcSMark Murray     }
204b528cefcSMark Murray     *t->req_body.till = in_creds->times.endtime;
205b528cefcSMark Murray 
206b528cefcSMark Murray     t->req_body.nonce = nonce;
207b528cefcSMark Murray     if(second_ticket){
208b528cefcSMark Murray 	ALLOC(t->req_body.additional_tickets, 1);
209b528cefcSMark Murray 	if (t->req_body.additional_tickets == NULL) {
210b528cefcSMark Murray 	    ret = ENOMEM;
211ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
212ae771770SStanislav Sedov 				   N_("malloc: out of memory", ""));
213b528cefcSMark Murray 	    goto fail;
214b528cefcSMark Murray 	}
215b528cefcSMark Murray 	ALLOC_SEQ(t->req_body.additional_tickets, 1);
216b528cefcSMark Murray 	if (t->req_body.additional_tickets->val == NULL) {
217b528cefcSMark Murray 	    ret = ENOMEM;
218ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
219ae771770SStanislav Sedov 				   N_("malloc: out of memory", ""));
220b528cefcSMark Murray 	    goto fail;
221b528cefcSMark Murray 	}
222b528cefcSMark Murray 	ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val);
223b528cefcSMark Murray 	if (ret)
224b528cefcSMark Murray 	    goto fail;
225b528cefcSMark Murray     }
226b528cefcSMark Murray     ALLOC(t->padata, 1);
227b528cefcSMark Murray     if (t->padata == NULL) {
228b528cefcSMark Murray 	ret = ENOMEM;
229ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
230b528cefcSMark Murray 	goto fail;
231b528cefcSMark Murray     }
232c19800e8SDoug Rabson     ALLOC_SEQ(t->padata, 1 + padata->len);
233b528cefcSMark Murray     if (t->padata->val == NULL) {
234b528cefcSMark Murray 	ret = ENOMEM;
235ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
236b528cefcSMark Murray 	goto fail;
237b528cefcSMark Murray     }
238c19800e8SDoug Rabson     {
239ae771770SStanislav Sedov 	size_t i;
240c19800e8SDoug Rabson 	for (i = 0; i < padata->len; i++) {
241c19800e8SDoug Rabson 	    ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]);
242c19800e8SDoug Rabson 	    if (ret) {
243ae771770SStanislav Sedov 		krb5_set_error_message(context, ret,
244ae771770SStanislav Sedov 				       N_("malloc: out of memory", ""));
245c19800e8SDoug Rabson 		goto fail;
246c19800e8SDoug Rabson 	    }
247c19800e8SDoug Rabson 	}
248c19800e8SDoug Rabson     }
249b528cefcSMark Murray 
250b528cefcSMark Murray     ret = krb5_auth_con_init(context, &ac);
251b528cefcSMark Murray     if(ret)
252b528cefcSMark Murray 	goto fail;
2531c43270aSJacques Vidrine 
254ae771770SStanislav Sedov     ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session);
255ae771770SStanislav Sedov     if (ret)
256b528cefcSMark Murray 	goto fail;
257b528cefcSMark Murray 
258c19800e8SDoug Rabson     ret = set_auth_data (context, &t->req_body, &in_creds->authdata,
259ae771770SStanislav Sedov 			 ac->local_subkey);
260ae771770SStanislav Sedov     if (ret)
261b528cefcSMark Murray 	goto fail;
262b528cefcSMark Murray 
263b528cefcSMark Murray     ret = make_pa_tgs_req(context,
264b528cefcSMark Murray 			  ac,
265b528cefcSMark Murray 			  &t->req_body,
266c19800e8SDoug Rabson 			  &t->padata->val[0],
267ae771770SStanislav Sedov 			  krbtgt);
268ae771770SStanislav Sedov     if(ret)
269b528cefcSMark Murray 	goto fail;
270b528cefcSMark Murray 
271ae771770SStanislav Sedov     ret = krb5_auth_con_getlocalsubkey(context, ac, subkey);
272ae771770SStanislav Sedov     if (ret)
273ae771770SStanislav Sedov 	goto fail;
274ae771770SStanislav Sedov 
275b528cefcSMark Murray fail:
276ae771770SStanislav Sedov     if (ac)
277ae771770SStanislav Sedov 	krb5_auth_con_free(context, ac);
2781c43270aSJacques Vidrine     if (ret) {
2791c43270aSJacques Vidrine 	t->req_body.addresses = NULL;
280b528cefcSMark Murray 	free_TGS_REQ (t);
2811c43270aSJacques Vidrine     }
282b528cefcSMark Murray     return ret;
283b528cefcSMark Murray }
284b528cefcSMark Murray 
2851c43270aSJacques Vidrine krb5_error_code
_krb5_get_krbtgt(krb5_context context,krb5_ccache id,krb5_realm realm,krb5_creds ** cred)2861c43270aSJacques Vidrine _krb5_get_krbtgt(krb5_context context,
287b528cefcSMark Murray 		 krb5_ccache  id,
288b528cefcSMark Murray 		 krb5_realm realm,
289b528cefcSMark Murray 		 krb5_creds **cred)
290b528cefcSMark Murray {
291b528cefcSMark Murray     krb5_error_code ret;
292b528cefcSMark Murray     krb5_creds tmp_cred;
293b528cefcSMark Murray 
294b528cefcSMark Murray     memset(&tmp_cred, 0, sizeof(tmp_cred));
295b528cefcSMark Murray 
2961c43270aSJacques Vidrine     ret = krb5_cc_get_principal(context, id, &tmp_cred.client);
2971c43270aSJacques Vidrine     if (ret)
2981c43270aSJacques Vidrine 	return ret;
2991c43270aSJacques Vidrine 
300b528cefcSMark Murray     ret = krb5_make_principal(context,
301b528cefcSMark Murray 			      &tmp_cred.server,
302b528cefcSMark Murray 			      realm,
303b528cefcSMark Murray 			      KRB5_TGS_NAME,
304b528cefcSMark Murray 			      realm,
305b528cefcSMark Murray 			      NULL);
3061c43270aSJacques Vidrine     if(ret) {
3071c43270aSJacques Vidrine 	krb5_free_principal(context, tmp_cred.client);
308b528cefcSMark Murray 	return ret;
3091c43270aSJacques Vidrine     }
310b528cefcSMark Murray     ret = krb5_get_credentials(context,
311b528cefcSMark Murray 			       KRB5_GC_CACHED,
312b528cefcSMark Murray 			       id,
313b528cefcSMark Murray 			       &tmp_cred,
314b528cefcSMark Murray 			       cred);
3151c43270aSJacques Vidrine     krb5_free_principal(context, tmp_cred.client);
316b528cefcSMark Murray     krb5_free_principal(context, tmp_cred.server);
317b528cefcSMark Murray     if(ret)
318b528cefcSMark Murray 	return ret;
319b528cefcSMark Murray     return 0;
320b528cefcSMark Murray }
321b528cefcSMark Murray 
322b528cefcSMark Murray /* DCE compatible decrypt proc */
323ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
decrypt_tkt_with_subkey(krb5_context context,krb5_keyblock * key,krb5_key_usage usage,krb5_const_pointer skey,krb5_kdc_rep * dec_rep)324b528cefcSMark Murray decrypt_tkt_with_subkey (krb5_context context,
325b528cefcSMark Murray 			 krb5_keyblock *key,
326b528cefcSMark Murray 			 krb5_key_usage usage,
327ae771770SStanislav Sedov 			 krb5_const_pointer skey,
328b528cefcSMark Murray 			 krb5_kdc_rep *dec_rep)
329b528cefcSMark Murray {
330ae771770SStanislav Sedov     const krb5_keyblock *subkey = skey;
331ae771770SStanislav Sedov     krb5_error_code ret = 0;
332b528cefcSMark Murray     krb5_data data;
333b528cefcSMark Murray     size_t size;
334b528cefcSMark Murray     krb5_crypto crypto;
335b528cefcSMark Murray 
336ae771770SStanislav Sedov     assert(usage == 0);
337ae771770SStanislav Sedov 
338ae771770SStanislav Sedov     krb5_data_zero(&data);
339ae771770SStanislav Sedov 
340ae771770SStanislav Sedov     /*
341ae771770SStanislav Sedov      * start out with trying with subkey if we have one
342ae771770SStanislav Sedov      */
343ae771770SStanislav Sedov     if (subkey) {
344c19800e8SDoug Rabson 	ret = krb5_crypto_init(context, subkey, 0, &crypto);
3455e9cd1aeSAssar Westerlund 	if (ret)
3465e9cd1aeSAssar Westerlund 	    return ret;
347b528cefcSMark Murray 	ret = krb5_decrypt_EncryptedData (context,
348b528cefcSMark Murray 					  crypto,
349b528cefcSMark Murray 					  KRB5_KU_TGS_REP_ENC_PART_SUB_KEY,
350b528cefcSMark Murray 					  &dec_rep->kdc_rep.enc_part,
351b528cefcSMark Murray 					  &data);
352ae771770SStanislav Sedov 	/*
353ae771770SStanislav Sedov 	 * If the is Windows 2000 DC, we need to retry with key usage
354ae771770SStanislav Sedov 	 * 8 when doing ARCFOUR.
355ae771770SStanislav Sedov 	 */
356ae771770SStanislav Sedov 	if (ret && subkey->keytype == ETYPE_ARCFOUR_HMAC_MD5) {
357ae771770SStanislav Sedov 	    ret = krb5_decrypt_EncryptedData(context,
358ae771770SStanislav Sedov 					     crypto,
359ae771770SStanislav Sedov 					     8,
360ae771770SStanislav Sedov 					     &dec_rep->kdc_rep.enc_part,
361ae771770SStanislav Sedov 					     &data);
362ae771770SStanislav Sedov 	}
363ae771770SStanislav Sedov 	krb5_crypto_destroy(context, crypto);
364ae771770SStanislav Sedov     }
365ae771770SStanislav Sedov     if (subkey == NULL || ret) {
366ae771770SStanislav Sedov 	ret = krb5_crypto_init(context, key, 0, &crypto);
367ae771770SStanislav Sedov 	if (ret)
368ae771770SStanislav Sedov 	    return ret;
369ae771770SStanislav Sedov 	ret = krb5_decrypt_EncryptedData (context,
370ae771770SStanislav Sedov 					  crypto,
371ae771770SStanislav Sedov 					  KRB5_KU_TGS_REP_ENC_PART_SESSION,
372ae771770SStanislav Sedov 					  &dec_rep->kdc_rep.enc_part,
373ae771770SStanislav Sedov 					  &data);
374b528cefcSMark Murray 	krb5_crypto_destroy(context, crypto);
375b528cefcSMark Murray     }
376b528cefcSMark Murray     if (ret)
377b528cefcSMark Murray 	return ret;
378b528cefcSMark Murray 
379ae771770SStanislav Sedov     ret = decode_EncASRepPart(data.data,
380b528cefcSMark Murray 			      data.length,
381b528cefcSMark Murray 			      &dec_rep->enc_part,
382b528cefcSMark Murray 			      &size);
383b528cefcSMark Murray     if (ret)
384ae771770SStanislav Sedov 	ret = decode_EncTGSRepPart(data.data,
385b528cefcSMark Murray 				   data.length,
386b528cefcSMark Murray 				   &dec_rep->enc_part,
387b528cefcSMark Murray 				   &size);
388ae771770SStanislav Sedov     if (ret)
389ae771770SStanislav Sedov       krb5_set_error_message(context, ret,
390ae771770SStanislav Sedov 			     N_("Failed to decode encpart in ticket", ""));
391b528cefcSMark Murray     krb5_data_free (&data);
392b528cefcSMark Murray     return ret;
393b528cefcSMark Murray }
394b528cefcSMark Murray 
395b528cefcSMark Murray static krb5_error_code
get_cred_kdc(krb5_context context,krb5_ccache id,krb5_kdc_flags flags,krb5_addresses * addresses,krb5_creds * in_creds,krb5_creds * krbtgt,krb5_principal impersonate_principal,Ticket * second_ticket,krb5_creds * out_creds)396ae771770SStanislav Sedov get_cred_kdc(krb5_context context,
397b528cefcSMark Murray 	     krb5_ccache id,
398b528cefcSMark Murray 	     krb5_kdc_flags flags,
399b528cefcSMark Murray 	     krb5_addresses *addresses,
400b528cefcSMark Murray 	     krb5_creds *in_creds,
401b528cefcSMark Murray 	     krb5_creds *krbtgt,
402c19800e8SDoug Rabson 	     krb5_principal impersonate_principal,
403c19800e8SDoug Rabson 	     Ticket *second_ticket,
404ae771770SStanislav Sedov 	     krb5_creds *out_creds)
405b528cefcSMark Murray {
406b528cefcSMark Murray     TGS_REQ req;
407b528cefcSMark Murray     krb5_data enc;
408b528cefcSMark Murray     krb5_data resp;
409b528cefcSMark Murray     krb5_kdc_rep rep;
410b528cefcSMark Murray     KRB_ERROR error;
411b528cefcSMark Murray     krb5_error_code ret;
412b528cefcSMark Murray     unsigned nonce;
413b528cefcSMark Murray     krb5_keyblock *subkey = NULL;
414ae771770SStanislav Sedov     size_t len = 0;
415c19800e8SDoug Rabson     Ticket second_ticket_data;
416c19800e8SDoug Rabson     METHOD_DATA padata;
417c19800e8SDoug Rabson 
418c19800e8SDoug Rabson     krb5_data_zero(&resp);
419c19800e8SDoug Rabson     krb5_data_zero(&enc);
420c19800e8SDoug Rabson     padata.val = NULL;
421c19800e8SDoug Rabson     padata.len = 0;
422b528cefcSMark Murray 
423b528cefcSMark Murray     krb5_generate_random_block(&nonce, sizeof(nonce));
424b528cefcSMark Murray     nonce &= 0xffffffff;
425b528cefcSMark Murray 
426c19800e8SDoug Rabson     if(flags.b.enc_tkt_in_skey && second_ticket == NULL){
427b528cefcSMark Murray 	ret = decode_Ticket(in_creds->second_ticket.data,
428b528cefcSMark Murray 			    in_creds->second_ticket.length,
429c19800e8SDoug Rabson 			    &second_ticket_data, &len);
430b528cefcSMark Murray 	if(ret)
431b528cefcSMark Murray 	    return ret;
432c19800e8SDoug Rabson 	second_ticket = &second_ticket_data;
433c19800e8SDoug Rabson     }
434c19800e8SDoug Rabson 
435c19800e8SDoug Rabson 
436c19800e8SDoug Rabson     if (impersonate_principal) {
437c19800e8SDoug Rabson 	krb5_crypto crypto;
438c19800e8SDoug Rabson 	PA_S4U2Self self;
439c19800e8SDoug Rabson 	krb5_data data;
440c19800e8SDoug Rabson 	void *buf;
441ae771770SStanislav Sedov 	size_t size = 0;
442c19800e8SDoug Rabson 
443c19800e8SDoug Rabson 	self.name = impersonate_principal->name;
444c19800e8SDoug Rabson 	self.realm = impersonate_principal->realm;
445c19800e8SDoug Rabson 	self.auth = estrdup("Kerberos");
446c19800e8SDoug Rabson 
447c19800e8SDoug Rabson 	ret = _krb5_s4u2self_to_checksumdata(context, &self, &data);
448c19800e8SDoug Rabson 	if (ret) {
449c19800e8SDoug Rabson 	    free(self.auth);
450c19800e8SDoug Rabson 	    goto out;
451c19800e8SDoug Rabson 	}
452c19800e8SDoug Rabson 
453c19800e8SDoug Rabson 	ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto);
454c19800e8SDoug Rabson 	if (ret) {
455c19800e8SDoug Rabson 	    free(self.auth);
456c19800e8SDoug Rabson 	    krb5_data_free(&data);
457c19800e8SDoug Rabson 	    goto out;
458c19800e8SDoug Rabson 	}
459c19800e8SDoug Rabson 
460c19800e8SDoug Rabson 	ret = krb5_create_checksum(context,
461c19800e8SDoug Rabson 				   crypto,
462c19800e8SDoug Rabson 				   KRB5_KU_OTHER_CKSUM,
463c19800e8SDoug Rabson 				   0,
464c19800e8SDoug Rabson 				   data.data,
465c19800e8SDoug Rabson 				   data.length,
466c19800e8SDoug Rabson 				   &self.cksum);
467c19800e8SDoug Rabson 	krb5_crypto_destroy(context, crypto);
468c19800e8SDoug Rabson 	krb5_data_free(&data);
469c19800e8SDoug Rabson 	if (ret) {
470c19800e8SDoug Rabson 	    free(self.auth);
471c19800e8SDoug Rabson 	    goto out;
472c19800e8SDoug Rabson 	}
473c19800e8SDoug Rabson 
474c19800e8SDoug Rabson 	ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret);
475c19800e8SDoug Rabson 	free(self.auth);
476c19800e8SDoug Rabson 	free_Checksum(&self.cksum);
477c19800e8SDoug Rabson 	if (ret)
478c19800e8SDoug Rabson 	    goto out;
479c19800e8SDoug Rabson 	if (len != size)
480c19800e8SDoug Rabson 	    krb5_abortx(context, "internal asn1 error");
481c19800e8SDoug Rabson 
482ae771770SStanislav Sedov 	ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len);
483c19800e8SDoug Rabson 	if (ret)
484c19800e8SDoug Rabson 	    goto out;
485b528cefcSMark Murray     }
486b528cefcSMark Murray 
487b528cefcSMark Murray     ret = init_tgs_req (context,
488b528cefcSMark Murray 			id,
489b528cefcSMark Murray 			addresses,
490b528cefcSMark Murray 			flags,
491c19800e8SDoug Rabson 			second_ticket,
492b528cefcSMark Murray 			in_creds,
493b528cefcSMark Murray 			krbtgt,
494b528cefcSMark Murray 			nonce,
495c19800e8SDoug Rabson 			&padata,
496b528cefcSMark Murray 			&subkey,
497ae771770SStanislav Sedov 			&req);
498b528cefcSMark Murray     if (ret)
499b528cefcSMark Murray 	goto out;
500b528cefcSMark Murray 
501c19800e8SDoug Rabson     ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret);
5020cadf2f4SJacques Vidrine     if (ret)
503b528cefcSMark Murray 	goto out;
504c19800e8SDoug Rabson     if(enc.length != len)
5050cadf2f4SJacques Vidrine 	krb5_abortx(context, "internal error in ASN.1 encoder");
506b528cefcSMark Murray 
507b528cefcSMark Murray     /* don't free addresses */
508b528cefcSMark Murray     req.req_body.addresses = NULL;
509b528cefcSMark Murray     free_TGS_REQ(&req);
510b528cefcSMark Murray 
511b528cefcSMark Murray     /*
512b528cefcSMark Murray      * Send and receive
513b528cefcSMark Murray      */
514c19800e8SDoug Rabson     {
515c19800e8SDoug Rabson 	krb5_sendto_ctx stctx;
516c19800e8SDoug Rabson 	ret = krb5_sendto_ctx_alloc(context, &stctx);
517c19800e8SDoug Rabson 	if (ret)
518c19800e8SDoug Rabson 	    return ret;
519c19800e8SDoug Rabson 	krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
520b528cefcSMark Murray 
521c19800e8SDoug Rabson 	ret = krb5_sendto_context (context, stctx, &enc,
522c19800e8SDoug Rabson 				   krbtgt->server->name.name_string.val[1],
523c19800e8SDoug Rabson 				   &resp);
524c19800e8SDoug Rabson 	krb5_sendto_ctx_free(context, stctx);
525c19800e8SDoug Rabson     }
526b528cefcSMark Murray     if(ret)
527b528cefcSMark Murray 	goto out;
528b528cefcSMark Murray 
529b528cefcSMark Murray     memset(&rep, 0, sizeof(rep));
530b528cefcSMark Murray     if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) {
531ae771770SStanislav Sedov 	unsigned eflags = 0;
532ae771770SStanislav Sedov 
533b528cefcSMark Murray 	ret = krb5_copy_principal(context,
534b528cefcSMark Murray 				  in_creds->client,
535b528cefcSMark Murray 				  &out_creds->client);
536b528cefcSMark Murray 	if(ret)
537ae771770SStanislav Sedov 	    goto out2;
538b528cefcSMark Murray 	ret = krb5_copy_principal(context,
539b528cefcSMark Murray 				  in_creds->server,
540b528cefcSMark Murray 				  &out_creds->server);
541b528cefcSMark Murray 	if(ret)
542ae771770SStanislav Sedov 	    goto out2;
543b528cefcSMark Murray 	/* this should go someplace else */
544b528cefcSMark Murray 	out_creds->times.endtime = in_creds->times.endtime;
545b528cefcSMark Murray 
546ae771770SStanislav Sedov 	/* XXX should do better testing */
547ae771770SStanislav Sedov 	if (flags.b.constrained_delegation || impersonate_principal)
548ae771770SStanislav Sedov 	    eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
549ae771770SStanislav Sedov 
550b528cefcSMark Murray 	ret = _krb5_extract_ticket(context,
551b528cefcSMark Murray 				   &rep,
552b528cefcSMark Murray 				   out_creds,
553b528cefcSMark Murray 				   &krbtgt->session,
554b528cefcSMark Murray 				   NULL,
555ae771770SStanislav Sedov 				   0,
556b528cefcSMark Murray 				   &krbtgt->addresses,
557b528cefcSMark Murray 				   nonce,
558ae771770SStanislav Sedov 				   eflags,
559b528cefcSMark Murray 				   decrypt_tkt_with_subkey,
560b528cefcSMark Murray 				   subkey);
561ae771770SStanislav Sedov     out2:
562b528cefcSMark Murray 	krb5_free_kdc_rep(context, &rep);
563b528cefcSMark Murray     } else if(krb5_rd_error(context, &resp, &error) == 0) {
564adb0ddaeSAssar Westerlund 	ret = krb5_error_from_rd_error(context, &error, in_creds);
565adb0ddaeSAssar Westerlund 	krb5_free_error_contents(context, &error);
566ae771770SStanislav Sedov     } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) {
567b528cefcSMark Murray 	ret = KRB5KRB_AP_ERR_V4_REPLY;
568ae771770SStanislav Sedov 	krb5_clear_error_message(context);
569adb0ddaeSAssar Westerlund     } else {
570b528cefcSMark Murray 	ret = KRB5KRB_AP_ERR_MSG_TYPE;
571ae771770SStanislav Sedov 	krb5_clear_error_message(context);
572adb0ddaeSAssar Westerlund     }
573c19800e8SDoug Rabson 
574b528cefcSMark Murray out:
575c19800e8SDoug Rabson     if (second_ticket == &second_ticket_data)
576c19800e8SDoug Rabson 	free_Ticket(&second_ticket_data);
577c19800e8SDoug Rabson     free_METHOD_DATA(&padata);
578c19800e8SDoug Rabson     krb5_data_free(&resp);
579c19800e8SDoug Rabson     krb5_data_free(&enc);
580ae771770SStanislav Sedov     if(subkey)
581ae771770SStanislav Sedov 	krb5_free_keyblock(context, subkey);
582b528cefcSMark Murray     return ret;
583b528cefcSMark Murray 
584b528cefcSMark Murray }
585b528cefcSMark Murray 
586ae771770SStanislav Sedov /*
587ae771770SStanislav Sedov  * same as above, just get local addresses first if the krbtgt have
588ae771770SStanislav Sedov  * them and the realm is not addressless
589ae771770SStanislav Sedov  */
590ae771770SStanislav Sedov 
591adb0ddaeSAssar Westerlund static krb5_error_code
get_cred_kdc_address(krb5_context context,krb5_ccache id,krb5_kdc_flags flags,krb5_addresses * addrs,krb5_creds * in_creds,krb5_creds * krbtgt,krb5_principal impersonate_principal,Ticket * second_ticket,krb5_creds * out_creds)592ae771770SStanislav Sedov get_cred_kdc_address(krb5_context context,
593adb0ddaeSAssar Westerlund 		     krb5_ccache id,
594adb0ddaeSAssar Westerlund 		     krb5_kdc_flags flags,
595ae771770SStanislav Sedov 		     krb5_addresses *addrs,
596adb0ddaeSAssar Westerlund 		     krb5_creds *in_creds,
597adb0ddaeSAssar Westerlund 		     krb5_creds *krbtgt,
598c19800e8SDoug Rabson 		     krb5_principal impersonate_principal,
599c19800e8SDoug Rabson 		     Ticket *second_ticket,
600adb0ddaeSAssar Westerlund 		     krb5_creds *out_creds)
601adb0ddaeSAssar Westerlund {
602adb0ddaeSAssar Westerlund     krb5_error_code ret;
603ae771770SStanislav Sedov     krb5_addresses addresses = { 0, NULL };
604adb0ddaeSAssar Westerlund 
605ae771770SStanislav Sedov     /*
606ae771770SStanislav Sedov      * Inherit the address-ness of the krbtgt if the address is not
607ae771770SStanislav Sedov      * specified.
608ae771770SStanislav Sedov      */
609adb0ddaeSAssar Westerlund 
610ae771770SStanislav Sedov     if (addrs == NULL && krbtgt->addresses.len != 0) {
611ae771770SStanislav Sedov 	krb5_boolean noaddr;
612b528cefcSMark Murray 
613ae771770SStanislav Sedov 	krb5_appdefault_boolean(context, NULL, krbtgt->server->realm,
614ae771770SStanislav Sedov 				"no-addresses", FALSE, &noaddr);
615b528cefcSMark Murray 
616ae771770SStanislav Sedov 	if (!noaddr) {
617b528cefcSMark Murray 	    krb5_get_all_client_addrs(context, &addresses);
6184137ff4cSJacques Vidrine 	    /* XXX this sucks. */
619ae771770SStanislav Sedov 	    addrs = &addresses;
6204137ff4cSJacques Vidrine 	    if(addresses.len == 0)
6214137ff4cSJacques Vidrine 		addrs = NULL;
622ae771770SStanislav Sedov 	}
623ae771770SStanislav Sedov     }
624ae771770SStanislav Sedov     ret = get_cred_kdc(context, id, flags, addrs, in_creds,
625ae771770SStanislav Sedov 		       krbtgt, impersonate_principal,
626ae771770SStanislav Sedov 		       second_ticket, out_creds);
627b528cefcSMark Murray     krb5_free_addresses(context, &addresses);
628b528cefcSMark Murray     return ret;
629b528cefcSMark Murray }
630b528cefcSMark Murray 
631ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_kdc_cred(krb5_context context,krb5_ccache id,krb5_kdc_flags flags,krb5_addresses * addresses,Ticket * second_ticket,krb5_creds * in_creds,krb5_creds ** out_creds)632b528cefcSMark Murray krb5_get_kdc_cred(krb5_context context,
633b528cefcSMark Murray 		  krb5_ccache id,
634b528cefcSMark Murray 		  krb5_kdc_flags flags,
635b528cefcSMark Murray 		  krb5_addresses *addresses,
636b528cefcSMark Murray 		  Ticket  *second_ticket,
637b528cefcSMark Murray 		  krb5_creds *in_creds,
638b528cefcSMark Murray 		  krb5_creds **out_creds
639b528cefcSMark Murray 		  )
640b528cefcSMark Murray {
641b528cefcSMark Murray     krb5_error_code ret;
642b528cefcSMark Murray     krb5_creds *krbtgt;
643adb0ddaeSAssar Westerlund 
644b528cefcSMark Murray     *out_creds = calloc(1, sizeof(**out_creds));
645adb0ddaeSAssar Westerlund     if(*out_creds == NULL) {
646ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
647ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
648b528cefcSMark Murray 	return ENOMEM;
649adb0ddaeSAssar Westerlund     }
6501c43270aSJacques Vidrine     ret = _krb5_get_krbtgt (context,
651b528cefcSMark Murray 			    id,
652b528cefcSMark Murray 			    in_creds->server->realm,
653b528cefcSMark Murray 			    &krbtgt);
654b528cefcSMark Murray     if(ret) {
655b528cefcSMark Murray 	free(*out_creds);
656ae771770SStanislav Sedov 	*out_creds = NULL;
657b528cefcSMark Murray 	return ret;
658b528cefcSMark Murray     }
659b528cefcSMark Murray     ret = get_cred_kdc(context, id, flags, addresses,
660c19800e8SDoug Rabson 		       in_creds, krbtgt, NULL, NULL, *out_creds);
661b528cefcSMark Murray     krb5_free_creds (context, krbtgt);
662ae771770SStanislav Sedov     if(ret) {
663b528cefcSMark Murray 	free(*out_creds);
664ae771770SStanislav Sedov 	*out_creds = NULL;
665ae771770SStanislav Sedov     }
666b528cefcSMark Murray     return ret;
667b528cefcSMark Murray }
668b528cefcSMark Murray 
669ae771770SStanislav Sedov static int
not_found(krb5_context context,krb5_const_principal p,krb5_error_code code)670ae771770SStanislav Sedov not_found(krb5_context context, krb5_const_principal p, krb5_error_code code)
671c19800e8SDoug Rabson {
672c19800e8SDoug Rabson     krb5_error_code ret;
673c19800e8SDoug Rabson     char *str;
674c19800e8SDoug Rabson 
675c19800e8SDoug Rabson     ret = krb5_unparse_name(context, p, &str);
676c19800e8SDoug Rabson     if(ret) {
677ae771770SStanislav Sedov 	krb5_clear_error_message(context);
678ae771770SStanislav Sedov 	return code;
679c19800e8SDoug Rabson     }
680ae771770SStanislav Sedov     krb5_set_error_message(context, code,
681ae771770SStanislav Sedov 			   N_("Matching credential (%s) not found", ""), str);
682c19800e8SDoug Rabson     free(str);
683ae771770SStanislav Sedov     return code;
684c19800e8SDoug Rabson }
685b528cefcSMark Murray 
686b528cefcSMark Murray static krb5_error_code
find_cred(krb5_context context,krb5_ccache id,krb5_principal server,krb5_creds ** tgts,krb5_creds * out_creds)687b528cefcSMark Murray find_cred(krb5_context context,
688b528cefcSMark Murray 	  krb5_ccache id,
689b528cefcSMark Murray 	  krb5_principal server,
690b528cefcSMark Murray 	  krb5_creds **tgts,
691b528cefcSMark Murray 	  krb5_creds *out_creds)
692b528cefcSMark Murray {
693b528cefcSMark Murray     krb5_error_code ret;
694b528cefcSMark Murray     krb5_creds mcreds;
695c19800e8SDoug Rabson 
696c19800e8SDoug Rabson     krb5_cc_clear_mcred(&mcreds);
697b528cefcSMark Murray     mcreds.server = server;
698b528cefcSMark Murray     ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM,
699b528cefcSMark Murray 				&mcreds, out_creds);
700b528cefcSMark Murray     if(ret == 0)
701b528cefcSMark Murray 	return 0;
702b528cefcSMark Murray     while(tgts && *tgts){
703b528cefcSMark Murray 	if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM,
704b528cefcSMark Murray 			      &mcreds, *tgts)){
705b528cefcSMark Murray 	    ret = krb5_copy_creds_contents(context, *tgts, out_creds);
706b528cefcSMark Murray 	    return ret;
707b528cefcSMark Murray 	}
708b528cefcSMark Murray 	tgts++;
709b528cefcSMark Murray     }
710ae771770SStanislav Sedov     return not_found(context, server, KRB5_CC_NOTFOUND);
711b528cefcSMark Murray }
712b528cefcSMark Murray 
713b528cefcSMark Murray static krb5_error_code
add_cred(krb5_context context,krb5_creds const * tkt,krb5_creds *** tgts)714ae771770SStanislav Sedov add_cred(krb5_context context, krb5_creds const *tkt, krb5_creds ***tgts)
715b528cefcSMark Murray {
716b528cefcSMark Murray     int i;
717b528cefcSMark Murray     krb5_error_code ret;
718b528cefcSMark Murray     krb5_creds **tmp = *tgts;
719adb0ddaeSAssar Westerlund 
720b528cefcSMark Murray     for(i = 0; tmp && tmp[i]; i++); /* XXX */
721b528cefcSMark Murray     tmp = realloc(tmp, (i+2)*sizeof(*tmp));
722adb0ddaeSAssar Westerlund     if(tmp == NULL) {
723ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
724ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
725b528cefcSMark Murray 	return ENOMEM;
726adb0ddaeSAssar Westerlund     }
727b528cefcSMark Murray     *tgts = tmp;
728b528cefcSMark Murray     ret = krb5_copy_creds(context, tkt, &tmp[i]);
729b528cefcSMark Murray     tmp[i+1] = NULL;
730b528cefcSMark Murray     return ret;
731b528cefcSMark Murray }
732b528cefcSMark Murray 
733b528cefcSMark Murray static krb5_error_code
get_cred_kdc_capath_worker(krb5_context context,krb5_kdc_flags flags,krb5_ccache ccache,krb5_creds * in_creds,krb5_const_realm try_realm,krb5_principal impersonate_principal,Ticket * second_ticket,krb5_creds ** out_creds,krb5_creds *** ret_tgts)734ae771770SStanislav Sedov get_cred_kdc_capath_worker(krb5_context context,
735b528cefcSMark Murray                            krb5_kdc_flags flags,
736b528cefcSMark Murray                            krb5_ccache ccache,
737b528cefcSMark Murray                            krb5_creds *in_creds,
738ae771770SStanislav Sedov                            krb5_const_realm try_realm,
739c19800e8SDoug Rabson                            krb5_principal impersonate_principal,
740c19800e8SDoug Rabson                            Ticket *second_ticket,
741b528cefcSMark Murray                            krb5_creds **out_creds,
742b528cefcSMark Murray                            krb5_creds ***ret_tgts)
743b528cefcSMark Murray {
744b528cefcSMark Murray     krb5_error_code ret;
745b528cefcSMark Murray     krb5_creds *tgt, tmp_creds;
746ae771770SStanislav Sedov     krb5_const_realm client_realm, server_realm;
747ae771770SStanislav Sedov     int ok_as_delegate = 1;
748b528cefcSMark Murray 
749b528cefcSMark Murray     *out_creds = NULL;
750b528cefcSMark Murray 
751c19800e8SDoug Rabson     client_realm = krb5_principal_get_realm(context, in_creds->client);
752c19800e8SDoug Rabson     server_realm = krb5_principal_get_realm(context, in_creds->server);
753b528cefcSMark Murray     memset(&tmp_creds, 0, sizeof(tmp_creds));
754b528cefcSMark Murray     ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client);
755b528cefcSMark Murray     if(ret)
756b528cefcSMark Murray 	return ret;
7575e9cd1aeSAssar Westerlund 
758b528cefcSMark Murray     ret = krb5_make_principal(context,
759b528cefcSMark Murray 			      &tmp_creds.server,
7605e9cd1aeSAssar Westerlund 			      try_realm,
761b528cefcSMark Murray 			      KRB5_TGS_NAME,
762b528cefcSMark Murray 			      server_realm,
763b528cefcSMark Murray 			      NULL);
764b528cefcSMark Murray     if(ret){
765b528cefcSMark Murray 	krb5_free_principal(context, tmp_creds.client);
766b528cefcSMark Murray 	return ret;
767b528cefcSMark Murray     }
768b528cefcSMark Murray     {
769b528cefcSMark Murray 	krb5_creds tgts;
770ae771770SStanislav Sedov 
771b528cefcSMark Murray 	ret = find_cred(context, ccache, tmp_creds.server,
772b528cefcSMark Murray 			*ret_tgts, &tgts);
773b528cefcSMark Murray 	if(ret == 0){
774ae771770SStanislav Sedov 	    /* only allow implicit ok_as_delegate if the realm is the clients realm */
775ae771770SStanislav Sedov 	    if (strcmp(try_realm, client_realm) != 0 || strcmp(try_realm, server_realm) != 0)
776ae771770SStanislav Sedov 		ok_as_delegate = tgts.flags.b.ok_as_delegate;
777ae771770SStanislav Sedov 
778b528cefcSMark Murray 	    *out_creds = calloc(1, sizeof(**out_creds));
779adb0ddaeSAssar Westerlund 	    if(*out_creds == NULL) {
780b528cefcSMark Murray 		ret = ENOMEM;
781ae771770SStanislav Sedov 		krb5_set_error_message(context, ret,
782ae771770SStanislav Sedov 				       N_("malloc: out of memory", ""));
783adb0ddaeSAssar Westerlund 	    } else {
784ae771770SStanislav Sedov 		ret = get_cred_kdc_address(context, ccache, flags, NULL,
785c19800e8SDoug Rabson 					   in_creds, &tgts,
786c19800e8SDoug Rabson 					   impersonate_principal,
787c19800e8SDoug Rabson 					   second_ticket,
788c19800e8SDoug Rabson 					   *out_creds);
7895e9cd1aeSAssar Westerlund 		if (ret) {
790b528cefcSMark Murray 		    free (*out_creds);
7915e9cd1aeSAssar Westerlund 		    *out_creds = NULL;
792ae771770SStanislav Sedov 		} else if (ok_as_delegate == 0)
793ae771770SStanislav Sedov 		    (*out_creds)->flags.b.ok_as_delegate = 0;
794b528cefcSMark Murray 	    }
795c19800e8SDoug Rabson 	    krb5_free_cred_contents(context, &tgts);
796b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.server);
797b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.client);
798b528cefcSMark Murray 	    return ret;
799b528cefcSMark Murray 	}
800b528cefcSMark Murray     }
801ae771770SStanislav Sedov     if(krb5_realm_compare(context, in_creds->client, in_creds->server))
802ae771770SStanislav Sedov 	return not_found(context, in_creds->server, KRB5_CC_NOTFOUND);
803ae771770SStanislav Sedov 
804b528cefcSMark Murray     /* XXX this can loop forever */
805b528cefcSMark Murray     while(1){
806c19800e8SDoug Rabson 	heim_general_string tgt_inst;
8075e9cd1aeSAssar Westerlund 
808ae771770SStanislav Sedov 	ret = get_cred_kdc_capath(context, flags, ccache, &tmp_creds,
809c19800e8SDoug Rabson 				  NULL, NULL, &tgt, ret_tgts);
810b528cefcSMark Murray 	if(ret) {
811b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.server);
812b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.client);
813b528cefcSMark Murray 	    return ret;
814b528cefcSMark Murray 	}
815ae771770SStanislav Sedov 	/*
816ae771770SStanislav Sedov 	 * if either of the chain or the ok_as_delegate was stripped
817ae771770SStanislav Sedov 	 * by the kdc, make sure we strip it too.
818ae771770SStanislav Sedov 	 */
819ae771770SStanislav Sedov 	if (ok_as_delegate == 0 || tgt->flags.b.ok_as_delegate == 0) {
820ae771770SStanislav Sedov 	    ok_as_delegate = 0;
821ae771770SStanislav Sedov 	    tgt->flags.b.ok_as_delegate = 0;
822ae771770SStanislav Sedov 	}
823ae771770SStanislav Sedov 
824ae771770SStanislav Sedov 	ret = add_cred(context, tgt, ret_tgts);
825b528cefcSMark Murray 	if(ret) {
826b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.server);
827b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.client);
828b528cefcSMark Murray 	    return ret;
829b528cefcSMark Murray 	}
830b528cefcSMark Murray 	tgt_inst = tgt->server->name.name_string.val[1];
831b528cefcSMark Murray 	if(strcmp(tgt_inst, server_realm) == 0)
832b528cefcSMark Murray 	    break;
833b528cefcSMark Murray 	krb5_free_principal(context, tmp_creds.server);
834f74fc686SConrad Meyer 	tmp_creds.server = NULL;
835b528cefcSMark Murray 	ret = krb5_make_principal(context, &tmp_creds.server,
836b528cefcSMark Murray 				  tgt_inst, KRB5_TGS_NAME, server_realm, NULL);
837b528cefcSMark Murray 	if(ret) {
838b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.server);
839b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.client);
840b528cefcSMark Murray 	    return ret;
841b528cefcSMark Murray 	}
842b528cefcSMark Murray 	ret = krb5_free_creds(context, tgt);
843b528cefcSMark Murray 	if(ret) {
844b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.server);
845b528cefcSMark Murray 	    krb5_free_principal(context, tmp_creds.client);
846b528cefcSMark Murray 	    return ret;
847b528cefcSMark Murray 	}
848b528cefcSMark Murray     }
849b528cefcSMark Murray 
850b528cefcSMark Murray     krb5_free_principal(context, tmp_creds.server);
851b528cefcSMark Murray     krb5_free_principal(context, tmp_creds.client);
852b528cefcSMark Murray     *out_creds = calloc(1, sizeof(**out_creds));
853adb0ddaeSAssar Westerlund     if(*out_creds == NULL) {
854b528cefcSMark Murray 	ret = ENOMEM;
855ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
856adb0ddaeSAssar Westerlund     } else {
857ae771770SStanislav Sedov 	ret = get_cred_kdc_address (context, ccache, flags, NULL,
858ae771770SStanislav Sedov 				    in_creds, tgt, impersonate_principal,
859ae771770SStanislav Sedov 				    second_ticket, *out_creds);
8605e9cd1aeSAssar Westerlund 	if (ret) {
861b528cefcSMark Murray 	    free (*out_creds);
8625e9cd1aeSAssar Westerlund 	    *out_creds = NULL;
8635e9cd1aeSAssar Westerlund 	}
864b528cefcSMark Murray     }
865b528cefcSMark Murray     krb5_free_creds(context, tgt);
866b528cefcSMark Murray     return ret;
867b528cefcSMark Murray }
868b528cefcSMark Murray 
869ae771770SStanislav Sedov /*
870ae771770SStanislav Sedov get_cred(server)
871ae771770SStanislav Sedov 	creds = cc_get_cred(server)
872ae771770SStanislav Sedov 	if(creds) return creds
873ae771770SStanislav Sedov 	tgt = cc_get_cred(krbtgt/server_realm@any_realm)
874ae771770SStanislav Sedov 	if(tgt)
875ae771770SStanislav Sedov 		return get_cred_tgt(server, tgt)
876ae771770SStanislav Sedov 	if(client_realm == server_realm)
877ae771770SStanislav Sedov 		return NULL
878ae771770SStanislav Sedov 	tgt = get_cred(krbtgt/server_realm@client_realm)
879ae771770SStanislav Sedov 	while(tgt_inst != server_realm)
880ae771770SStanislav Sedov 		tgt = get_cred(krbtgt/server_realm@tgt_inst)
881ae771770SStanislav Sedov 	return get_cred_tgt(server, tgt)
882ae771770SStanislav Sedov 	*/
883adb0ddaeSAssar Westerlund 
884ae771770SStanislav Sedov static krb5_error_code
get_cred_kdc_capath(krb5_context context,krb5_kdc_flags flags,krb5_ccache ccache,krb5_creds * in_creds,krb5_principal impersonate_principal,Ticket * second_ticket,krb5_creds ** out_creds,krb5_creds *** ret_tgts)885ae771770SStanislav Sedov get_cred_kdc_capath(krb5_context context,
886ae771770SStanislav Sedov 		    krb5_kdc_flags flags,
887b528cefcSMark Murray 		    krb5_ccache ccache,
888b528cefcSMark Murray 		    krb5_creds *in_creds,
889ae771770SStanislav Sedov 		    krb5_principal impersonate_principal,
890ae771770SStanislav Sedov 		    Ticket *second_ticket,
891b528cefcSMark Murray 		    krb5_creds **out_creds,
892b528cefcSMark Murray 		    krb5_creds ***ret_tgts)
893b528cefcSMark Murray {
894ae771770SStanislav Sedov     krb5_error_code ret;
895ae771770SStanislav Sedov     krb5_const_realm client_realm, server_realm, try_realm;
896ae771770SStanislav Sedov 
897ae771770SStanislav Sedov     client_realm = krb5_principal_get_realm(context, in_creds->client);
898ae771770SStanislav Sedov     server_realm = krb5_principal_get_realm(context, in_creds->server);
899ae771770SStanislav Sedov 
900ae771770SStanislav Sedov     try_realm = client_realm;
901ae771770SStanislav Sedov     ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds, try_realm,
902ae771770SStanislav Sedov                                      impersonate_principal, second_ticket, out_creds,
903ae771770SStanislav Sedov                                      ret_tgts);
904ae771770SStanislav Sedov 
905ae771770SStanislav Sedov     if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
906ae771770SStanislav Sedov         try_realm = krb5_config_get_string(context, NULL, "capaths",
907ae771770SStanislav Sedov                                            client_realm, server_realm, NULL);
908ae771770SStanislav Sedov 
909ae771770SStanislav Sedov         if (try_realm != NULL && strcmp(try_realm, client_realm)) {
910ae771770SStanislav Sedov             ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds,
911ae771770SStanislav Sedov                                              try_realm, impersonate_principal,
912ae771770SStanislav Sedov                                              second_ticket, out_creds, ret_tgts);
913ae771770SStanislav Sedov         }
914ae771770SStanislav Sedov     }
915ae771770SStanislav Sedov 
916ae771770SStanislav Sedov     return ret;
917ae771770SStanislav Sedov }
918ae771770SStanislav Sedov 
919ae771770SStanislav Sedov static krb5_error_code
get_cred_kdc_referral(krb5_context context,krb5_kdc_flags flags,krb5_ccache ccache,krb5_creds * in_creds,krb5_principal impersonate_principal,Ticket * second_ticket,krb5_creds ** out_creds,krb5_creds *** ret_tgts)920ae771770SStanislav Sedov get_cred_kdc_referral(krb5_context context,
921ae771770SStanislav Sedov 		      krb5_kdc_flags flags,
922ae771770SStanislav Sedov 		      krb5_ccache ccache,
923ae771770SStanislav Sedov 		      krb5_creds *in_creds,
924ae771770SStanislav Sedov 		      krb5_principal impersonate_principal,
925ae771770SStanislav Sedov 		      Ticket *second_ticket,
926ae771770SStanislav Sedov 		      krb5_creds **out_creds,
927ae771770SStanislav Sedov 		      krb5_creds ***ret_tgts)
928ae771770SStanislav Sedov {
929ae771770SStanislav Sedov     krb5_const_realm client_realm;
930ae771770SStanislav Sedov     krb5_error_code ret;
931ae771770SStanislav Sedov     krb5_creds tgt, referral, ticket;
932ae771770SStanislav Sedov     int loop = 0;
933ae771770SStanislav Sedov     int ok_as_delegate = 1;
934ae771770SStanislav Sedov 
935ae771770SStanislav Sedov     if (in_creds->server->name.name_string.len < 2 && !flags.b.canonicalize) {
936ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5KDC_ERR_PATH_NOT_ACCEPTED,
937ae771770SStanislav Sedov 			       N_("Name too short to do referals, skipping", ""));
938ae771770SStanislav Sedov 	return KRB5KDC_ERR_PATH_NOT_ACCEPTED;
939ae771770SStanislav Sedov     }
940ae771770SStanislav Sedov 
941ae771770SStanislav Sedov     memset(&tgt, 0, sizeof(tgt));
942ae771770SStanislav Sedov     memset(&ticket, 0, sizeof(ticket));
943ae771770SStanislav Sedov 
944ae771770SStanislav Sedov     flags.b.canonicalize = 1;
945ae771770SStanislav Sedov 
946ae771770SStanislav Sedov     *out_creds = NULL;
947ae771770SStanislav Sedov 
948ae771770SStanislav Sedov     client_realm = krb5_principal_get_realm(context, in_creds->client);
949ae771770SStanislav Sedov 
950ae771770SStanislav Sedov     /* find tgt for the clients base realm */
951ae771770SStanislav Sedov     {
952ae771770SStanislav Sedov 	krb5_principal tgtname;
953ae771770SStanislav Sedov 
954ae771770SStanislav Sedov 	ret = krb5_make_principal(context, &tgtname,
955ae771770SStanislav Sedov 				  client_realm,
956ae771770SStanislav Sedov 				  KRB5_TGS_NAME,
957ae771770SStanislav Sedov 				  client_realm,
958ae771770SStanislav Sedov 				  NULL);
959ae771770SStanislav Sedov 	if(ret)
960ae771770SStanislav Sedov 	    return ret;
961ae771770SStanislav Sedov 
962ae771770SStanislav Sedov 	ret = find_cred(context, ccache, tgtname, *ret_tgts, &tgt);
963ae771770SStanislav Sedov 	krb5_free_principal(context, tgtname);
964ae771770SStanislav Sedov 	if (ret)
965ae771770SStanislav Sedov 	    return ret;
966ae771770SStanislav Sedov     }
967ae771770SStanislav Sedov 
968ae771770SStanislav Sedov     referral = *in_creds;
969ae771770SStanislav Sedov     ret = krb5_copy_principal(context, in_creds->server, &referral.server);
970ae771770SStanislav Sedov     if (ret) {
971ae771770SStanislav Sedov 	krb5_free_cred_contents(context, &tgt);
972ae771770SStanislav Sedov 	return ret;
973ae771770SStanislav Sedov     }
974ae771770SStanislav Sedov     ret = krb5_principal_set_realm(context, referral.server, client_realm);
975ae771770SStanislav Sedov     if (ret) {
976ae771770SStanislav Sedov 	krb5_free_cred_contents(context, &tgt);
977ae771770SStanislav Sedov 	krb5_free_principal(context, referral.server);
978ae771770SStanislav Sedov 	return ret;
979ae771770SStanislav Sedov     }
980ae771770SStanislav Sedov 
981ae771770SStanislav Sedov     while (loop++ < 17) {
982ae771770SStanislav Sedov 	krb5_creds **tickets;
983ae771770SStanislav Sedov 	krb5_creds mcreds;
984ae771770SStanislav Sedov 	char *referral_realm;
985ae771770SStanislav Sedov 
986ae771770SStanislav Sedov 	/* Use cache if we are not doing impersonation or contrainte deleg */
987ae771770SStanislav Sedov 	if (impersonate_principal == NULL || flags.b.constrained_delegation) {
988ae771770SStanislav Sedov 	    krb5_cc_clear_mcred(&mcreds);
989ae771770SStanislav Sedov 	    mcreds.server = referral.server;
990ae771770SStanislav Sedov 	    ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, &ticket);
991ae771770SStanislav Sedov 	} else
992ae771770SStanislav Sedov 	    ret = EINVAL;
993ae771770SStanislav Sedov 
994ae771770SStanislav Sedov 	if (ret) {
995ae771770SStanislav Sedov 	    ret = get_cred_kdc_address(context, ccache, flags, NULL,
996ae771770SStanislav Sedov 				       &referral, &tgt, impersonate_principal,
997ae771770SStanislav Sedov 				       second_ticket, &ticket);
998ae771770SStanislav Sedov 	    if (ret)
999ae771770SStanislav Sedov 		goto out;
1000ae771770SStanislav Sedov 	}
1001ae771770SStanislav Sedov 
1002ae771770SStanislav Sedov 	/* Did we get the right ticket ? */
1003ae771770SStanislav Sedov 	if (krb5_principal_compare_any_realm(context,
1004ae771770SStanislav Sedov 					     referral.server,
1005ae771770SStanislav Sedov 					     ticket.server))
1006ae771770SStanislav Sedov 	    break;
1007ae771770SStanislav Sedov 
1008ae771770SStanislav Sedov 	if (!krb5_principal_is_krbtgt(context, ticket.server)) {
1009ae771770SStanislav Sedov 	    krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US,
1010ae771770SStanislav Sedov 				   N_("Got back an non krbtgt "
1011ae771770SStanislav Sedov 				      "ticket referrals", ""));
1012ae771770SStanislav Sedov 	    ret = KRB5KRB_AP_ERR_NOT_US;
1013ae771770SStanislav Sedov 	    goto out;
1014ae771770SStanislav Sedov 	}
1015ae771770SStanislav Sedov 
1016ae771770SStanislav Sedov 	referral_realm = ticket.server->name.name_string.val[1];
1017ae771770SStanislav Sedov 
1018ae771770SStanislav Sedov 	/* check that there are no referrals loops */
1019ae771770SStanislav Sedov 	tickets = *ret_tgts;
1020ae771770SStanislav Sedov 
1021ae771770SStanislav Sedov 	krb5_cc_clear_mcred(&mcreds);
1022ae771770SStanislav Sedov 	mcreds.server = ticket.server;
1023ae771770SStanislav Sedov 
1024ae771770SStanislav Sedov 	while(tickets && *tickets){
1025ae771770SStanislav Sedov 	    if(krb5_compare_creds(context,
1026ae771770SStanislav Sedov 				  KRB5_TC_DONT_MATCH_REALM,
1027ae771770SStanislav Sedov 				  &mcreds,
1028ae771770SStanislav Sedov 				  *tickets))
1029ae771770SStanislav Sedov 	    {
1030ae771770SStanislav Sedov 		krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
1031ae771770SStanislav Sedov 				       N_("Referral from %s "
1032ae771770SStanislav Sedov 					  "loops back to realm %s", ""),
1033ae771770SStanislav Sedov 				       tgt.server->realm,
1034ae771770SStanislav Sedov 				       referral_realm);
1035ae771770SStanislav Sedov 		ret = KRB5_GET_IN_TKT_LOOP;
1036ae771770SStanislav Sedov                 goto out;
1037ae771770SStanislav Sedov 	    }
1038ae771770SStanislav Sedov 	    tickets++;
1039ae771770SStanislav Sedov 	}
1040ae771770SStanislav Sedov 
1041ae771770SStanislav Sedov 	/*
1042ae771770SStanislav Sedov 	 * if either of the chain or the ok_as_delegate was stripped
1043ae771770SStanislav Sedov 	 * by the kdc, make sure we strip it too.
1044ae771770SStanislav Sedov 	 */
1045ae771770SStanislav Sedov 
1046ae771770SStanislav Sedov 	if (ok_as_delegate == 0 || ticket.flags.b.ok_as_delegate == 0) {
1047ae771770SStanislav Sedov 	    ok_as_delegate = 0;
1048ae771770SStanislav Sedov 	    ticket.flags.b.ok_as_delegate = 0;
1049ae771770SStanislav Sedov 	}
1050ae771770SStanislav Sedov 
1051ae771770SStanislav Sedov 	ret = add_cred(context, &ticket, ret_tgts);
1052ae771770SStanislav Sedov 	if (ret)
1053ae771770SStanislav Sedov 	    goto out;
1054ae771770SStanislav Sedov 
1055ae771770SStanislav Sedov 	/* try realm in the referral */
1056ae771770SStanislav Sedov 	ret = krb5_principal_set_realm(context,
1057ae771770SStanislav Sedov 				       referral.server,
1058ae771770SStanislav Sedov 				       referral_realm);
1059ae771770SStanislav Sedov 	krb5_free_cred_contents(context, &tgt);
1060ae771770SStanislav Sedov 	tgt = ticket;
1061ae771770SStanislav Sedov 	memset(&ticket, 0, sizeof(ticket));
1062ae771770SStanislav Sedov 	if (ret)
1063ae771770SStanislav Sedov 	    goto out;
1064ae771770SStanislav Sedov     }
1065ae771770SStanislav Sedov 
1066ae771770SStanislav Sedov     ret = krb5_copy_creds(context, &ticket, out_creds);
1067ae771770SStanislav Sedov 
1068ae771770SStanislav Sedov out:
1069ae771770SStanislav Sedov     krb5_free_principal(context, referral.server);
1070ae771770SStanislav Sedov     krb5_free_cred_contents(context, &tgt);
1071ae771770SStanislav Sedov     krb5_free_cred_contents(context, &ticket);
1072ae771770SStanislav Sedov     return ret;
1073b528cefcSMark Murray }
1074b528cefcSMark Murray 
1075b528cefcSMark Murray 
1076ae771770SStanislav Sedov /*
1077ae771770SStanislav Sedov  * Glue function between referrals version and old client chasing
1078ae771770SStanislav Sedov  * codebase.
1079ae771770SStanislav Sedov  */
1080ae771770SStanislav Sedov 
1081ae771770SStanislav Sedov krb5_error_code
_krb5_get_cred_kdc_any(krb5_context context,krb5_kdc_flags flags,krb5_ccache ccache,krb5_creds * in_creds,krb5_principal impersonate_principal,Ticket * second_ticket,krb5_creds ** out_creds,krb5_creds *** ret_tgts)1082ae771770SStanislav Sedov _krb5_get_cred_kdc_any(krb5_context context,
1083ae771770SStanislav Sedov 		       krb5_kdc_flags flags,
1084ae771770SStanislav Sedov 		       krb5_ccache ccache,
1085ae771770SStanislav Sedov 		       krb5_creds *in_creds,
1086ae771770SStanislav Sedov 		       krb5_principal impersonate_principal,
1087ae771770SStanislav Sedov 		       Ticket *second_ticket,
1088ae771770SStanislav Sedov 		       krb5_creds **out_creds,
1089ae771770SStanislav Sedov 		       krb5_creds ***ret_tgts)
1090ae771770SStanislav Sedov {
1091ae771770SStanislav Sedov     krb5_error_code ret;
1092ae771770SStanislav Sedov     krb5_deltat offset;
1093ae771770SStanislav Sedov 
1094ae771770SStanislav Sedov     ret = krb5_cc_get_kdc_offset(context, ccache, &offset);
1095ae771770SStanislav Sedov     if (ret) {
1096ae771770SStanislav Sedov 	context->kdc_sec_offset = offset;
1097ae771770SStanislav Sedov 	context->kdc_usec_offset = 0;
1098ae771770SStanislav Sedov     }
1099ae771770SStanislav Sedov 
1100ae771770SStanislav Sedov     ret = get_cred_kdc_referral(context,
1101ae771770SStanislav Sedov 				flags,
1102ae771770SStanislav Sedov 				ccache,
1103ae771770SStanislav Sedov 				in_creds,
1104ae771770SStanislav Sedov 				impersonate_principal,
1105ae771770SStanislav Sedov 				second_ticket,
1106ae771770SStanislav Sedov 				out_creds,
1107ae771770SStanislav Sedov 				ret_tgts);
1108ae771770SStanislav Sedov     if (ret == 0 || flags.b.canonicalize)
1109ae771770SStanislav Sedov 	return ret;
1110ae771770SStanislav Sedov     return get_cred_kdc_capath(context,
1111ae771770SStanislav Sedov 				flags,
1112ae771770SStanislav Sedov 				ccache,
1113ae771770SStanislav Sedov 				in_creds,
1114ae771770SStanislav Sedov 				impersonate_principal,
1115ae771770SStanislav Sedov 				second_ticket,
1116ae771770SStanislav Sedov 				out_creds,
1117ae771770SStanislav Sedov 				ret_tgts);
1118ae771770SStanislav Sedov }
1119ae771770SStanislav Sedov 
1120ae771770SStanislav Sedov 
1121ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_credentials_with_flags(krb5_context context,krb5_flags options,krb5_kdc_flags flags,krb5_ccache ccache,krb5_creds * in_creds,krb5_creds ** out_creds)1122b528cefcSMark Murray krb5_get_credentials_with_flags(krb5_context context,
1123b528cefcSMark Murray 				krb5_flags options,
1124b528cefcSMark Murray 				krb5_kdc_flags flags,
1125b528cefcSMark Murray 				krb5_ccache ccache,
1126b528cefcSMark Murray 				krb5_creds *in_creds,
1127b528cefcSMark Murray 				krb5_creds **out_creds)
1128b528cefcSMark Murray {
1129b528cefcSMark Murray     krb5_error_code ret;
1130b528cefcSMark Murray     krb5_creds **tgts;
11315e9cd1aeSAssar Westerlund     krb5_creds *res_creds;
1132b528cefcSMark Murray     int i;
1133b528cefcSMark Murray 
1134ae771770SStanislav Sedov     if (in_creds->session.keytype) {
1135ae771770SStanislav Sedov 	ret = krb5_enctype_valid(context, in_creds->session.keytype);
1136ae771770SStanislav Sedov 	if (ret)
1137ae771770SStanislav Sedov 	    return ret;
1138ae771770SStanislav Sedov     }
1139ae771770SStanislav Sedov 
11405e9cd1aeSAssar Westerlund     *out_creds = NULL;
11415e9cd1aeSAssar Westerlund     res_creds = calloc(1, sizeof(*res_creds));
1142adb0ddaeSAssar Westerlund     if (res_creds == NULL) {
1143ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
1144ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
1145b528cefcSMark Murray 	return ENOMEM;
1146adb0ddaeSAssar Westerlund     }
1147b528cefcSMark Murray 
1148c19800e8SDoug Rabson     if (in_creds->session.keytype)
1149c19800e8SDoug Rabson 	options |= KRB5_TC_MATCH_KEYTYPE;
1150c19800e8SDoug Rabson 
1151c19800e8SDoug Rabson     /*
1152c19800e8SDoug Rabson      * If we got a credential, check if credential is expired before
1153c19800e8SDoug Rabson      * returning it.
1154c19800e8SDoug Rabson      */
1155b528cefcSMark Murray     ret = krb5_cc_retrieve_cred(context,
1156b528cefcSMark Murray                                 ccache,
1157b528cefcSMark Murray                                 in_creds->session.keytype ?
1158b528cefcSMark Murray                                 KRB5_TC_MATCH_KEYTYPE : 0,
11595e9cd1aeSAssar Westerlund                                 in_creds, res_creds);
1160c19800e8SDoug Rabson     /*
1161c19800e8SDoug Rabson      * If we got a credential, check if credential is expired before
1162c19800e8SDoug Rabson      * returning it, but only if KRB5_GC_EXPIRED_OK is not set.
1163c19800e8SDoug Rabson      */
11645e9cd1aeSAssar Westerlund     if (ret == 0) {
1165c19800e8SDoug Rabson 	krb5_timestamp timeret;
1166c19800e8SDoug Rabson 
1167c19800e8SDoug Rabson 	/* If expired ok, don't bother checking */
1168c19800e8SDoug Rabson         if(options & KRB5_GC_EXPIRED_OK) {
11695e9cd1aeSAssar Westerlund             *out_creds = res_creds;
1170b528cefcSMark Murray             return 0;
11715e9cd1aeSAssar Westerlund         }
1172c19800e8SDoug Rabson 
1173c19800e8SDoug Rabson 	krb5_timeofday(context, &timeret);
1174c19800e8SDoug Rabson 	if(res_creds->times.endtime > timeret) {
1175c19800e8SDoug Rabson 	    *out_creds = res_creds;
1176c19800e8SDoug Rabson 	    return 0;
1177c19800e8SDoug Rabson 	}
1178c19800e8SDoug Rabson 	if(options & KRB5_GC_CACHED)
1179c19800e8SDoug Rabson 	    krb5_cc_remove_cred(context, ccache, 0, res_creds);
1180c19800e8SDoug Rabson 
1181c19800e8SDoug Rabson     } else if(ret != KRB5_CC_END) {
11825e9cd1aeSAssar Westerlund         free(res_creds);
1183b528cefcSMark Murray         return ret;
1184c19800e8SDoug Rabson     }
1185c19800e8SDoug Rabson     free(res_creds);
1186ae771770SStanislav Sedov     if(options & KRB5_GC_CACHED)
1187ae771770SStanislav Sedov 	return not_found(context, in_creds->server, KRB5_CC_NOTFOUND);
1188ae771770SStanislav Sedov 
1189b528cefcSMark Murray     if(options & KRB5_GC_USER_USER)
1190b528cefcSMark Murray 	flags.b.enc_tkt_in_skey = 1;
1191c19800e8SDoug Rabson     if (flags.b.enc_tkt_in_skey)
1192c19800e8SDoug Rabson 	options |= KRB5_GC_NO_STORE;
1193c19800e8SDoug Rabson 
1194b528cefcSMark Murray     tgts = NULL;
1195ae771770SStanislav Sedov     ret = _krb5_get_cred_kdc_any(context, flags, ccache,
1196c19800e8SDoug Rabson 				 in_creds, NULL, NULL, out_creds, &tgts);
1197b528cefcSMark Murray     for(i = 0; tgts && tgts[i]; i++) {
1198b528cefcSMark Murray 	krb5_cc_store_cred(context, ccache, tgts[i]);
1199b528cefcSMark Murray 	krb5_free_creds(context, tgts[i]);
1200b528cefcSMark Murray     }
1201b528cefcSMark Murray     free(tgts);
1202c19800e8SDoug Rabson     if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0)
1203b528cefcSMark Murray 	krb5_cc_store_cred(context, ccache, *out_creds);
1204b528cefcSMark Murray     return ret;
1205b528cefcSMark Murray }
1206b528cefcSMark Murray 
1207ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_credentials(krb5_context context,krb5_flags options,krb5_ccache ccache,krb5_creds * in_creds,krb5_creds ** out_creds)1208b528cefcSMark Murray krb5_get_credentials(krb5_context context,
1209b528cefcSMark Murray 		     krb5_flags options,
1210b528cefcSMark Murray 		     krb5_ccache ccache,
1211b528cefcSMark Murray 		     krb5_creds *in_creds,
1212b528cefcSMark Murray 		     krb5_creds **out_creds)
1213b528cefcSMark Murray {
1214b528cefcSMark Murray     krb5_kdc_flags flags;
1215b528cefcSMark Murray     flags.i = 0;
1216b528cefcSMark Murray     return krb5_get_credentials_with_flags(context, options, flags,
1217b528cefcSMark Murray 					   ccache, in_creds, out_creds);
1218b528cefcSMark Murray }
1219c19800e8SDoug Rabson 
1220c19800e8SDoug Rabson struct krb5_get_creds_opt_data {
1221c19800e8SDoug Rabson     krb5_principal self;
1222c19800e8SDoug Rabson     krb5_flags options;
1223c19800e8SDoug Rabson     krb5_enctype enctype;
1224c19800e8SDoug Rabson     Ticket *ticket;
1225c19800e8SDoug Rabson };
1226c19800e8SDoug Rabson 
1227c19800e8SDoug Rabson 
1228ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_creds_opt_alloc(krb5_context context,krb5_get_creds_opt * opt)1229c19800e8SDoug Rabson krb5_get_creds_opt_alloc(krb5_context context, krb5_get_creds_opt *opt)
1230c19800e8SDoug Rabson {
1231c19800e8SDoug Rabson     *opt = calloc(1, sizeof(**opt));
1232c19800e8SDoug Rabson     if (*opt == NULL) {
1233ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
1234ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
1235c19800e8SDoug Rabson 	return ENOMEM;
1236c19800e8SDoug Rabson     }
1237c19800e8SDoug Rabson     return 0;
1238c19800e8SDoug Rabson }
1239c19800e8SDoug Rabson 
1240ae771770SStanislav Sedov KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_get_creds_opt_free(krb5_context context,krb5_get_creds_opt opt)1241c19800e8SDoug Rabson krb5_get_creds_opt_free(krb5_context context, krb5_get_creds_opt opt)
1242c19800e8SDoug Rabson {
1243c19800e8SDoug Rabson     if (opt->self)
1244c19800e8SDoug Rabson 	krb5_free_principal(context, opt->self);
1245ae771770SStanislav Sedov     if (opt->ticket) {
1246ae771770SStanislav Sedov 	free_Ticket(opt->ticket);
1247ae771770SStanislav Sedov 	free(opt->ticket);
1248ae771770SStanislav Sedov     }
1249c19800e8SDoug Rabson     memset(opt, 0, sizeof(*opt));
1250c19800e8SDoug Rabson     free(opt);
1251c19800e8SDoug Rabson }
1252c19800e8SDoug Rabson 
1253ae771770SStanislav Sedov KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_get_creds_opt_set_options(krb5_context context,krb5_get_creds_opt opt,krb5_flags options)1254c19800e8SDoug Rabson krb5_get_creds_opt_set_options(krb5_context context,
1255c19800e8SDoug Rabson 			       krb5_get_creds_opt opt,
1256c19800e8SDoug Rabson 			       krb5_flags options)
1257c19800e8SDoug Rabson {
1258c19800e8SDoug Rabson     opt->options = options;
1259c19800e8SDoug Rabson }
1260c19800e8SDoug Rabson 
1261ae771770SStanislav Sedov KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_get_creds_opt_add_options(krb5_context context,krb5_get_creds_opt opt,krb5_flags options)1262c19800e8SDoug Rabson krb5_get_creds_opt_add_options(krb5_context context,
1263c19800e8SDoug Rabson 			       krb5_get_creds_opt opt,
1264c19800e8SDoug Rabson 			       krb5_flags options)
1265c19800e8SDoug Rabson {
1266c19800e8SDoug Rabson     opt->options |= options;
1267c19800e8SDoug Rabson }
1268c19800e8SDoug Rabson 
1269ae771770SStanislav Sedov KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_get_creds_opt_set_enctype(krb5_context context,krb5_get_creds_opt opt,krb5_enctype enctype)1270c19800e8SDoug Rabson krb5_get_creds_opt_set_enctype(krb5_context context,
1271c19800e8SDoug Rabson 			       krb5_get_creds_opt opt,
1272c19800e8SDoug Rabson 			       krb5_enctype enctype)
1273c19800e8SDoug Rabson {
1274c19800e8SDoug Rabson     opt->enctype = enctype;
1275c19800e8SDoug Rabson }
1276c19800e8SDoug Rabson 
1277ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_creds_opt_set_impersonate(krb5_context context,krb5_get_creds_opt opt,krb5_const_principal self)1278c19800e8SDoug Rabson krb5_get_creds_opt_set_impersonate(krb5_context context,
1279c19800e8SDoug Rabson 				   krb5_get_creds_opt opt,
1280c19800e8SDoug Rabson 				   krb5_const_principal self)
1281c19800e8SDoug Rabson {
1282c19800e8SDoug Rabson     if (opt->self)
1283c19800e8SDoug Rabson 	krb5_free_principal(context, opt->self);
1284c19800e8SDoug Rabson     return krb5_copy_principal(context, self, &opt->self);
1285c19800e8SDoug Rabson }
1286c19800e8SDoug Rabson 
1287ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_creds_opt_set_ticket(krb5_context context,krb5_get_creds_opt opt,const Ticket * ticket)1288c19800e8SDoug Rabson krb5_get_creds_opt_set_ticket(krb5_context context,
1289c19800e8SDoug Rabson 			      krb5_get_creds_opt opt,
1290c19800e8SDoug Rabson 			      const Ticket *ticket)
1291c19800e8SDoug Rabson {
1292c19800e8SDoug Rabson     if (opt->ticket) {
1293c19800e8SDoug Rabson 	free_Ticket(opt->ticket);
1294c19800e8SDoug Rabson 	free(opt->ticket);
1295c19800e8SDoug Rabson 	opt->ticket = NULL;
1296c19800e8SDoug Rabson     }
1297c19800e8SDoug Rabson     if (ticket) {
1298c19800e8SDoug Rabson 	krb5_error_code ret;
1299c19800e8SDoug Rabson 
1300c19800e8SDoug Rabson 	opt->ticket = malloc(sizeof(*ticket));
1301c19800e8SDoug Rabson 	if (opt->ticket == NULL) {
1302ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM,
1303ae771770SStanislav Sedov 				   N_("malloc: out of memory", ""));
1304c19800e8SDoug Rabson 	    return ENOMEM;
1305c19800e8SDoug Rabson 	}
1306c19800e8SDoug Rabson 	ret = copy_Ticket(ticket, opt->ticket);
1307c19800e8SDoug Rabson 	if (ret) {
1308c19800e8SDoug Rabson 	    free(opt->ticket);
1309c19800e8SDoug Rabson 	    opt->ticket = NULL;
1310ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
1311ae771770SStanislav Sedov 				   N_("malloc: out of memory", ""));
1312c19800e8SDoug Rabson 	    return ret;
1313c19800e8SDoug Rabson 	}
1314c19800e8SDoug Rabson     }
1315c19800e8SDoug Rabson     return 0;
1316c19800e8SDoug Rabson }
1317c19800e8SDoug Rabson 
1318c19800e8SDoug Rabson 
1319c19800e8SDoug Rabson 
1320ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_creds(krb5_context context,krb5_get_creds_opt opt,krb5_ccache ccache,krb5_const_principal inprinc,krb5_creds ** out_creds)1321c19800e8SDoug Rabson krb5_get_creds(krb5_context context,
1322c19800e8SDoug Rabson 	       krb5_get_creds_opt opt,
1323c19800e8SDoug Rabson 	       krb5_ccache ccache,
1324c19800e8SDoug Rabson 	       krb5_const_principal inprinc,
1325c19800e8SDoug Rabson 	       krb5_creds **out_creds)
1326c19800e8SDoug Rabson {
1327c19800e8SDoug Rabson     krb5_kdc_flags flags;
1328c19800e8SDoug Rabson     krb5_flags options;
1329c19800e8SDoug Rabson     krb5_creds in_creds;
1330c19800e8SDoug Rabson     krb5_error_code ret;
1331c19800e8SDoug Rabson     krb5_creds **tgts;
1332c19800e8SDoug Rabson     krb5_creds *res_creds;
1333c19800e8SDoug Rabson     int i;
1334c19800e8SDoug Rabson 
1335ae771770SStanislav Sedov     if (opt && opt->enctype) {
1336ae771770SStanislav Sedov 	ret = krb5_enctype_valid(context, opt->enctype);
1337ae771770SStanislav Sedov 	if (ret)
1338ae771770SStanislav Sedov 	    return ret;
1339ae771770SStanislav Sedov     }
1340ae771770SStanislav Sedov 
1341c19800e8SDoug Rabson     memset(&in_creds, 0, sizeof(in_creds));
1342c19800e8SDoug Rabson     in_creds.server = rk_UNCONST(inprinc);
1343c19800e8SDoug Rabson 
1344c19800e8SDoug Rabson     ret = krb5_cc_get_principal(context, ccache, &in_creds.client);
1345c19800e8SDoug Rabson     if (ret)
1346c19800e8SDoug Rabson 	return ret;
1347c19800e8SDoug Rabson 
1348ae771770SStanislav Sedov     if (opt)
1349c19800e8SDoug Rabson 	options = opt->options;
1350ae771770SStanislav Sedov     else
1351ae771770SStanislav Sedov 	options = 0;
1352c19800e8SDoug Rabson     flags.i = 0;
1353c19800e8SDoug Rabson 
1354c19800e8SDoug Rabson     *out_creds = NULL;
1355c19800e8SDoug Rabson     res_creds = calloc(1, sizeof(*res_creds));
1356c19800e8SDoug Rabson     if (res_creds == NULL) {
1357c19800e8SDoug Rabson 	krb5_free_principal(context, in_creds.client);
1358ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
1359ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
1360c19800e8SDoug Rabson 	return ENOMEM;
1361c19800e8SDoug Rabson     }
1362c19800e8SDoug Rabson 
1363ae771770SStanislav Sedov     if (opt && opt->enctype) {
1364c19800e8SDoug Rabson 	in_creds.session.keytype = opt->enctype;
1365c19800e8SDoug Rabson 	options |= KRB5_TC_MATCH_KEYTYPE;
1366c19800e8SDoug Rabson     }
1367c19800e8SDoug Rabson 
1368c19800e8SDoug Rabson     /*
1369c19800e8SDoug Rabson      * If we got a credential, check if credential is expired before
1370c19800e8SDoug Rabson      * returning it.
1371c19800e8SDoug Rabson      */
1372c19800e8SDoug Rabson     ret = krb5_cc_retrieve_cred(context,
1373c19800e8SDoug Rabson                                 ccache,
1374ae771770SStanislav Sedov 				options & KRB5_TC_MATCH_KEYTYPE,
1375c19800e8SDoug Rabson                                 &in_creds, res_creds);
1376c19800e8SDoug Rabson     /*
1377c19800e8SDoug Rabson      * If we got a credential, check if credential is expired before
1378c19800e8SDoug Rabson      * returning it, but only if KRB5_GC_EXPIRED_OK is not set.
1379c19800e8SDoug Rabson      */
1380c19800e8SDoug Rabson     if (ret == 0) {
1381c19800e8SDoug Rabson 	krb5_timestamp timeret;
1382c19800e8SDoug Rabson 
1383c19800e8SDoug Rabson 	/* If expired ok, don't bother checking */
1384c19800e8SDoug Rabson         if(options & KRB5_GC_EXPIRED_OK) {
1385c19800e8SDoug Rabson             *out_creds = res_creds;
1386c19800e8SDoug Rabson 	    krb5_free_principal(context, in_creds.client);
1387ae771770SStanislav Sedov             goto out;
1388c19800e8SDoug Rabson         }
1389c19800e8SDoug Rabson 
1390c19800e8SDoug Rabson 	krb5_timeofday(context, &timeret);
1391c19800e8SDoug Rabson 	if(res_creds->times.endtime > timeret) {
1392c19800e8SDoug Rabson 	    *out_creds = res_creds;
1393c19800e8SDoug Rabson 	    krb5_free_principal(context, in_creds.client);
1394ae771770SStanislav Sedov             goto out;
1395c19800e8SDoug Rabson 	}
1396c19800e8SDoug Rabson 	if(options & KRB5_GC_CACHED)
1397c19800e8SDoug Rabson 	    krb5_cc_remove_cred(context, ccache, 0, res_creds);
1398c19800e8SDoug Rabson 
1399c19800e8SDoug Rabson     } else if(ret != KRB5_CC_END) {
1400c19800e8SDoug Rabson         free(res_creds);
1401c19800e8SDoug Rabson 	krb5_free_principal(context, in_creds.client);
1402ae771770SStanislav Sedov 	goto out;
1403c19800e8SDoug Rabson     }
1404c19800e8SDoug Rabson     free(res_creds);
1405c19800e8SDoug Rabson     if(options & KRB5_GC_CACHED) {
1406c19800e8SDoug Rabson 	krb5_free_principal(context, in_creds.client);
1407ae771770SStanislav Sedov 	ret = not_found(context, in_creds.server, KRB5_CC_NOTFOUND);
1408ae771770SStanislav Sedov 	goto out;
1409c19800e8SDoug Rabson     }
1410c19800e8SDoug Rabson     if(options & KRB5_GC_USER_USER) {
1411c19800e8SDoug Rabson 	flags.b.enc_tkt_in_skey = 1;
1412c19800e8SDoug Rabson 	options |= KRB5_GC_NO_STORE;
1413c19800e8SDoug Rabson     }
1414c19800e8SDoug Rabson     if (options & KRB5_GC_FORWARDABLE)
1415c19800e8SDoug Rabson 	flags.b.forwardable = 1;
1416c19800e8SDoug Rabson     if (options & KRB5_GC_NO_TRANSIT_CHECK)
1417c19800e8SDoug Rabson 	flags.b.disable_transited_check = 1;
1418c19800e8SDoug Rabson     if (options & KRB5_GC_CONSTRAINED_DELEGATION) {
1419c19800e8SDoug Rabson 	flags.b.request_anonymous = 1; /* XXX ARGH confusion */
1420c19800e8SDoug Rabson 	flags.b.constrained_delegation = 1;
1421c19800e8SDoug Rabson     }
1422ae771770SStanislav Sedov     if (options & KRB5_GC_CANONICALIZE)
1423ae771770SStanislav Sedov 	flags.b.canonicalize = 1;
1424c19800e8SDoug Rabson 
1425c19800e8SDoug Rabson     tgts = NULL;
1426ae771770SStanislav Sedov     ret = _krb5_get_cred_kdc_any(context, flags, ccache,
1427c19800e8SDoug Rabson 				 &in_creds, opt->self, opt->ticket,
1428c19800e8SDoug Rabson 				 out_creds, &tgts);
1429c19800e8SDoug Rabson     krb5_free_principal(context, in_creds.client);
1430c19800e8SDoug Rabson     for(i = 0; tgts && tgts[i]; i++) {
1431c19800e8SDoug Rabson 	krb5_cc_store_cred(context, ccache, tgts[i]);
1432c19800e8SDoug Rabson 	krb5_free_creds(context, tgts[i]);
1433c19800e8SDoug Rabson     }
1434c19800e8SDoug Rabson     free(tgts);
1435c19800e8SDoug Rabson     if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0)
1436c19800e8SDoug Rabson 	krb5_cc_store_cred(context, ccache, *out_creds);
1437ae771770SStanislav Sedov 
1438ae771770SStanislav Sedov  out:
1439ae771770SStanislav Sedov     _krb5_debug(context, 5, "krb5_get_creds: ret = %d", ret);
1440ae771770SStanislav Sedov 
1441c19800e8SDoug Rabson     return ret;
1442c19800e8SDoug Rabson }
1443c19800e8SDoug Rabson 
1444c19800e8SDoug Rabson /*
1445c19800e8SDoug Rabson  *
1446c19800e8SDoug Rabson  */
1447c19800e8SDoug Rabson 
1448ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_renewed_creds(krb5_context context,krb5_creds * creds,krb5_const_principal client,krb5_ccache ccache,const char * in_tkt_service)1449c19800e8SDoug Rabson krb5_get_renewed_creds(krb5_context context,
1450c19800e8SDoug Rabson 		       krb5_creds *creds,
1451c19800e8SDoug Rabson 		       krb5_const_principal client,
1452c19800e8SDoug Rabson 		       krb5_ccache ccache,
1453c19800e8SDoug Rabson 		       const char *in_tkt_service)
1454c19800e8SDoug Rabson {
1455c19800e8SDoug Rabson     krb5_error_code ret;
1456c19800e8SDoug Rabson     krb5_kdc_flags flags;
1457c19800e8SDoug Rabson     krb5_creds in, *template, *out = NULL;
1458c19800e8SDoug Rabson 
1459c19800e8SDoug Rabson     memset(&in, 0, sizeof(in));
1460c19800e8SDoug Rabson     memset(creds, 0, sizeof(*creds));
1461c19800e8SDoug Rabson 
1462c19800e8SDoug Rabson     ret = krb5_copy_principal(context, client, &in.client);
1463c19800e8SDoug Rabson     if (ret)
1464c19800e8SDoug Rabson 	return ret;
1465c19800e8SDoug Rabson 
1466c19800e8SDoug Rabson     if (in_tkt_service) {
1467c19800e8SDoug Rabson 	ret = krb5_parse_name(context, in_tkt_service, &in.server);
1468c19800e8SDoug Rabson 	if (ret) {
1469c19800e8SDoug Rabson 	    krb5_free_principal(context, in.client);
1470c19800e8SDoug Rabson 	    return ret;
1471c19800e8SDoug Rabson 	}
1472c19800e8SDoug Rabson     } else {
1473c19800e8SDoug Rabson 	const char *realm = krb5_principal_get_realm(context, client);
1474c19800e8SDoug Rabson 
1475c19800e8SDoug Rabson 	ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME,
1476c19800e8SDoug Rabson 				  realm, NULL);
1477c19800e8SDoug Rabson 	if (ret) {
1478c19800e8SDoug Rabson 	    krb5_free_principal(context, in.client);
1479c19800e8SDoug Rabson 	    return ret;
1480c19800e8SDoug Rabson 	}
1481c19800e8SDoug Rabson     }
1482c19800e8SDoug Rabson 
1483c19800e8SDoug Rabson     flags.i = 0;
1484c19800e8SDoug Rabson     flags.b.renewable = flags.b.renew = 1;
1485c19800e8SDoug Rabson 
1486c19800e8SDoug Rabson     /*
1487c19800e8SDoug Rabson      * Get template from old credential cache for the same entry, if
1488c19800e8SDoug Rabson      * this failes, no worries.
1489c19800e8SDoug Rabson      */
1490c19800e8SDoug Rabson     ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &in, &template);
1491c19800e8SDoug Rabson     if (ret == 0) {
1492c19800e8SDoug Rabson 	flags.b.forwardable = template->flags.b.forwardable;
1493c19800e8SDoug Rabson 	flags.b.proxiable = template->flags.b.proxiable;
1494c19800e8SDoug Rabson 	krb5_free_creds (context, template);
1495c19800e8SDoug Rabson     }
1496c19800e8SDoug Rabson 
1497c19800e8SDoug Rabson     ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &in, &out);
1498c19800e8SDoug Rabson     krb5_free_principal(context, in.client);
1499c19800e8SDoug Rabson     krb5_free_principal(context, in.server);
1500c19800e8SDoug Rabson     if (ret)
1501c19800e8SDoug Rabson 	return ret;
1502c19800e8SDoug Rabson 
1503c19800e8SDoug Rabson     ret = krb5_copy_creds_contents(context, out, creds);
1504c19800e8SDoug Rabson     krb5_free_creds(context, out);
1505c19800e8SDoug Rabson 
1506c19800e8SDoug Rabson     return ret;
1507c19800e8SDoug Rabson }
1508