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