xref: /freebsd/crypto/heimdal/lib/krb5/acache.c (revision c19800e8cd5640693f36f2040db4ab5e8d738146)
1c19800e8SDoug Rabson /*
2c19800e8SDoug Rabson  * Copyright (c) 2004 - 2007 Kungliga Tekniska H�gskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * All rights reserved.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34c19800e8SDoug Rabson #include "krb5_locl.h"
35c19800e8SDoug Rabson #include <krb5_ccapi.h>
36c19800e8SDoug Rabson #ifdef HAVE_DLFCN_H
37c19800e8SDoug Rabson #include <dlfcn.h>
38c19800e8SDoug Rabson #endif
39c19800e8SDoug Rabson 
40c19800e8SDoug Rabson RCSID("$Id: acache.c 22099 2007-12-03 17:14:34Z lha $");
41c19800e8SDoug Rabson 
42c19800e8SDoug Rabson /* XXX should we fetch these for each open ? */
43c19800e8SDoug Rabson static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER;
44c19800e8SDoug Rabson static cc_initialize_func init_func;
45c19800e8SDoug Rabson 
46c19800e8SDoug Rabson #ifdef HAVE_DLOPEN
47c19800e8SDoug Rabson static void *cc_handle;
48c19800e8SDoug Rabson #endif
49c19800e8SDoug Rabson 
50c19800e8SDoug Rabson typedef struct krb5_acc {
51c19800e8SDoug Rabson     char *cache_name;
52c19800e8SDoug Rabson     cc_context_t context;
53c19800e8SDoug Rabson     cc_ccache_t ccache;
54c19800e8SDoug Rabson } krb5_acc;
55c19800e8SDoug Rabson 
56c19800e8SDoug Rabson static krb5_error_code acc_close(krb5_context, krb5_ccache);
57c19800e8SDoug Rabson 
58c19800e8SDoug Rabson #define ACACHE(X) ((krb5_acc *)(X)->data.data)
59c19800e8SDoug Rabson 
60c19800e8SDoug Rabson static const struct {
61c19800e8SDoug Rabson     cc_int32 error;
62c19800e8SDoug Rabson     krb5_error_code ret;
63c19800e8SDoug Rabson } cc_errors[] = {
64c19800e8SDoug Rabson     { ccErrBadName,		KRB5_CC_BADNAME },
65c19800e8SDoug Rabson     { ccErrCredentialsNotFound,	KRB5_CC_NOTFOUND },
66c19800e8SDoug Rabson     { ccErrCCacheNotFound,	KRB5_FCC_NOFILE },
67c19800e8SDoug Rabson     { ccErrContextNotFound,	KRB5_CC_NOTFOUND },
68c19800e8SDoug Rabson     { ccIteratorEnd,		KRB5_CC_END },
69c19800e8SDoug Rabson     { ccErrNoMem,		KRB5_CC_NOMEM },
70c19800e8SDoug Rabson     { ccErrServerUnavailable,	KRB5_CC_NOSUPP },
71c19800e8SDoug Rabson     { ccNoError,		0 }
72c19800e8SDoug Rabson };
73c19800e8SDoug Rabson 
74c19800e8SDoug Rabson static krb5_error_code
75c19800e8SDoug Rabson translate_cc_error(krb5_context context, cc_int32 error)
76c19800e8SDoug Rabson {
77c19800e8SDoug Rabson     int i;
78c19800e8SDoug Rabson     krb5_clear_error_string(context);
79c19800e8SDoug Rabson     for(i = 0; i < sizeof(cc_errors)/sizeof(cc_errors[0]); i++)
80c19800e8SDoug Rabson 	if (cc_errors[i].error == error)
81c19800e8SDoug Rabson 	    return cc_errors[i].ret;
82c19800e8SDoug Rabson     return KRB5_FCC_INTERNAL;
83c19800e8SDoug Rabson }
84c19800e8SDoug Rabson 
85c19800e8SDoug Rabson static krb5_error_code
86c19800e8SDoug Rabson init_ccapi(krb5_context context)
87c19800e8SDoug Rabson {
88c19800e8SDoug Rabson     const char *lib;
89c19800e8SDoug Rabson 
90c19800e8SDoug Rabson     HEIMDAL_MUTEX_lock(&acc_mutex);
91c19800e8SDoug Rabson     if (init_func) {
92c19800e8SDoug Rabson 	HEIMDAL_MUTEX_unlock(&acc_mutex);
93c19800e8SDoug Rabson 	krb5_clear_error_string(context);
94c19800e8SDoug Rabson 	return 0;
95c19800e8SDoug Rabson     }
96c19800e8SDoug Rabson 
97c19800e8SDoug Rabson     lib = krb5_config_get_string(context, NULL,
98c19800e8SDoug Rabson 				 "libdefaults", "ccapi_library",
99c19800e8SDoug Rabson 				 NULL);
100c19800e8SDoug Rabson     if (lib == NULL) {
101c19800e8SDoug Rabson #ifdef __APPLE__
102c19800e8SDoug Rabson 	lib = "/System/Library/Frameworks/Kerberos.framework/Kerberos";
103c19800e8SDoug Rabson #else
104c19800e8SDoug Rabson 	lib = "/usr/lib/libkrb5_cc.so";
105c19800e8SDoug Rabson #endif
106c19800e8SDoug Rabson     }
107c19800e8SDoug Rabson 
108c19800e8SDoug Rabson #ifdef HAVE_DLOPEN
109c19800e8SDoug Rabson 
110c19800e8SDoug Rabson #ifndef RTLD_LAZY
111c19800e8SDoug Rabson #define RTLD_LAZY 0
112c19800e8SDoug Rabson #endif
113c19800e8SDoug Rabson 
114c19800e8SDoug Rabson     cc_handle = dlopen(lib, RTLD_LAZY);
115c19800e8SDoug Rabson     if (cc_handle == NULL) {
116c19800e8SDoug Rabson 	HEIMDAL_MUTEX_unlock(&acc_mutex);
117c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to load %s", lib);
118c19800e8SDoug Rabson 	return KRB5_CC_NOSUPP;
119c19800e8SDoug Rabson     }
120c19800e8SDoug Rabson 
121c19800e8SDoug Rabson     init_func = (cc_initialize_func)dlsym(cc_handle, "cc_initialize");
122c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&acc_mutex);
123c19800e8SDoug Rabson     if (init_func == NULL) {
124c19800e8SDoug Rabson 	krb5_set_error_string(context, "Failed to find cc_initialize"
125c19800e8SDoug Rabson 			      "in %s: %s", lib, dlerror());
126c19800e8SDoug Rabson 	dlclose(cc_handle);
127c19800e8SDoug Rabson 	return KRB5_CC_NOSUPP;
128c19800e8SDoug Rabson     }
129c19800e8SDoug Rabson 
130c19800e8SDoug Rabson     return 0;
131c19800e8SDoug Rabson #else
132c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&acc_mutex);
133c19800e8SDoug Rabson     krb5_set_error_string(context, "no support for shared object");
134c19800e8SDoug Rabson     return KRB5_CC_NOSUPP;
135c19800e8SDoug Rabson #endif
136c19800e8SDoug Rabson }
137c19800e8SDoug Rabson 
138c19800e8SDoug Rabson static krb5_error_code
139c19800e8SDoug Rabson make_cred_from_ccred(krb5_context context,
140c19800e8SDoug Rabson 		     const cc_credentials_v5_t *incred,
141c19800e8SDoug Rabson 		     krb5_creds *cred)
142c19800e8SDoug Rabson {
143c19800e8SDoug Rabson     krb5_error_code ret;
144c19800e8SDoug Rabson     int i;
145c19800e8SDoug Rabson 
146c19800e8SDoug Rabson     memset(cred, 0, sizeof(*cred));
147c19800e8SDoug Rabson 
148c19800e8SDoug Rabson     ret = krb5_parse_name(context, incred->client, &cred->client);
149c19800e8SDoug Rabson     if (ret)
150c19800e8SDoug Rabson 	goto fail;
151c19800e8SDoug Rabson 
152c19800e8SDoug Rabson     ret = krb5_parse_name(context, incred->server, &cred->server);
153c19800e8SDoug Rabson     if (ret)
154c19800e8SDoug Rabson 	goto fail;
155c19800e8SDoug Rabson 
156c19800e8SDoug Rabson     cred->session.keytype = incred->keyblock.type;
157c19800e8SDoug Rabson     cred->session.keyvalue.length = incred->keyblock.length;
158c19800e8SDoug Rabson     cred->session.keyvalue.data = malloc(incred->keyblock.length);
159c19800e8SDoug Rabson     if (cred->session.keyvalue.data == NULL)
160c19800e8SDoug Rabson 	goto nomem;
161c19800e8SDoug Rabson     memcpy(cred->session.keyvalue.data, incred->keyblock.data,
162c19800e8SDoug Rabson 	   incred->keyblock.length);
163c19800e8SDoug Rabson 
164c19800e8SDoug Rabson     cred->times.authtime = incred->authtime;
165c19800e8SDoug Rabson     cred->times.starttime = incred->starttime;
166c19800e8SDoug Rabson     cred->times.endtime = incred->endtime;
167c19800e8SDoug Rabson     cred->times.renew_till = incred->renew_till;
168c19800e8SDoug Rabson 
169c19800e8SDoug Rabson     ret = krb5_data_copy(&cred->ticket,
170c19800e8SDoug Rabson 			 incred->ticket.data,
171c19800e8SDoug Rabson 			 incred->ticket.length);
172c19800e8SDoug Rabson     if (ret)
173c19800e8SDoug Rabson 	goto nomem;
174c19800e8SDoug Rabson 
175c19800e8SDoug Rabson     ret = krb5_data_copy(&cred->second_ticket,
176c19800e8SDoug Rabson 			 incred->second_ticket.data,
177c19800e8SDoug Rabson 			 incred->second_ticket.length);
178c19800e8SDoug Rabson     if (ret)
179c19800e8SDoug Rabson 	goto nomem;
180c19800e8SDoug Rabson 
181c19800e8SDoug Rabson     cred->authdata.val = NULL;
182c19800e8SDoug Rabson     cred->authdata.len = 0;
183c19800e8SDoug Rabson 
184c19800e8SDoug Rabson     cred->addresses.val = NULL;
185c19800e8SDoug Rabson     cred->addresses.len = 0;
186c19800e8SDoug Rabson 
187c19800e8SDoug Rabson     for (i = 0; incred->authdata && incred->authdata[i]; i++)
188c19800e8SDoug Rabson 	;
189c19800e8SDoug Rabson 
190c19800e8SDoug Rabson     if (i) {
191c19800e8SDoug Rabson 	cred->authdata.val = calloc(i, sizeof(cred->authdata.val[0]));
192c19800e8SDoug Rabson 	if (cred->authdata.val == NULL)
193c19800e8SDoug Rabson 	    goto nomem;
194c19800e8SDoug Rabson 	cred->authdata.len = i;
195c19800e8SDoug Rabson 	for (i = 0; i < cred->authdata.len; i++) {
196c19800e8SDoug Rabson 	    cred->authdata.val[i].ad_type = incred->authdata[i]->type;
197c19800e8SDoug Rabson 	    ret = krb5_data_copy(&cred->authdata.val[i].ad_data,
198c19800e8SDoug Rabson 				 incred->authdata[i]->data,
199c19800e8SDoug Rabson 				 incred->authdata[i]->length);
200c19800e8SDoug Rabson 	    if (ret)
201c19800e8SDoug Rabson 		goto nomem;
202c19800e8SDoug Rabson 	}
203c19800e8SDoug Rabson     }
204c19800e8SDoug Rabson 
205c19800e8SDoug Rabson     for (i = 0; incred->addresses && incred->addresses[i]; i++)
206c19800e8SDoug Rabson 	;
207c19800e8SDoug Rabson 
208c19800e8SDoug Rabson     if (i) {
209c19800e8SDoug Rabson 	cred->addresses.val = calloc(i, sizeof(cred->addresses.val[0]));
210c19800e8SDoug Rabson 	if (cred->addresses.val == NULL)
211c19800e8SDoug Rabson 	    goto nomem;
212c19800e8SDoug Rabson 	cred->addresses.len = i;
213c19800e8SDoug Rabson 
214c19800e8SDoug Rabson 	for (i = 0; i < cred->addresses.len; i++) {
215c19800e8SDoug Rabson 	    cred->addresses.val[i].addr_type = incred->addresses[i]->type;
216c19800e8SDoug Rabson 	    ret = krb5_data_copy(&cred->addresses.val[i].address,
217c19800e8SDoug Rabson 				 incred->addresses[i]->data,
218c19800e8SDoug Rabson 				 incred->addresses[i]->length);
219c19800e8SDoug Rabson 	    if (ret)
220c19800e8SDoug Rabson 		goto nomem;
221c19800e8SDoug Rabson 	}
222c19800e8SDoug Rabson     }
223c19800e8SDoug Rabson 
224c19800e8SDoug Rabson     cred->flags.i = 0;
225c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDABLE)
226c19800e8SDoug Rabson 	cred->flags.b.forwardable = 1;
227c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDED)
228c19800e8SDoug Rabson 	cred->flags.b.forwarded = 1;
229c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXIABLE)
230c19800e8SDoug Rabson 	cred->flags.b.proxiable = 1;
231c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXY)
232c19800e8SDoug Rabson 	cred->flags.b.proxy = 1;
233c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_MAY_POSTDATE)
234c19800e8SDoug Rabson 	cred->flags.b.may_postdate = 1;
235c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_POSTDATED)
236c19800e8SDoug Rabson 	cred->flags.b.postdated = 1;
237c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INVALID)
238c19800e8SDoug Rabson 	cred->flags.b.invalid = 1;
239c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_RENEWABLE)
240c19800e8SDoug Rabson 	cred->flags.b.renewable = 1;
241c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INITIAL)
242c19800e8SDoug Rabson 	cred->flags.b.initial = 1;
243c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PRE_AUTH)
244c19800e8SDoug Rabson 	cred->flags.b.pre_authent = 1;
245c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_HW_AUTH)
246c19800e8SDoug Rabson 	cred->flags.b.hw_authent = 1;
247c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED)
248c19800e8SDoug Rabson 	cred->flags.b.transited_policy_checked = 1;
249c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE)
250c19800e8SDoug Rabson 	cred->flags.b.ok_as_delegate = 1;
251c19800e8SDoug Rabson     if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_ANONYMOUS)
252c19800e8SDoug Rabson 	cred->flags.b.anonymous = 1;
253c19800e8SDoug Rabson 
254c19800e8SDoug Rabson     return 0;
255c19800e8SDoug Rabson 
256c19800e8SDoug Rabson nomem:
257c19800e8SDoug Rabson     ret = ENOMEM;
258c19800e8SDoug Rabson     krb5_set_error_string(context, "malloc - out of memory");
259c19800e8SDoug Rabson 
260c19800e8SDoug Rabson fail:
261c19800e8SDoug Rabson     krb5_free_cred_contents(context, cred);
262c19800e8SDoug Rabson     return ret;
263c19800e8SDoug Rabson }
264c19800e8SDoug Rabson 
265c19800e8SDoug Rabson static void
266c19800e8SDoug Rabson free_ccred(cc_credentials_v5_t *cred)
267c19800e8SDoug Rabson {
268c19800e8SDoug Rabson     int i;
269c19800e8SDoug Rabson 
270c19800e8SDoug Rabson     if (cred->addresses) {
271c19800e8SDoug Rabson 	for (i = 0; cred->addresses[i] != 0; i++) {
272c19800e8SDoug Rabson 	    if (cred->addresses[i]->data)
273c19800e8SDoug Rabson 		free(cred->addresses[i]->data);
274c19800e8SDoug Rabson 	    free(cred->addresses[i]);
275c19800e8SDoug Rabson 	}
276c19800e8SDoug Rabson 	free(cred->addresses);
277c19800e8SDoug Rabson     }
278c19800e8SDoug Rabson     if (cred->server)
279c19800e8SDoug Rabson 	free(cred->server);
280c19800e8SDoug Rabson     if (cred->client)
281c19800e8SDoug Rabson 	free(cred->client);
282c19800e8SDoug Rabson     memset(cred, 0, sizeof(*cred));
283c19800e8SDoug Rabson }
284c19800e8SDoug Rabson 
285c19800e8SDoug Rabson static krb5_error_code
286c19800e8SDoug Rabson make_ccred_from_cred(krb5_context context,
287c19800e8SDoug Rabson 		     const krb5_creds *incred,
288c19800e8SDoug Rabson 		     cc_credentials_v5_t *cred)
289c19800e8SDoug Rabson {
290c19800e8SDoug Rabson     krb5_error_code ret;
291c19800e8SDoug Rabson     int i;
292c19800e8SDoug Rabson 
293c19800e8SDoug Rabson     memset(cred, 0, sizeof(*cred));
294c19800e8SDoug Rabson 
295c19800e8SDoug Rabson     ret = krb5_unparse_name(context, incred->client, &cred->client);
296c19800e8SDoug Rabson     if (ret)
297c19800e8SDoug Rabson 	goto fail;
298c19800e8SDoug Rabson 
299c19800e8SDoug Rabson     ret = krb5_unparse_name(context, incred->server, &cred->server);
300c19800e8SDoug Rabson     if (ret)
301c19800e8SDoug Rabson 	goto fail;
302c19800e8SDoug Rabson 
303c19800e8SDoug Rabson     cred->keyblock.type = incred->session.keytype;
304c19800e8SDoug Rabson     cred->keyblock.length = incred->session.keyvalue.length;
305c19800e8SDoug Rabson     cred->keyblock.data = incred->session.keyvalue.data;
306c19800e8SDoug Rabson 
307c19800e8SDoug Rabson     cred->authtime = incred->times.authtime;
308c19800e8SDoug Rabson     cred->starttime = incred->times.starttime;
309c19800e8SDoug Rabson     cred->endtime = incred->times.endtime;
310c19800e8SDoug Rabson     cred->renew_till = incred->times.renew_till;
311c19800e8SDoug Rabson 
312c19800e8SDoug Rabson     cred->ticket.length = incred->ticket.length;
313c19800e8SDoug Rabson     cred->ticket.data = incred->ticket.data;
314c19800e8SDoug Rabson 
315c19800e8SDoug Rabson     cred->second_ticket.length = incred->second_ticket.length;
316c19800e8SDoug Rabson     cred->second_ticket.data = incred->second_ticket.data;
317c19800e8SDoug Rabson 
318c19800e8SDoug Rabson     /* XXX this one should also be filled in */
319c19800e8SDoug Rabson     cred->authdata = NULL;
320c19800e8SDoug Rabson 
321c19800e8SDoug Rabson     cred->addresses = calloc(incred->addresses.len + 1,
322c19800e8SDoug Rabson 			     sizeof(cred->addresses[0]));
323c19800e8SDoug Rabson     if (cred->addresses == NULL) {
324c19800e8SDoug Rabson 
325c19800e8SDoug Rabson 	ret = ENOMEM;
326c19800e8SDoug Rabson 	goto fail;
327c19800e8SDoug Rabson     }
328c19800e8SDoug Rabson 
329c19800e8SDoug Rabson     for (i = 0; i < incred->addresses.len; i++) {
330c19800e8SDoug Rabson 	cc_data *addr;
331c19800e8SDoug Rabson 	addr = malloc(sizeof(*addr));
332c19800e8SDoug Rabson 	if (addr == NULL) {
333c19800e8SDoug Rabson 	    ret = ENOMEM;
334c19800e8SDoug Rabson 	    goto fail;
335c19800e8SDoug Rabson 	}
336c19800e8SDoug Rabson 	addr->type = incred->addresses.val[i].addr_type;
337c19800e8SDoug Rabson 	addr->length = incred->addresses.val[i].address.length;
338c19800e8SDoug Rabson 	addr->data = malloc(addr->length);
339c19800e8SDoug Rabson 	if (addr->data == NULL) {
340c19800e8SDoug Rabson 	    ret = ENOMEM;
341c19800e8SDoug Rabson 	    goto fail;
342c19800e8SDoug Rabson 	}
343c19800e8SDoug Rabson 	memcpy(addr->data, incred->addresses.val[i].address.data,
344c19800e8SDoug Rabson 	       addr->length);
345c19800e8SDoug Rabson 	cred->addresses[i] = addr;
346c19800e8SDoug Rabson     }
347c19800e8SDoug Rabson     cred->addresses[i] = NULL;
348c19800e8SDoug Rabson 
349c19800e8SDoug Rabson     cred->ticket_flags = 0;
350c19800e8SDoug Rabson     if (incred->flags.b.forwardable)
351c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDABLE;
352c19800e8SDoug Rabson     if (incred->flags.b.forwarded)
353c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDED;
354c19800e8SDoug Rabson     if (incred->flags.b.proxiable)
355c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXIABLE;
356c19800e8SDoug Rabson     if (incred->flags.b.proxy)
357c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXY;
358c19800e8SDoug Rabson     if (incred->flags.b.may_postdate)
359c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE;
360c19800e8SDoug Rabson     if (incred->flags.b.postdated)
361c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_POSTDATED;
362c19800e8SDoug Rabson     if (incred->flags.b.invalid)
363c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INVALID;
364c19800e8SDoug Rabson     if (incred->flags.b.renewable)
365c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_RENEWABLE;
366c19800e8SDoug Rabson     if (incred->flags.b.initial)
367c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INITIAL;
368c19800e8SDoug Rabson     if (incred->flags.b.pre_authent)
369c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PRE_AUTH;
370c19800e8SDoug Rabson     if (incred->flags.b.hw_authent)
371c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_HW_AUTH;
372c19800e8SDoug Rabson     if (incred->flags.b.transited_policy_checked)
373c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED;
374c19800e8SDoug Rabson     if (incred->flags.b.ok_as_delegate)
375c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE;
376c19800e8SDoug Rabson     if (incred->flags.b.anonymous)
377c19800e8SDoug Rabson 	cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_ANONYMOUS;
378c19800e8SDoug Rabson 
379c19800e8SDoug Rabson     return 0;
380c19800e8SDoug Rabson 
381c19800e8SDoug Rabson fail:
382c19800e8SDoug Rabson     free_ccred(cred);
383c19800e8SDoug Rabson 
384c19800e8SDoug Rabson     krb5_clear_error_string(context);
385c19800e8SDoug Rabson     return ret;
386c19800e8SDoug Rabson }
387c19800e8SDoug Rabson 
388c19800e8SDoug Rabson static char *
389c19800e8SDoug Rabson get_cc_name(cc_ccache_t cache)
390c19800e8SDoug Rabson {
391c19800e8SDoug Rabson     cc_string_t name;
392c19800e8SDoug Rabson     cc_int32 error;
393c19800e8SDoug Rabson     char *str;
394c19800e8SDoug Rabson 
395c19800e8SDoug Rabson     error = (*cache->func->get_name)(cache, &name);
396c19800e8SDoug Rabson     if (error)
397c19800e8SDoug Rabson 	return NULL;
398c19800e8SDoug Rabson 
399c19800e8SDoug Rabson     str = strdup(name->data);
400c19800e8SDoug Rabson     (*name->func->release)(name);
401c19800e8SDoug Rabson     return str;
402c19800e8SDoug Rabson }
403c19800e8SDoug Rabson 
404c19800e8SDoug Rabson 
405c19800e8SDoug Rabson static const char*
406c19800e8SDoug Rabson acc_get_name(krb5_context context,
407c19800e8SDoug Rabson 	     krb5_ccache id)
408c19800e8SDoug Rabson {
409c19800e8SDoug Rabson     krb5_acc *a = ACACHE(id);
410c19800e8SDoug Rabson     static char n[255];
411c19800e8SDoug Rabson     char *name;
412c19800e8SDoug Rabson 
413c19800e8SDoug Rabson     name = get_cc_name(a->ccache);
414c19800e8SDoug Rabson     if (name == NULL) {
415c19800e8SDoug Rabson 	krb5_set_error_string(context, "malloc: out of memory");
416c19800e8SDoug Rabson 	return NULL;
417c19800e8SDoug Rabson     }
418c19800e8SDoug Rabson     strlcpy(n, name, sizeof(n));
419c19800e8SDoug Rabson     free(name);
420c19800e8SDoug Rabson     return n;
421c19800e8SDoug Rabson }
422c19800e8SDoug Rabson 
423c19800e8SDoug Rabson static krb5_error_code
424c19800e8SDoug Rabson acc_alloc(krb5_context context, krb5_ccache *id)
425c19800e8SDoug Rabson {
426c19800e8SDoug Rabson     krb5_error_code ret;
427c19800e8SDoug Rabson     cc_int32 error;
428c19800e8SDoug Rabson     krb5_acc *a;
429c19800e8SDoug Rabson 
430c19800e8SDoug Rabson     ret = init_ccapi(context);
431c19800e8SDoug Rabson     if (ret)
432c19800e8SDoug Rabson 	return ret;
433c19800e8SDoug Rabson 
434c19800e8SDoug Rabson     ret = krb5_data_alloc(&(*id)->data, sizeof(*a));
435c19800e8SDoug Rabson     if (ret) {
436c19800e8SDoug Rabson 	krb5_clear_error_string(context);
437c19800e8SDoug Rabson 	return ret;
438c19800e8SDoug Rabson     }
439c19800e8SDoug Rabson 
440c19800e8SDoug Rabson     a = ACACHE(*id);
441c19800e8SDoug Rabson 
442c19800e8SDoug Rabson     error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
443c19800e8SDoug Rabson     if (error) {
444c19800e8SDoug Rabson 	krb5_data_free(&(*id)->data);
445c19800e8SDoug Rabson 	return translate_cc_error(context, error);
446c19800e8SDoug Rabson     }
447c19800e8SDoug Rabson 
448c19800e8SDoug Rabson     a->cache_name = NULL;
449c19800e8SDoug Rabson 
450c19800e8SDoug Rabson     return 0;
451c19800e8SDoug Rabson }
452c19800e8SDoug Rabson 
453c19800e8SDoug Rabson static krb5_error_code
454c19800e8SDoug Rabson acc_resolve(krb5_context context, krb5_ccache *id, const char *res)
455c19800e8SDoug Rabson {
456c19800e8SDoug Rabson     krb5_error_code ret;
457c19800e8SDoug Rabson     cc_int32 error;
458c19800e8SDoug Rabson     krb5_acc *a;
459c19800e8SDoug Rabson 
460c19800e8SDoug Rabson     ret = acc_alloc(context, id);
461c19800e8SDoug Rabson     if (ret)
462c19800e8SDoug Rabson 	return ret;
463c19800e8SDoug Rabson 
464c19800e8SDoug Rabson     a = ACACHE(*id);
465c19800e8SDoug Rabson 
466c19800e8SDoug Rabson     error = (*a->context->func->open_ccache)(a->context, res,
467c19800e8SDoug Rabson 					     &a->ccache);
468c19800e8SDoug Rabson     if (error == 0) {
469c19800e8SDoug Rabson 	a->cache_name = get_cc_name(a->ccache);
470c19800e8SDoug Rabson 	if (a->cache_name == NULL) {
471c19800e8SDoug Rabson 	    acc_close(context, *id);
472c19800e8SDoug Rabson 	    *id = NULL;
473c19800e8SDoug Rabson 	    krb5_set_error_string(context, "malloc: out of memory");
474c19800e8SDoug Rabson 	    return ENOMEM;
475c19800e8SDoug Rabson 	}
476c19800e8SDoug Rabson     } else if (error == ccErrCCacheNotFound) {
477c19800e8SDoug Rabson 	a->ccache = NULL;
478c19800e8SDoug Rabson 	a->cache_name = NULL;
479c19800e8SDoug Rabson 	error = 0;
480c19800e8SDoug Rabson     } else {
481c19800e8SDoug Rabson 	*id = NULL;
482c19800e8SDoug Rabson 	return translate_cc_error(context, error);
483c19800e8SDoug Rabson     }
484c19800e8SDoug Rabson 
485c19800e8SDoug Rabson     return 0;
486c19800e8SDoug Rabson }
487c19800e8SDoug Rabson 
488c19800e8SDoug Rabson static krb5_error_code
489c19800e8SDoug Rabson acc_gen_new(krb5_context context, krb5_ccache *id)
490c19800e8SDoug Rabson {
491c19800e8SDoug Rabson     krb5_error_code ret;
492c19800e8SDoug Rabson     krb5_acc *a;
493c19800e8SDoug Rabson 
494c19800e8SDoug Rabson     ret = acc_alloc(context, id);
495c19800e8SDoug Rabson     if (ret)
496c19800e8SDoug Rabson 	return ret;
497c19800e8SDoug Rabson 
498c19800e8SDoug Rabson     a = ACACHE(*id);
499c19800e8SDoug Rabson 
500c19800e8SDoug Rabson     a->ccache = NULL;
501c19800e8SDoug Rabson     a->cache_name = NULL;
502c19800e8SDoug Rabson 
503c19800e8SDoug Rabson     return 0;
504c19800e8SDoug Rabson }
505c19800e8SDoug Rabson 
506c19800e8SDoug Rabson static krb5_error_code
507c19800e8SDoug Rabson acc_initialize(krb5_context context,
508c19800e8SDoug Rabson 	       krb5_ccache id,
509c19800e8SDoug Rabson 	       krb5_principal primary_principal)
510c19800e8SDoug Rabson {
511c19800e8SDoug Rabson     krb5_acc *a = ACACHE(id);
512c19800e8SDoug Rabson     krb5_error_code ret;
513c19800e8SDoug Rabson     int32_t error;
514c19800e8SDoug Rabson     char *name;
515c19800e8SDoug Rabson 
516c19800e8SDoug Rabson     ret = krb5_unparse_name(context, primary_principal, &name);
517c19800e8SDoug Rabson     if (ret)
518c19800e8SDoug Rabson 	return ret;
519c19800e8SDoug Rabson 
520c19800e8SDoug Rabson     error = (*a->context->func->create_new_ccache)(a->context,
521c19800e8SDoug Rabson 						   cc_credentials_v5,
522c19800e8SDoug Rabson 						   name,
523c19800e8SDoug Rabson 						   &a->ccache);
524c19800e8SDoug Rabson     free(name);
525c19800e8SDoug Rabson 
526c19800e8SDoug Rabson     return translate_cc_error(context, error);
527c19800e8SDoug Rabson }
528c19800e8SDoug Rabson 
529c19800e8SDoug Rabson static krb5_error_code
530c19800e8SDoug Rabson acc_close(krb5_context context,
531c19800e8SDoug Rabson 	  krb5_ccache id)
532c19800e8SDoug Rabson {
533c19800e8SDoug Rabson     krb5_acc *a = ACACHE(id);
534c19800e8SDoug Rabson 
535c19800e8SDoug Rabson     if (a->ccache) {
536c19800e8SDoug Rabson 	(*a->ccache->func->release)(a->ccache);
537c19800e8SDoug Rabson 	a->ccache = NULL;
538c19800e8SDoug Rabson     }
539c19800e8SDoug Rabson     if (a->cache_name) {
540c19800e8SDoug Rabson 	free(a->cache_name);
541c19800e8SDoug Rabson 	a->cache_name = NULL;
542c19800e8SDoug Rabson     }
543c19800e8SDoug Rabson     (*a->context->func->release)(a->context);
544c19800e8SDoug Rabson     a->context = NULL;
545c19800e8SDoug Rabson     krb5_data_free(&id->data);
546c19800e8SDoug Rabson     return 0;
547c19800e8SDoug Rabson }
548c19800e8SDoug Rabson 
549c19800e8SDoug Rabson static krb5_error_code
550c19800e8SDoug Rabson acc_destroy(krb5_context context,
551c19800e8SDoug Rabson 	    krb5_ccache id)
552c19800e8SDoug Rabson {
553c19800e8SDoug Rabson     krb5_acc *a = ACACHE(id);
554c19800e8SDoug Rabson     cc_int32 error = 0;
555c19800e8SDoug Rabson 
556c19800e8SDoug Rabson     if (a->ccache) {
557c19800e8SDoug Rabson 	error = (*a->ccache->func->destroy)(a->ccache);
558c19800e8SDoug Rabson 	a->ccache = NULL;
559c19800e8SDoug Rabson     }
560c19800e8SDoug Rabson     if (a->context) {
561c19800e8SDoug Rabson 	error = (a->context->func->release)(a->context);
562c19800e8SDoug Rabson 	a->context = NULL;
563c19800e8SDoug Rabson     }
564c19800e8SDoug Rabson     return translate_cc_error(context, error);
565c19800e8SDoug Rabson }
566c19800e8SDoug Rabson 
567c19800e8SDoug Rabson static krb5_error_code
568c19800e8SDoug Rabson acc_store_cred(krb5_context context,
569c19800e8SDoug Rabson 	       krb5_ccache id,
570c19800e8SDoug Rabson 	       krb5_creds *creds)
571c19800e8SDoug Rabson {
572c19800e8SDoug Rabson     krb5_acc *a = ACACHE(id);
573c19800e8SDoug Rabson     cc_credentials_union cred;
574c19800e8SDoug Rabson     cc_credentials_v5_t v5cred;
575c19800e8SDoug Rabson     krb5_error_code ret;
576c19800e8SDoug Rabson     cc_int32 error;
577c19800e8SDoug Rabson 
578c19800e8SDoug Rabson     if (a->ccache == NULL) {
579c19800e8SDoug Rabson 	krb5_set_error_string(context, "No API credential found");
580c19800e8SDoug Rabson 	return KRB5_CC_NOTFOUND;
581c19800e8SDoug Rabson     }
582c19800e8SDoug Rabson 
583c19800e8SDoug Rabson     cred.version = cc_credentials_v5;
584c19800e8SDoug Rabson     cred.credentials.credentials_v5 = &v5cred;
585c19800e8SDoug Rabson 
586c19800e8SDoug Rabson     ret = make_ccred_from_cred(context,
587c19800e8SDoug Rabson 			       creds,
588c19800e8SDoug Rabson 			       &v5cred);
589c19800e8SDoug Rabson     if (ret)
590c19800e8SDoug Rabson 	return ret;
591c19800e8SDoug Rabson 
592c19800e8SDoug Rabson     error = (*a->ccache->func->store_credentials)(a->ccache, &cred);
593c19800e8SDoug Rabson     if (error)
594c19800e8SDoug Rabson 	ret = translate_cc_error(context, error);
595c19800e8SDoug Rabson 
596c19800e8SDoug Rabson     free_ccred(&v5cred);
597c19800e8SDoug Rabson 
598c19800e8SDoug Rabson     return ret;
599c19800e8SDoug Rabson }
600c19800e8SDoug Rabson 
601c19800e8SDoug Rabson static krb5_error_code
602c19800e8SDoug Rabson acc_get_principal(krb5_context context,
603c19800e8SDoug Rabson 		  krb5_ccache id,
604c19800e8SDoug Rabson 		  krb5_principal *principal)
605c19800e8SDoug Rabson {
606c19800e8SDoug Rabson     krb5_acc *a = ACACHE(id);
607c19800e8SDoug Rabson     krb5_error_code ret;
608c19800e8SDoug Rabson     int32_t error;
609c19800e8SDoug Rabson     cc_string_t name;
610c19800e8SDoug Rabson 
611c19800e8SDoug Rabson     if (a->ccache == NULL) {
612c19800e8SDoug Rabson 	krb5_set_error_string(context, "No API credential found");
613c19800e8SDoug Rabson 	return KRB5_CC_NOTFOUND;
614c19800e8SDoug Rabson     }
615c19800e8SDoug Rabson 
616c19800e8SDoug Rabson     error = (*a->ccache->func->get_principal)(a->ccache,
617c19800e8SDoug Rabson 					      cc_credentials_v5,
618c19800e8SDoug Rabson 					      &name);
619c19800e8SDoug Rabson     if (error)
620c19800e8SDoug Rabson 	return translate_cc_error(context, error);
621c19800e8SDoug Rabson 
622c19800e8SDoug Rabson     ret = krb5_parse_name(context, name->data, principal);
623c19800e8SDoug Rabson 
624c19800e8SDoug Rabson     (*name->func->release)(name);
625c19800e8SDoug Rabson     return ret;
626c19800e8SDoug Rabson }
627c19800e8SDoug Rabson 
628c19800e8SDoug Rabson static krb5_error_code
629c19800e8SDoug Rabson acc_get_first (krb5_context context,
630c19800e8SDoug Rabson 	       krb5_ccache id,
631c19800e8SDoug Rabson 	       krb5_cc_cursor *cursor)
632c19800e8SDoug Rabson {
633c19800e8SDoug Rabson     cc_credentials_iterator_t iter;
634c19800e8SDoug Rabson     krb5_acc *a = ACACHE(id);
635c19800e8SDoug Rabson     int32_t error;
636c19800e8SDoug Rabson 
637c19800e8SDoug Rabson     if (a->ccache == NULL) {
638c19800e8SDoug Rabson 	krb5_set_error_string(context, "No API credential found");
639c19800e8SDoug Rabson 	return KRB5_CC_NOTFOUND;
640c19800e8SDoug Rabson     }
641c19800e8SDoug Rabson 
642c19800e8SDoug Rabson     error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
643c19800e8SDoug Rabson     if (error) {
644c19800e8SDoug Rabson 	krb5_clear_error_string(context);
645c19800e8SDoug Rabson 	return ENOENT;
646c19800e8SDoug Rabson     }
647c19800e8SDoug Rabson     *cursor = iter;
648c19800e8SDoug Rabson     return 0;
649c19800e8SDoug Rabson }
650c19800e8SDoug Rabson 
651c19800e8SDoug Rabson 
652c19800e8SDoug Rabson static krb5_error_code
653c19800e8SDoug Rabson acc_get_next (krb5_context context,
654c19800e8SDoug Rabson 	      krb5_ccache id,
655c19800e8SDoug Rabson 	      krb5_cc_cursor *cursor,
656c19800e8SDoug Rabson 	      krb5_creds *creds)
657c19800e8SDoug Rabson {
658c19800e8SDoug Rabson     cc_credentials_iterator_t iter = *cursor;
659c19800e8SDoug Rabson     cc_credentials_t cred;
660c19800e8SDoug Rabson     krb5_error_code ret;
661c19800e8SDoug Rabson     int32_t error;
662c19800e8SDoug Rabson 
663c19800e8SDoug Rabson     while (1) {
664c19800e8SDoug Rabson 	error = (*iter->func->next)(iter, &cred);
665c19800e8SDoug Rabson 	if (error)
666c19800e8SDoug Rabson 	    return translate_cc_error(context, error);
667c19800e8SDoug Rabson 	if (cred->data->version == cc_credentials_v5)
668c19800e8SDoug Rabson 	    break;
669c19800e8SDoug Rabson 	(*cred->func->release)(cred);
670c19800e8SDoug Rabson     }
671c19800e8SDoug Rabson 
672c19800e8SDoug Rabson     ret = make_cred_from_ccred(context,
673c19800e8SDoug Rabson 			       cred->data->credentials.credentials_v5,
674c19800e8SDoug Rabson 			       creds);
675c19800e8SDoug Rabson     (*cred->func->release)(cred);
676c19800e8SDoug Rabson     return ret;
677c19800e8SDoug Rabson }
678c19800e8SDoug Rabson 
679c19800e8SDoug Rabson static krb5_error_code
680c19800e8SDoug Rabson acc_end_get (krb5_context context,
681c19800e8SDoug Rabson 	     krb5_ccache id,
682c19800e8SDoug Rabson 	     krb5_cc_cursor *cursor)
683c19800e8SDoug Rabson {
684c19800e8SDoug Rabson     cc_credentials_iterator_t iter = *cursor;
685c19800e8SDoug Rabson     (*iter->func->release)(iter);
686c19800e8SDoug Rabson     return 0;
687c19800e8SDoug Rabson }
688c19800e8SDoug Rabson 
689c19800e8SDoug Rabson static krb5_error_code
690c19800e8SDoug Rabson acc_remove_cred(krb5_context context,
691c19800e8SDoug Rabson 		krb5_ccache id,
692c19800e8SDoug Rabson 		krb5_flags which,
693c19800e8SDoug Rabson 		krb5_creds *cred)
694c19800e8SDoug Rabson {
695c19800e8SDoug Rabson     cc_credentials_iterator_t iter;
696c19800e8SDoug Rabson     krb5_acc *a = ACACHE(id);
697c19800e8SDoug Rabson     cc_credentials_t ccred;
698c19800e8SDoug Rabson     krb5_error_code ret;
699c19800e8SDoug Rabson     cc_int32 error;
700c19800e8SDoug Rabson     char *client, *server;
701c19800e8SDoug Rabson 
702c19800e8SDoug Rabson     if (a->ccache == NULL) {
703c19800e8SDoug Rabson 	krb5_set_error_string(context, "No API credential found");
704c19800e8SDoug Rabson 	return KRB5_CC_NOTFOUND;
705c19800e8SDoug Rabson     }
706c19800e8SDoug Rabson 
707c19800e8SDoug Rabson     if (cred->client) {
708c19800e8SDoug Rabson 	ret = krb5_unparse_name(context, cred->client, &client);
709c19800e8SDoug Rabson 	if (ret)
710c19800e8SDoug Rabson 	    return ret;
711c19800e8SDoug Rabson     } else
712c19800e8SDoug Rabson 	client = NULL;
713c19800e8SDoug Rabson 
714c19800e8SDoug Rabson     ret = krb5_unparse_name(context, cred->server, &server);
715c19800e8SDoug Rabson     if (ret) {
716c19800e8SDoug Rabson 	free(client);
717c19800e8SDoug Rabson 	return ret;
718c19800e8SDoug Rabson     }
719c19800e8SDoug Rabson 
720c19800e8SDoug Rabson     error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
721c19800e8SDoug Rabson     if (error) {
722c19800e8SDoug Rabson 	free(server);
723c19800e8SDoug Rabson 	free(client);
724c19800e8SDoug Rabson 	return translate_cc_error(context, error);
725c19800e8SDoug Rabson     }
726c19800e8SDoug Rabson 
727c19800e8SDoug Rabson     ret = KRB5_CC_NOTFOUND;
728c19800e8SDoug Rabson     while (1) {
729c19800e8SDoug Rabson 	cc_credentials_v5_t *v5cred;
730c19800e8SDoug Rabson 
731c19800e8SDoug Rabson 	error = (*iter->func->next)(iter, &ccred);
732c19800e8SDoug Rabson 	if (error)
733c19800e8SDoug Rabson 	    break;
734c19800e8SDoug Rabson 
735c19800e8SDoug Rabson 	if (ccred->data->version != cc_credentials_v5)
736c19800e8SDoug Rabson 	    goto next;
737c19800e8SDoug Rabson 
738c19800e8SDoug Rabson 	v5cred = ccred->data->credentials.credentials_v5;
739c19800e8SDoug Rabson 
740c19800e8SDoug Rabson 	if (client && strcmp(v5cred->client, client) != 0)
741c19800e8SDoug Rabson 	    goto next;
742c19800e8SDoug Rabson 
743c19800e8SDoug Rabson 	if (strcmp(v5cred->server, server) != 0)
744c19800e8SDoug Rabson 	    goto next;
745c19800e8SDoug Rabson 
746c19800e8SDoug Rabson 	(*a->ccache->func->remove_credentials)(a->ccache, ccred);
747c19800e8SDoug Rabson 	ret = 0;
748c19800e8SDoug Rabson     next:
749c19800e8SDoug Rabson 	(*ccred->func->release)(ccred);
750c19800e8SDoug Rabson     }
751c19800e8SDoug Rabson 
752c19800e8SDoug Rabson     (*iter->func->release)(iter);
753c19800e8SDoug Rabson 
754c19800e8SDoug Rabson     if (ret)
755c19800e8SDoug Rabson 	krb5_set_error_string(context, "Can't find credential %s in cache",
756c19800e8SDoug Rabson 			      server);
757c19800e8SDoug Rabson     free(server);
758c19800e8SDoug Rabson     free(client);
759c19800e8SDoug Rabson 
760c19800e8SDoug Rabson     return ret;
761c19800e8SDoug Rabson }
762c19800e8SDoug Rabson 
763c19800e8SDoug Rabson static krb5_error_code
764c19800e8SDoug Rabson acc_set_flags(krb5_context context,
765c19800e8SDoug Rabson 	      krb5_ccache id,
766c19800e8SDoug Rabson 	      krb5_flags flags)
767c19800e8SDoug Rabson {
768c19800e8SDoug Rabson     return 0;
769c19800e8SDoug Rabson }
770c19800e8SDoug Rabson 
771c19800e8SDoug Rabson static krb5_error_code
772c19800e8SDoug Rabson acc_get_version(krb5_context context,
773c19800e8SDoug Rabson 		krb5_ccache id)
774c19800e8SDoug Rabson {
775c19800e8SDoug Rabson     return 0;
776c19800e8SDoug Rabson }
777c19800e8SDoug Rabson 
778c19800e8SDoug Rabson struct cache_iter {
779c19800e8SDoug Rabson     cc_context_t context;
780c19800e8SDoug Rabson     cc_ccache_iterator_t iter;
781c19800e8SDoug Rabson };
782c19800e8SDoug Rabson 
783c19800e8SDoug Rabson static krb5_error_code
784c19800e8SDoug Rabson acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
785c19800e8SDoug Rabson {
786c19800e8SDoug Rabson     struct cache_iter *iter;
787c19800e8SDoug Rabson     krb5_error_code ret;
788c19800e8SDoug Rabson     cc_int32 error;
789c19800e8SDoug Rabson 
790c19800e8SDoug Rabson     ret = init_ccapi(context);
791c19800e8SDoug Rabson     if (ret)
792c19800e8SDoug Rabson 	return ret;
793c19800e8SDoug Rabson 
794c19800e8SDoug Rabson     iter = calloc(1, sizeof(*iter));
795c19800e8SDoug Rabson     if (iter == NULL) {
796c19800e8SDoug Rabson 	krb5_set_error_string(context, "malloc - out of memory");
797c19800e8SDoug Rabson 	return ENOMEM;
798c19800e8SDoug Rabson     }
799c19800e8SDoug Rabson 
800c19800e8SDoug Rabson     error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL);
801c19800e8SDoug Rabson     if (error) {
802c19800e8SDoug Rabson 	free(iter);
803c19800e8SDoug Rabson 	return translate_cc_error(context, error);
804c19800e8SDoug Rabson     }
805c19800e8SDoug Rabson 
806c19800e8SDoug Rabson     error = (*iter->context->func->new_ccache_iterator)(iter->context,
807c19800e8SDoug Rabson 							&iter->iter);
808c19800e8SDoug Rabson     if (error) {
809c19800e8SDoug Rabson 	free(iter);
810c19800e8SDoug Rabson 	krb5_clear_error_string(context);
811c19800e8SDoug Rabson 	return ENOENT;
812c19800e8SDoug Rabson     }
813c19800e8SDoug Rabson     *cursor = iter;
814c19800e8SDoug Rabson     return 0;
815c19800e8SDoug Rabson }
816c19800e8SDoug Rabson 
817c19800e8SDoug Rabson static krb5_error_code
818c19800e8SDoug Rabson acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
819c19800e8SDoug Rabson {
820c19800e8SDoug Rabson     struct cache_iter *iter = cursor;
821c19800e8SDoug Rabson     cc_ccache_t cache;
822c19800e8SDoug Rabson     krb5_acc *a;
823c19800e8SDoug Rabson     krb5_error_code ret;
824c19800e8SDoug Rabson     int32_t error;
825c19800e8SDoug Rabson 
826c19800e8SDoug Rabson     error = (*iter->iter->func->next)(iter->iter, &cache);
827c19800e8SDoug Rabson     if (error)
828c19800e8SDoug Rabson 	return translate_cc_error(context, error);
829c19800e8SDoug Rabson 
830c19800e8SDoug Rabson     ret = _krb5_cc_allocate(context, &krb5_acc_ops, id);
831c19800e8SDoug Rabson     if (ret) {
832c19800e8SDoug Rabson 	(*cache->func->release)(cache);
833c19800e8SDoug Rabson 	return ret;
834c19800e8SDoug Rabson     }
835c19800e8SDoug Rabson 
836c19800e8SDoug Rabson     ret = acc_alloc(context, id);
837c19800e8SDoug Rabson     if (ret) {
838c19800e8SDoug Rabson 	(*cache->func->release)(cache);
839c19800e8SDoug Rabson 	free(*id);
840c19800e8SDoug Rabson 	return ret;
841c19800e8SDoug Rabson     }
842c19800e8SDoug Rabson 
843c19800e8SDoug Rabson     a = ACACHE(*id);
844c19800e8SDoug Rabson     a->ccache = cache;
845c19800e8SDoug Rabson 
846c19800e8SDoug Rabson     a->cache_name = get_cc_name(a->ccache);
847c19800e8SDoug Rabson     if (a->cache_name == NULL) {
848c19800e8SDoug Rabson 	acc_close(context, *id);
849c19800e8SDoug Rabson 	*id = NULL;
850c19800e8SDoug Rabson 	krb5_set_error_string(context, "malloc: out of memory");
851c19800e8SDoug Rabson 	return ENOMEM;
852c19800e8SDoug Rabson     }
853c19800e8SDoug Rabson     return 0;
854c19800e8SDoug Rabson }
855c19800e8SDoug Rabson 
856c19800e8SDoug Rabson static krb5_error_code
857c19800e8SDoug Rabson acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
858c19800e8SDoug Rabson {
859c19800e8SDoug Rabson     struct cache_iter *iter = cursor;
860c19800e8SDoug Rabson 
861c19800e8SDoug Rabson     (*iter->iter->func->release)(iter->iter);
862c19800e8SDoug Rabson     iter->iter = NULL;
863c19800e8SDoug Rabson     (*iter->context->func->release)(iter->context);
864c19800e8SDoug Rabson     iter->context = NULL;
865c19800e8SDoug Rabson     free(iter);
866c19800e8SDoug Rabson     return 0;
867c19800e8SDoug Rabson }
868c19800e8SDoug Rabson 
869c19800e8SDoug Rabson static krb5_error_code
870c19800e8SDoug Rabson acc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
871c19800e8SDoug Rabson {
872c19800e8SDoug Rabson     krb5_acc *afrom = ACACHE(from);
873c19800e8SDoug Rabson     krb5_acc *ato = ACACHE(to);
874c19800e8SDoug Rabson     int32_t error;
875c19800e8SDoug Rabson 
876c19800e8SDoug Rabson     if (ato->ccache == NULL) {
877c19800e8SDoug Rabson 	cc_string_t name;
878c19800e8SDoug Rabson 
879c19800e8SDoug Rabson 	error = (*afrom->ccache->func->get_principal)(afrom->ccache,
880c19800e8SDoug Rabson 						      cc_credentials_v5,
881c19800e8SDoug Rabson 						      &name);
882c19800e8SDoug Rabson 	if (error)
883c19800e8SDoug Rabson 	    return translate_cc_error(context, error);
884c19800e8SDoug Rabson 
885c19800e8SDoug Rabson 	error = (*ato->context->func->create_new_ccache)(ato->context,
886c19800e8SDoug Rabson 							 cc_credentials_v5,
887c19800e8SDoug Rabson 							 name->data,
888c19800e8SDoug Rabson 							 &ato->ccache);
889c19800e8SDoug Rabson 	(*name->func->release)(name);
890c19800e8SDoug Rabson 	if (error)
891c19800e8SDoug Rabson 	    return translate_cc_error(context, error);
892c19800e8SDoug Rabson     }
893c19800e8SDoug Rabson 
894c19800e8SDoug Rabson 
895c19800e8SDoug Rabson     error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache);
896c19800e8SDoug Rabson     return translate_cc_error(context, error);
897c19800e8SDoug Rabson }
898c19800e8SDoug Rabson 
899c19800e8SDoug Rabson static krb5_error_code
900c19800e8SDoug Rabson acc_default_name(krb5_context context, char **str)
901c19800e8SDoug Rabson {
902c19800e8SDoug Rabson     krb5_error_code ret;
903c19800e8SDoug Rabson     cc_context_t cc;
904c19800e8SDoug Rabson     cc_string_t name;
905c19800e8SDoug Rabson     int32_t error;
906c19800e8SDoug Rabson 
907c19800e8SDoug Rabson     ret = init_ccapi(context);
908c19800e8SDoug Rabson     if (ret)
909c19800e8SDoug Rabson 	return ret;
910c19800e8SDoug Rabson 
911c19800e8SDoug Rabson     error = (*init_func)(&cc, ccapi_version_3, NULL, NULL);
912c19800e8SDoug Rabson     if (error)
913c19800e8SDoug Rabson 	return translate_cc_error(context, error);
914c19800e8SDoug Rabson 
915c19800e8SDoug Rabson     error = (*cc->func->get_default_ccache_name)(cc, &name);
916c19800e8SDoug Rabson     if (error) {
917c19800e8SDoug Rabson 	(*cc->func->release)(cc);
918c19800e8SDoug Rabson 	return translate_cc_error(context, error);
919c19800e8SDoug Rabson     }
920c19800e8SDoug Rabson 
921c19800e8SDoug Rabson     asprintf(str, "API:%s", name->data);
922c19800e8SDoug Rabson     (*name->func->release)(name);
923c19800e8SDoug Rabson     (*cc->func->release)(cc);
924c19800e8SDoug Rabson 
925c19800e8SDoug Rabson     if (*str == NULL) {
926c19800e8SDoug Rabson 	krb5_set_error_string(context, "out of memory");
927c19800e8SDoug Rabson 	return ENOMEM;
928c19800e8SDoug Rabson     }
929c19800e8SDoug Rabson     return 0;
930c19800e8SDoug Rabson }
931c19800e8SDoug Rabson 
932c19800e8SDoug Rabson 
933c19800e8SDoug Rabson /**
934c19800e8SDoug Rabson  * Variable containing the API based credential cache implemention.
935c19800e8SDoug Rabson  *
936c19800e8SDoug Rabson  * @ingroup krb5_ccache
937c19800e8SDoug Rabson  */
938c19800e8SDoug Rabson 
939c19800e8SDoug Rabson const krb5_cc_ops krb5_acc_ops = {
940c19800e8SDoug Rabson     "API",
941c19800e8SDoug Rabson     acc_get_name,
942c19800e8SDoug Rabson     acc_resolve,
943c19800e8SDoug Rabson     acc_gen_new,
944c19800e8SDoug Rabson     acc_initialize,
945c19800e8SDoug Rabson     acc_destroy,
946c19800e8SDoug Rabson     acc_close,
947c19800e8SDoug Rabson     acc_store_cred,
948c19800e8SDoug Rabson     NULL, /* acc_retrieve */
949c19800e8SDoug Rabson     acc_get_principal,
950c19800e8SDoug Rabson     acc_get_first,
951c19800e8SDoug Rabson     acc_get_next,
952c19800e8SDoug Rabson     acc_end_get,
953c19800e8SDoug Rabson     acc_remove_cred,
954c19800e8SDoug Rabson     acc_set_flags,
955c19800e8SDoug Rabson     acc_get_version,
956c19800e8SDoug Rabson     acc_get_cache_first,
957c19800e8SDoug Rabson     acc_get_cache_next,
958c19800e8SDoug Rabson     acc_end_cache_get,
959c19800e8SDoug Rabson     acc_move,
960c19800e8SDoug Rabson     acc_default_name
961c19800e8SDoug Rabson };
962