2 * Copyright (c) 2005, PADL Software Pty Ltd.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of PADL Software nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 static HEIMDAL_MUTEX ccache_mutex
= HEIMDAL_MUTEX_INITIALIZER
;
38 static kcm_ccache_data
*ccache_head
= NULL
;
39 static unsigned int ccache_nextid
= 0;
41 char *kcm_ccache_nextid(pid_t pid
, uid_t uid
, gid_t gid
)
46 HEIMDAL_MUTEX_lock(&ccache_mutex
);
48 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
50 asprintf(&name
, "%d:%u", uid
, n
);
55 static krb5_error_code
56 kcm_ccache_resolve_internal(krb5_context context
,
65 ret
= KRB5_FCC_NOFILE
;
67 HEIMDAL_MUTEX_lock(&ccache_mutex
);
69 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
70 if ((p
->flags
& KCM_FLAGS_VALID
) == 0)
72 if (strcmp(p
->name
, name
) == 0) {
79 kcm_retain_ccache(context
, p
);
83 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
88 krb5_error_code
kcm_debug_ccache(krb5_context context
)
92 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
93 char *cpn
= NULL
, *spn
= NULL
;
97 if ((p
->flags
& KCM_FLAGS_VALID
) == 0) {
98 kcm_log(7, "cache %08x: empty slot");
104 for (k
= p
->creds
; k
!= NULL
; k
= k
->next
)
107 if (p
->client
!= NULL
)
108 krb5_unparse_name(context
, p
->client
, &cpn
);
109 if (p
->server
!= NULL
)
110 krb5_unparse_name(context
, p
->server
, &spn
);
112 kcm_log(7, "cache %08x: name %s refcnt %d flags %04x mode %04o "
113 "uid %d gid %d client %s server %s ncreds %d",
114 p
, p
->name
, p
->refcnt
, p
->flags
, p
->mode
, p
->uid
, p
->gid
,
115 (cpn
== NULL
) ? "<none>" : cpn
,
116 (spn
== NULL
) ? "<none>" : spn
,
128 static krb5_error_code
129 kcm_ccache_destroy_internal(krb5_context context
, const char *name
)
134 ret
= KRB5_FCC_NOFILE
;
136 HEIMDAL_MUTEX_lock(&ccache_mutex
);
137 for (p
= &ccache_head
; *p
!= NULL
; p
= &(*p
)->next
) {
138 if (((*p
)->flags
& KCM_FLAGS_VALID
) == 0)
140 if (strcmp((*p
)->name
, name
) == 0) {
149 kcm_release_ccache(context
, p
);
152 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
157 static krb5_error_code
158 kcm_ccache_alloc(krb5_context context
,
162 kcm_ccache slot
= NULL
, p
;
168 /* First, check for duplicates */
169 HEIMDAL_MUTEX_lock(&ccache_mutex
);
171 for (p
= ccache_head
; p
!= NULL
; p
= p
->next
) {
172 if (p
->flags
& KCM_FLAGS_VALID
) {
173 if (strcmp(p
->name
, name
) == 0) {
177 } else if (slot
== NULL
)
185 * Then try and find an empty slot
186 * XXX we need to recycle slots for this to actually do anything
189 for (; p
!= NULL
; p
= p
->next
) {
190 if ((p
->flags
& KCM_FLAGS_VALID
) == 0) {
197 slot
= (kcm_ccache_data
*)malloc(sizeof(*slot
));
202 slot
->next
= ccache_head
;
203 HEIMDAL_MUTEX_init(&slot
->mutex
);
208 slot
->name
= strdup(name
);
209 if (slot
->name
== NULL
) {
215 slot
->flags
= KCM_FLAGS_VALID
;
216 slot
->mode
= S_IRUSR
| S_IWUSR
;
223 slot
->cursors
= NULL
;
224 slot
->key
.keytab
= NULL
;
226 slot
->renew_life
= 0;
233 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
237 HEIMDAL_MUTEX_unlock(&ccache_mutex
);
238 if (new_slot
&& slot
!= NULL
) {
239 HEIMDAL_MUTEX_destroy(&slot
->mutex
);
246 kcm_ccache_remove_creds_internal(krb5_context context
,
250 struct kcm_cursor
*c
;
254 struct kcm_creds
*old
;
256 krb5_free_cred_contents(context
, &k
->cred
);
261 ccache
->creds
= NULL
;
263 /* remove anything that would have pointed into the creds too */
265 ccache
->n_cursor
= 0;
269 struct kcm_cursor
*old
;
275 ccache
->cursors
= NULL
;
281 kcm_ccache_remove_creds(krb5_context context
,
286 KCM_ASSERT_VALID(ccache
);
288 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
289 ret
= kcm_ccache_remove_creds_internal(context
, ccache
);
290 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
296 kcm_zero_ccache_data_internal(krb5_context context
,
297 kcm_ccache_data
*cache
)
299 if (cache
->client
!= NULL
) {
300 krb5_free_principal(context
, cache
->client
);
301 cache
->client
= NULL
;
304 if (cache
->server
!= NULL
) {
305 krb5_free_principal(context
, cache
->server
);
306 cache
->server
= NULL
;
309 kcm_ccache_remove_creds_internal(context
, cache
);
315 kcm_zero_ccache_data(krb5_context context
,
320 KCM_ASSERT_VALID(cache
);
322 HEIMDAL_MUTEX_lock(&cache
->mutex
);
323 ret
= kcm_zero_ccache_data_internal(context
, cache
);
324 HEIMDAL_MUTEX_unlock(&cache
->mutex
);
329 static krb5_error_code
330 kcm_free_ccache_data_internal(krb5_context context
,
331 kcm_ccache_data
*cache
)
333 KCM_ASSERT_VALID(cache
);
335 if (cache
->name
!= NULL
) {
340 if (cache
->flags
& KCM_FLAGS_USE_KEYTAB
) {
341 krb5_kt_close(context
, cache
->key
.keytab
);
342 cache
->key
.keytab
= NULL
;
343 } else if (cache
->flags
& KCM_FLAGS_USE_CACHED_KEY
) {
344 krb5_free_keyblock_contents(context
, &cache
->key
.keyblock
);
345 krb5_keyblock_zero(&cache
->key
.keyblock
);
353 kcm_zero_ccache_data_internal(context
, cache
);
356 cache
->renew_life
= 0;
361 HEIMDAL_MUTEX_unlock(&cache
->mutex
);
362 HEIMDAL_MUTEX_destroy(&cache
->mutex
);
368 kcm_retain_ccache(krb5_context context
,
371 KCM_ASSERT_VALID(ccache
);
373 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
375 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
381 kcm_release_ccache(krb5_context context
,
384 kcm_ccache c
= *ccache
;
385 krb5_error_code ret
= 0;
389 HEIMDAL_MUTEX_lock(&c
->mutex
);
390 if (c
->refcnt
== 1) {
391 ret
= kcm_free_ccache_data_internal(context
, c
);
396 HEIMDAL_MUTEX_unlock(&c
->mutex
);
405 kcm_ccache_gen_new(krb5_context context
,
414 name
= kcm_ccache_nextid(pid
, uid
, gid
);
416 return KRB5_CC_NOMEM
;
419 ret
= kcm_ccache_new(context
, name
, ccache
);
426 kcm_ccache_new(krb5_context context
,
432 ret
= kcm_ccache_alloc(context
, name
, ccache
);
435 * one reference is held by the linked list,
438 kcm_retain_ccache(context
, *ccache
);
445 kcm_ccache_resolve(krb5_context context
,
451 ret
= kcm_ccache_resolve_internal(context
, name
, ccache
);
457 kcm_ccache_destroy(krb5_context context
,
462 ret
= kcm_ccache_destroy_internal(context
, name
);
468 kcm_ccache_destroy_if_empty(krb5_context context
,
473 KCM_ASSERT_VALID(ccache
);
475 if (ccache
->creds
== NULL
) {
476 ret
= kcm_ccache_destroy_internal(context
, ccache
->name
);
484 kcm_ccache_store_cred(krb5_context context
,
492 KCM_ASSERT_VALID(ccache
);
494 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
495 ret
= kcm_ccache_store_cred_internal(context
, ccache
, creds
, copy
, &tmp
);
496 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
502 kcm_ccache_store_cred_internal(krb5_context context
,
508 struct kcm_creds
**c
;
511 for (c
= &ccache
->creds
; *c
!= NULL
; c
= &(*c
)->next
)
514 *c
= (struct kcm_creds
*)malloc(sizeof(struct kcm_creds
));
516 return KRB5_CC_NOMEM
;
519 *credp
= &(*c
)->cred
;
522 ret
= krb5_copy_creds_contents(context
, creds
, *credp
);
538 remove_cred(krb5_context context
,
539 struct kcm_creds
**c
)
541 struct kcm_creds
*cred
;
547 krb5_free_cred_contents(context
, &cred
->cred
);
552 kcm_ccache_remove_cred_internal(krb5_context context
,
554 krb5_flags whichfields
,
555 const krb5_creds
*mcreds
)
558 struct kcm_creds
**c
;
560 ret
= KRB5_CC_NOTFOUND
;
562 for (c
= &ccache
->creds
; *c
!= NULL
; c
= &(*c
)->next
) {
563 if (krb5_compare_creds(context
, whichfields
, mcreds
, &(*c
)->cred
)) {
564 remove_cred(context
, c
);
573 kcm_ccache_remove_cred(krb5_context context
,
575 krb5_flags whichfields
,
576 const krb5_creds
*mcreds
)
580 KCM_ASSERT_VALID(ccache
);
582 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
583 ret
= kcm_ccache_remove_cred_internal(context
, ccache
, whichfields
, mcreds
);
584 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);
590 kcm_ccache_retrieve_cred_internal(krb5_context context
,
592 krb5_flags whichfields
,
593 const krb5_creds
*mcreds
,
600 memset(creds
, 0, sizeof(*creds
));
605 for (c
= ccache
->creds
; c
!= NULL
; c
= c
->next
) {
606 match
= krb5_compare_creds(context
, whichfields
, mcreds
, &c
->cred
);
620 kcm_ccache_retrieve_cred(krb5_context context
,
622 krb5_flags whichfields
,
623 const krb5_creds
*mcreds
,
628 KCM_ASSERT_VALID(ccache
);
630 HEIMDAL_MUTEX_lock(&ccache
->mutex
);
631 ret
= kcm_ccache_retrieve_cred_internal(context
, ccache
,
632 whichfields
, mcreds
, credp
);
633 HEIMDAL_MUTEX_unlock(&ccache
->mutex
);