2 * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include "krb5_locl.h"
38 typedef struct krb5_mcache
{
42 krb5_principal primary_principal
;
47 struct krb5_mcache
*next
;
49 krb5_deltat kdc_offset
;
53 static HEIMDAL_MUTEX mcc_mutex
= HEIMDAL_MUTEX_INITIALIZER
;
54 static struct krb5_mcache
*mcc_head
;
56 #define MCACHE(X) ((krb5_mcache *)(X)->data.data)
58 #define MISDEAD(X) ((X)->dead)
60 static const char* KRB5_CALLCONV
61 mcc_get_name(krb5_context context
,
64 return MCACHE(id
)->name
;
67 static krb5_mcache
* KRB5_CALLCONV
68 mcc_alloc(const char *name
)
77 ret
= asprintf(&m
->name
, "%p", m
);
79 m
->name
= strdup(name
);
80 if(ret
< 0 || m
->name
== NULL
) {
84 /* check for dups first */
85 HEIMDAL_MUTEX_lock(&mcc_mutex
);
86 for (m_c
= mcc_head
; m_c
!= NULL
; m_c
= m_c
->next
)
87 if (strcmp(m
->name
, m_c
->name
) == 0)
92 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
98 m
->primary_principal
= NULL
;
100 m
->mtime
= time(NULL
);
103 HEIMDAL_MUTEX_init(&(m
->mutex
));
105 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
109 static krb5_error_code KRB5_CALLCONV
110 mcc_resolve(krb5_context context
, krb5_ccache
*id
, const char *res
)
114 HEIMDAL_MUTEX_lock(&mcc_mutex
);
115 for (m
= mcc_head
; m
!= NULL
; m
= m
->next
)
116 if (strcmp(m
->name
, res
) == 0)
118 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
121 HEIMDAL_MUTEX_lock(&(m
->mutex
));
123 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
124 (*id
)->data
.data
= m
;
125 (*id
)->data
.length
= sizeof(*m
);
131 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
132 N_("malloc: out of memory", ""));
133 return KRB5_CC_NOMEM
;
136 (*id
)->data
.data
= m
;
137 (*id
)->data
.length
= sizeof(*m
);
143 static krb5_error_code KRB5_CALLCONV
144 mcc_gen_new(krb5_context context
, krb5_ccache
*id
)
151 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
152 N_("malloc: out of memory", ""));
153 return KRB5_CC_NOMEM
;
156 (*id
)->data
.data
= m
;
157 (*id
)->data
.length
= sizeof(*m
);
162 static krb5_error_code KRB5_CALLCONV
163 mcc_initialize(krb5_context context
,
165 krb5_principal primary_principal
)
167 krb5_mcache
*m
= MCACHE(id
);
168 krb5_error_code ret
= 0;
169 HEIMDAL_MUTEX_lock(&(m
->mutex
));
170 heim_assert(m
->refcnt
!= 0, "resurection released mcache");
172 m
->mtime
= time(NULL
);
173 ret
= krb5_copy_principal (context
,
175 &m
->primary_principal
);
176 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
181 mcc_close_internal(krb5_mcache
*m
)
183 HEIMDAL_MUTEX_lock(&(m
->mutex
));
184 heim_assert(m
->refcnt
!= 0, "closed dead cache mcache");
185 if (--m
->refcnt
!= 0) {
186 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
191 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
194 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
198 static krb5_error_code KRB5_CALLCONV
199 mcc_close(krb5_context context
,
202 krb5_mcache
*m
= MCACHE(id
);
204 if (mcc_close_internal(MCACHE(id
))) {
205 HEIMDAL_MUTEX_destroy(&(m
->mutex
));
206 krb5_data_free(&id
->data
);
211 static krb5_error_code KRB5_CALLCONV
212 mcc_destroy(krb5_context context
,
215 krb5_mcache
**n
, *m
= MCACHE(id
);
218 HEIMDAL_MUTEX_lock(&(m
->mutex
));
221 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
222 krb5_abortx(context
, "mcc_destroy: refcnt already 0");
226 /* if this is an active mcache, remove it from the linked
227 list, and free all data */
228 HEIMDAL_MUTEX_lock(&mcc_mutex
);
229 for(n
= &mcc_head
; n
&& *n
; n
= &(*n
)->next
) {
235 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
236 if (m
->primary_principal
!= NULL
) {
237 krb5_free_principal (context
, m
->primary_principal
);
238 m
->primary_principal
= NULL
;
246 krb5_free_cred_contents (context
, &l
->cred
);
253 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
257 static krb5_error_code KRB5_CALLCONV
258 mcc_store_cred(krb5_context context
,
262 krb5_mcache
*m
= MCACHE(id
);
266 HEIMDAL_MUTEX_lock(&(m
->mutex
));
269 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
273 l
= malloc (sizeof(*l
));
275 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
276 N_("malloc: out of memory", ""));
277 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
278 return KRB5_CC_NOMEM
;
282 memset (&l
->cred
, 0, sizeof(l
->cred
));
283 ret
= krb5_copy_creds_contents (context
, creds
, &l
->cred
);
287 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
290 m
->mtime
= time(NULL
);
291 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
295 static krb5_error_code KRB5_CALLCONV
296 mcc_get_principal(krb5_context context
,
298 krb5_principal
*principal
)
300 krb5_mcache
*m
= MCACHE(id
);
301 krb5_error_code ret
= 0;
303 HEIMDAL_MUTEX_lock(&(m
->mutex
));
304 if (MISDEAD(m
) || m
->primary_principal
== NULL
) {
305 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
308 ret
= krb5_copy_principal (context
,
309 m
->primary_principal
,
311 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
315 static krb5_error_code KRB5_CALLCONV
316 mcc_get_first (krb5_context context
,
318 krb5_cc_cursor
*cursor
)
320 krb5_mcache
*m
= MCACHE(id
);
322 HEIMDAL_MUTEX_lock(&(m
->mutex
));
324 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
329 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
333 static krb5_error_code KRB5_CALLCONV
334 mcc_get_next (krb5_context context
,
336 krb5_cc_cursor
*cursor
,
339 krb5_mcache
*m
= MCACHE(id
);
342 HEIMDAL_MUTEX_lock(&(m
->mutex
));
344 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
347 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
352 return krb5_copy_creds_contents (context
,
359 static krb5_error_code KRB5_CALLCONV
360 mcc_end_get (krb5_context context
,
362 krb5_cc_cursor
*cursor
)
367 static krb5_error_code KRB5_CALLCONV
368 mcc_remove_cred(krb5_context context
,
373 krb5_mcache
*m
= MCACHE(id
);
376 HEIMDAL_MUTEX_lock(&(m
->mutex
));
378 for(q
= &m
->creds
, p
= *q
; p
; p
= *q
) {
379 if(krb5_compare_creds(context
, which
, mcreds
, &p
->cred
)) {
381 krb5_free_cred_contents(context
, &p
->cred
);
383 m
->mtime
= time(NULL
);
387 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
391 static krb5_error_code KRB5_CALLCONV
392 mcc_set_flags(krb5_context context
,
403 static krb5_error_code KRB5_CALLCONV
404 mcc_get_cache_first(krb5_context context
, krb5_cc_cursor
*cursor
)
406 struct mcache_iter
*iter
;
408 iter
= calloc(1, sizeof(*iter
));
410 return krb5_enomem(context
);
412 HEIMDAL_MUTEX_lock(&mcc_mutex
);
413 iter
->cache
= mcc_head
;
415 HEIMDAL_MUTEX_lock(&(iter
->cache
->mutex
));
416 iter
->cache
->refcnt
++;
417 HEIMDAL_MUTEX_unlock(&(iter
->cache
->mutex
));
419 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
425 static krb5_error_code KRB5_CALLCONV
426 mcc_get_cache_next(krb5_context context
, krb5_cc_cursor cursor
, krb5_ccache
*id
)
428 struct mcache_iter
*iter
= cursor
;
432 if (iter
->cache
== NULL
)
435 HEIMDAL_MUTEX_lock(&mcc_mutex
);
439 HEIMDAL_MUTEX_lock(&(m
->next
->mutex
));
441 HEIMDAL_MUTEX_unlock(&(m
->next
->mutex
));
444 iter
->cache
= m
->next
;
445 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
447 ret
= _krb5_cc_allocate(context
, &krb5_mcc_ops
, id
);
451 (*id
)->data
.data
= m
;
452 (*id
)->data
.length
= sizeof(*m
);
457 static krb5_error_code KRB5_CALLCONV
458 mcc_end_cache_get(krb5_context context
, krb5_cc_cursor cursor
)
460 struct mcache_iter
*iter
= cursor
;
463 mcc_close_internal(iter
->cache
);
469 static krb5_error_code KRB5_CALLCONV
470 mcc_move(krb5_context context
, krb5_ccache from
, krb5_ccache to
)
472 krb5_mcache
*mfrom
= MCACHE(from
), *mto
= MCACHE(to
);
474 krb5_principal principal
;
477 HEIMDAL_MUTEX_lock(&mcc_mutex
);
479 /* drop the from cache from the linked list to avoid lookups */
480 for(n
= &mcc_head
; n
&& *n
; n
= &(*n
)->next
) {
487 HEIMDAL_MUTEX_lock(&(mfrom
->mutex
));
488 HEIMDAL_MUTEX_lock(&(mto
->mutex
));
491 mto
->creds
= mfrom
->creds
;
492 mfrom
->creds
= creds
;
494 principal
= mto
->primary_principal
;
495 mto
->primary_principal
= mfrom
->primary_principal
;
496 mfrom
->primary_principal
= principal
;
498 mto
->mtime
= mfrom
->mtime
= time(NULL
);
500 HEIMDAL_MUTEX_unlock(&(mfrom
->mutex
));
501 HEIMDAL_MUTEX_unlock(&(mto
->mutex
));
502 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
503 mcc_destroy(context
, from
);
508 static krb5_error_code KRB5_CALLCONV
509 mcc_default_name(krb5_context context
, char **str
)
511 *str
= strdup("MEMORY:");
513 return krb5_enomem(context
);
517 static krb5_error_code KRB5_CALLCONV
518 mcc_lastchange(krb5_context context
, krb5_ccache id
, krb5_timestamp
*mtime
)
520 krb5_mcache
*m
= MCACHE(id
);
521 HEIMDAL_MUTEX_lock(&(m
->mutex
));
523 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
527 static krb5_error_code KRB5_CALLCONV
528 mcc_set_kdc_offset(krb5_context context
, krb5_ccache id
, krb5_deltat kdc_offset
)
530 krb5_mcache
*m
= MCACHE(id
);
531 HEIMDAL_MUTEX_lock(&(m
->mutex
));
532 m
->kdc_offset
= kdc_offset
;
533 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
537 static krb5_error_code KRB5_CALLCONV
538 mcc_get_kdc_offset(krb5_context context
, krb5_ccache id
, krb5_deltat
*kdc_offset
)
540 krb5_mcache
*m
= MCACHE(id
);
541 HEIMDAL_MUTEX_lock(&(m
->mutex
));
542 *kdc_offset
= m
->kdc_offset
;
543 HEIMDAL_MUTEX_unlock(&(m
->mutex
));
549 * Variable containing the MEMORY based credential cache implemention.
551 * @ingroup krb5_ccache
554 KRB5_LIB_VARIABLE
const krb5_cc_ops krb5_mcc_ops
= {
564 NULL
, /* mcc_retrieve */