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