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