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