1 /* $NetBSD: cache.c,v 1.2 2014/07/24 22:54:10 joerg Exp $ */
4 * Copyright (c) 2005, PADL Software Pty Ltd.
7 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of PADL Software nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 HEIMDAL_MUTEX ccache_mutex
= HEIMDAL_MUTEX_INITIALIZER
;
40 kcm_ccache_data
*ccache_head
= NULL
;
41 static unsigned int ccache_nextid
= 0;
43 char *kcm_ccache_nextid(pid_t pid
, uid_t uid
, gid_t gid
)
48 HEIMDAL_MUTEX_lock(&ccache_mutex
);
50 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
52 asprintf(&name
, "%ld:%u", (long)uid
, n
);
58 kcm_ccache_resolve(krb5_context context
,
67 ret
= KRB5_FCC_NOFILE
;
69 HEIMDAL_MUTEX_lock(&ccache_mutex
);
71 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
72 if ((p
->flags
& KCM_FLAGS_VALID
) == 0)
74 if (strcmp(p
->name
, name
) == 0) {
81 kcm_retain_ccache(context
, p
);
85 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
91 kcm_ccache_resolve_by_uuid(krb5_context context
,
100 ret
= KRB5_FCC_NOFILE
;
102 HEIMDAL_MUTEX_lock(&ccache_mutex
);
104 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
105 if ((p
->flags
& KCM_FLAGS_VALID
) == 0)
107 if (memcmp(p
->uuid
, uuid
, sizeof(*uuid
)) == 0) {
114 kcm_retain_ccache(context
, p
);
118 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
124 kcm_ccache_get_uuids(krb5_context context
, kcm_client
*client
, kcm_operation opcode
, krb5_storage
*sp
)
129 ret
= KRB5_FCC_NOFILE
;
131 HEIMDAL_MUTEX_lock(&ccache_mutex
);
133 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
134 if ((p
->flags
& KCM_FLAGS_VALID
) == 0)
136 ret
= kcm_access(context
, client
, opcode
, p
);
141 krb5_storage_write(sp
, p
->uuid
, sizeof(p
->uuid
));
144 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
150 krb5_error_code
kcm_debug_ccache(krb5_context context
)
154 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
155 char *cpn
= NULL
, *spn
= NULL
;
159 if ((p
->flags
& KCM_FLAGS_VALID
) == 0) {
160 kcm_log(7, "cache %08x: empty slot");
166 for (k
= p
->creds
; k
!= NULL
; k
= k
->next
)
169 if (p
->client
!= NULL
)
170 krb5_unparse_name(context
, p
->client
, &cpn
);
171 if (p
->server
!= NULL
)
172 krb5_unparse_name(context
, p
->server
, &spn
);
174 kcm_log(7, "cache %08x: name %s refcnt %d flags %04x mode %04o "
175 "uid %d gid %d client %s server %s ncreds %d",
176 p
, p
->name
, p
->refcnt
, p
->flags
, p
->mode
, p
->uid
, p
->gid
,
177 (cpn
== NULL
) ? "<none>" : cpn
,
178 (spn
== NULL
) ? "<none>" : spn
,
191 kcm_free_ccache_data_internal(krb5_context context
,
192 kcm_ccache_data
*cache
)
194 KCM_ASSERT_VALID(cache
);
196 if (cache
->name
!= NULL
) {
201 if (cache
->flags
& KCM_FLAGS_USE_KEYTAB
) {
202 krb5_kt_close(context
, cache
->key
.keytab
);
203 cache
->key
.keytab
= NULL
;
204 } else if (cache
->flags
& KCM_FLAGS_USE_CACHED_KEY
) {
205 krb5_free_keyblock_contents(context
, &cache
->key
.keyblock
);
206 krb5_keyblock_zero(&cache
->key
.keyblock
);
215 kcm_zero_ccache_data_internal(context
, cache
);
218 cache
->renew_life
= 0;
223 HEIMDAL_MUTEX_unlock(&cache
->mutex
);
224 HEIMDAL_MUTEX_destroy(&cache
->mutex
);
229 kcm_ccache_destroy(krb5_context context
, const char *name
)
231 kcm_ccache
*p
, ccache
;
234 ret
= KRB5_FCC_NOFILE
;
236 HEIMDAL_MUTEX_lock(&ccache_mutex
);
237 for (p
= &ccache_head
; *p
!= NULL
; p
= &(*p
)->next
) {
238 if (((*p
)->flags
& KCM_FLAGS_VALID
) == 0)
240 if (strcmp((*p
)->name
, name
) == 0) {
248 if ((*p
)->refcnt
!= 1) {
255 kcm_free_ccache_data_internal(context
, ccache
);
259 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
264 static krb5_error_code
265 kcm_ccache_alloc(krb5_context context
,
269 kcm_ccache slot
= NULL
, p
;
275 /* First, check for duplicates */
276 HEIMDAL_MUTEX_lock(&ccache_mutex
);
278 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
279 if (p
->flags
& KCM_FLAGS_VALID
) {
280 if (strcmp(p
->name
, name
) == 0) {
284 } else if (slot
== NULL
)
292 * Create an enpty slot for us.
295 slot
= (kcm_ccache_data
*)malloc(sizeof(*slot
));
300 slot
->next
= ccache_head
;
301 HEIMDAL_MUTEX_init(&slot
->mutex
);
305 RAND_bytes(slot
->uuid
, sizeof(slot
->uuid
));
307 slot
->name
= strdup(name
);
308 if (slot
->name
== NULL
) {
314 slot
->flags
= KCM_FLAGS_VALID
;
315 slot
->mode
= S_IRUSR
| S_IWUSR
;
321 slot
->key
.keytab
= NULL
;
323 slot
->renew_life
= 0;
330 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
334 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
335 if (new_slot
&& slot
!= NULL
) {
336 HEIMDAL_MUTEX_destroy(&slot
->mutex
);
343 kcm_ccache_remove_creds_internal(krb5_context context
,
350 struct kcm_creds
*old
;
352 krb5_free_cred_contents(context
, &k
->cred
);
357 ccache
->creds
= NULL
;
363 kcm_ccache_remove_creds(krb5_context context
,
368 KCM_ASSERT_VALID(ccache
);
370 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
371 ret
= kcm_ccache_remove_creds_internal(context
, ccache
);
372 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
378 kcm_zero_ccache_data_internal(krb5_context context
,
379 kcm_ccache_data
*cache
)
381 if (cache
->client
!= NULL
) {
382 krb5_free_principal(context
, cache
->client
);
383 cache
->client
= NULL
;
386 if (cache
->server
!= NULL
) {
387 krb5_free_principal(context
, cache
->server
);
388 cache
->server
= NULL
;
391 kcm_ccache_remove_creds_internal(context
, cache
);
397 kcm_zero_ccache_data(krb5_context context
,
402 KCM_ASSERT_VALID(cache
);
404 HEIMDAL_MUTEX_lock(&cache
->mutex
);
405 ret
= kcm_zero_ccache_data_internal(context
, cache
);
406 HEIMDAL_MUTEX_unlock(&cache
->mutex
);
412 kcm_retain_ccache(krb5_context context
,
415 KCM_ASSERT_VALID(ccache
);
417 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
419 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
425 kcm_release_ccache(krb5_context context
, kcm_ccache c
)
427 krb5_error_code ret
= 0;
431 HEIMDAL_MUTEX_lock(&c
->mutex
);
432 if (c
->refcnt
== 1) {
433 kcm_free_ccache_data_internal(context
, c
);
437 HEIMDAL_MUTEX_unlock(&c
->mutex
);
444 kcm_ccache_gen_new(krb5_context context
,
453 name
= kcm_ccache_nextid(pid
, uid
, gid
);
455 return KRB5_CC_NOMEM
;
458 ret
= kcm_ccache_new(context
, name
, ccache
);
465 kcm_ccache_new(krb5_context context
,
471 ret
= kcm_ccache_alloc(context
, name
, ccache
);
474 * one reference is held by the linked list,
477 kcm_retain_ccache(context
, *ccache
);
484 kcm_ccache_destroy_if_empty(krb5_context context
,
489 KCM_ASSERT_VALID(ccache
);
491 if (ccache
->creds
== NULL
) {
492 ret
= kcm_ccache_destroy(context
, ccache
->name
);
500 kcm_ccache_store_cred(krb5_context context
,
508 KCM_ASSERT_VALID(ccache
);
510 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
511 ret
= kcm_ccache_store_cred_internal(context
, ccache
, creds
, copy
, &tmp
);
512 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
518 kcm_ccache_find_cred_uuid(krb5_context context
,
524 for (c
= ccache
->creds
; c
!= NULL
; c
= c
->next
)
525 if (memcmp(c
->uuid
, uuid
, sizeof(c
->uuid
)) == 0)
534 kcm_ccache_store_cred_internal(krb5_context context
,
540 struct kcm_creds
**c
;
543 for (c
= &ccache
->creds
; *c
!= NULL
; c
= &(*c
)->next
)
546 *c
= (struct kcm_creds
*)calloc(1, sizeof(**c
));
548 return KRB5_CC_NOMEM
;
550 RAND_bytes((*c
)->uuid
, sizeof((*c
)->uuid
));
552 *credp
= &(*c
)->cred
;
555 ret
= krb5_copy_creds_contents(context
, creds
, *credp
);
569 kcm_ccache_remove_cred_internal(krb5_context context
,
571 krb5_flags whichfields
,
572 const krb5_creds
*mcreds
)
575 struct kcm_creds
**c
;
577 ret
= KRB5_CC_NOTFOUND
;
579 for (c
= &ccache
->creds
; *c
!= NULL
; c
= &(*c
)->next
) {
580 if (krb5_compare_creds(context
, whichfields
, mcreds
, &(*c
)->cred
)) {
581 struct kcm_creds
*cred
= *c
;
584 krb5_free_cred_contents(context
, &cred
->cred
);
596 kcm_ccache_remove_cred(krb5_context context
,
598 krb5_flags whichfields
,
599 const krb5_creds
*mcreds
)
603 KCM_ASSERT_VALID(ccache
);
605 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
606 ret
= kcm_ccache_remove_cred_internal(context
, ccache
, whichfields
, mcreds
);
607 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
613 kcm_ccache_retrieve_cred_internal(krb5_context context
,
615 krb5_flags whichfields
,
616 const krb5_creds
*mcreds
,
623 memset(creds
, 0, sizeof(*creds
));
628 for (c
= ccache
->creds
; c
!= NULL
; c
= c
->next
) {
629 match
= krb5_compare_creds(context
, whichfields
, mcreds
, &c
->cred
);
643 kcm_ccache_retrieve_cred(krb5_context context
,
645 krb5_flags whichfields
,
646 const krb5_creds
*mcreds
,
651 KCM_ASSERT_VALID(ccache
);
653 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
654 ret
= kcm_ccache_retrieve_cred_internal(context
, ccache
,
655 whichfields
, mcreds
, credp
);
656 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
662 kcm_ccache_first_name(kcm_client
*client
)
667 HEIMDAL_MUTEX_lock(&ccache_mutex
);
669 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
670 if (kcm_is_same_session(client
, p
->uid
, p
->session
))
674 name
= strdup(p
->name
);
675 HEIMDAL_MUTEX_unlock(&ccache_mutex
);