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
;
52 static HEIMDAL_MUTEX mcc_mutex
= HEIMDAL_MUTEX_INITIALIZER
;
53 static struct krb5_mcache
*mcc_head
;
55 #define MCACHE(X) ((krb5_mcache *)(X)->data.data)
57 #define MISDEAD(X) ((X)->dead)
59 static const char* KRB5_CALLCONV
60 mcc_get_name(krb5_context context
,
63 return MCACHE(id
)->name
;
66 static krb5_mcache
* KRB5_CALLCONV
67 mcc_alloc(const char *name
)
76 ret
= asprintf(&m
->name
, "%p", m
);
78 m
->name
= strdup(name
);
79 if(ret
< 0 || m
->name
== NULL
) {
83 /* check for dups first */
84 HEIMDAL_MUTEX_lock(&mcc_mutex
);
85 for (m_c
= mcc_head
; m_c
!= NULL
; m_c
= m_c
->next
)
86 if (strcmp(m
->name
, m_c
->name
) == 0)
91 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
97 m
->primary_principal
= NULL
;
99 m
->mtime
= time(NULL
);
103 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
107 static krb5_error_code KRB5_CALLCONV
108 mcc_resolve(krb5_context context
, krb5_ccache
*id
, const char *res
)
112 HEIMDAL_MUTEX_lock(&mcc_mutex
);
113 for (m
= mcc_head
; m
!= NULL
; m
= m
->next
)
114 if (strcmp(m
->name
, res
) == 0)
116 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
120 (*id
)->data
.data
= m
;
121 (*id
)->data
.length
= sizeof(*m
);
127 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
128 N_("malloc: out of memory", ""));
129 return KRB5_CC_NOMEM
;
132 (*id
)->data
.data
= m
;
133 (*id
)->data
.length
= sizeof(*m
);
139 static krb5_error_code KRB5_CALLCONV
140 mcc_gen_new(krb5_context context
, krb5_ccache
*id
)
147 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
148 N_("malloc: out of memory", ""));
149 return KRB5_CC_NOMEM
;
152 (*id
)->data
.data
= m
;
153 (*id
)->data
.length
= sizeof(*m
);
158 static krb5_error_code KRB5_CALLCONV
159 mcc_initialize(krb5_context context
,
161 krb5_principal primary_principal
)
163 krb5_mcache
*m
= MCACHE(id
);
165 m
->mtime
= time(NULL
);
166 return krb5_copy_principal (context
,
168 &m
->primary_principal
);
172 mcc_close_internal(krb5_mcache
*m
)
174 if (--m
->refcnt
!= 0)
184 static krb5_error_code KRB5_CALLCONV
185 mcc_close(krb5_context context
,
188 if (mcc_close_internal(MCACHE(id
)))
189 krb5_data_free(&id
->data
);
193 static krb5_error_code KRB5_CALLCONV
194 mcc_destroy(krb5_context context
,
197 krb5_mcache
**n
, *m
= MCACHE(id
);
201 krb5_abortx(context
, "mcc_destroy: refcnt already 0");
204 /* if this is an active mcache, remove it from the linked
205 list, and free all data */
206 HEIMDAL_MUTEX_lock(&mcc_mutex
);
207 for(n
= &mcc_head
; n
&& *n
; n
= &(*n
)->next
) {
213 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
214 if (m
->primary_principal
!= NULL
) {
215 krb5_free_principal (context
, m
->primary_principal
);
216 m
->primary_principal
= NULL
;
224 krb5_free_cred_contents (context
, &l
->cred
);
234 static krb5_error_code KRB5_CALLCONV
235 mcc_store_cred(krb5_context context
,
239 krb5_mcache
*m
= MCACHE(id
);
246 l
= malloc (sizeof(*l
));
248 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
249 N_("malloc: out of memory", ""));
250 return KRB5_CC_NOMEM
;
254 memset (&l
->cred
, 0, sizeof(l
->cred
));
255 ret
= krb5_copy_creds_contents (context
, creds
, &l
->cred
);
261 m
->mtime
= time(NULL
);
265 static krb5_error_code KRB5_CALLCONV
266 mcc_get_principal(krb5_context context
,
268 krb5_principal
*principal
)
270 krb5_mcache
*m
= MCACHE(id
);
272 if (MISDEAD(m
) || m
->primary_principal
== NULL
)
274 return krb5_copy_principal (context
,
275 m
->primary_principal
,
279 static krb5_error_code KRB5_CALLCONV
280 mcc_get_first (krb5_context context
,
282 krb5_cc_cursor
*cursor
)
284 krb5_mcache
*m
= MCACHE(id
);
293 static krb5_error_code KRB5_CALLCONV
294 mcc_get_next (krb5_context context
,
296 krb5_cc_cursor
*cursor
,
299 krb5_mcache
*m
= MCACHE(id
);
308 return krb5_copy_creds_contents (context
,
315 static krb5_error_code KRB5_CALLCONV
316 mcc_end_get (krb5_context context
,
318 krb5_cc_cursor
*cursor
)
323 static krb5_error_code KRB5_CALLCONV
324 mcc_remove_cred(krb5_context context
,
329 krb5_mcache
*m
= MCACHE(id
);
331 for(q
= &m
->creds
, p
= *q
; p
; p
= *q
) {
332 if(krb5_compare_creds(context
, which
, mcreds
, &p
->cred
)) {
334 krb5_free_cred_contents(context
, &p
->cred
);
336 m
->mtime
= time(NULL
);
343 static krb5_error_code KRB5_CALLCONV
344 mcc_set_flags(krb5_context context
,
355 static krb5_error_code KRB5_CALLCONV
356 mcc_get_cache_first(krb5_context context
, krb5_cc_cursor
*cursor
)
358 struct mcache_iter
*iter
;
360 iter
= calloc(1, sizeof(*iter
));
362 krb5_set_error_message(context
, ENOMEM
,
363 N_("malloc: out of memory", ""));
367 HEIMDAL_MUTEX_lock(&mcc_mutex
);
368 iter
->cache
= mcc_head
;
370 iter
->cache
->refcnt
++;
371 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
377 static krb5_error_code KRB5_CALLCONV
378 mcc_get_cache_next(krb5_context context
, krb5_cc_cursor cursor
, krb5_ccache
*id
)
380 struct mcache_iter
*iter
= cursor
;
384 if (iter
->cache
== NULL
)
387 HEIMDAL_MUTEX_lock(&mcc_mutex
);
391 iter
->cache
= m
->next
;
392 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
394 ret
= _krb5_cc_allocate(context
, &krb5_mcc_ops
, id
);
398 (*id
)->data
.data
= m
;
399 (*id
)->data
.length
= sizeof(*m
);
404 static krb5_error_code KRB5_CALLCONV
405 mcc_end_cache_get(krb5_context context
, krb5_cc_cursor cursor
)
407 struct mcache_iter
*iter
= cursor
;
410 mcc_close_internal(iter
->cache
);
416 static krb5_error_code KRB5_CALLCONV
417 mcc_move(krb5_context context
, krb5_ccache from
, krb5_ccache to
)
419 krb5_mcache
*mfrom
= MCACHE(from
), *mto
= MCACHE(to
);
421 krb5_principal principal
;
424 HEIMDAL_MUTEX_lock(&mcc_mutex
);
426 /* drop the from cache from the linked list to avoid lookups */
427 for(n
= &mcc_head
; n
&& *n
; n
= &(*n
)->next
) {
436 mto
->creds
= mfrom
->creds
;
437 mfrom
->creds
= creds
;
439 principal
= mto
->primary_principal
;
440 mto
->primary_principal
= mfrom
->primary_principal
;
441 mfrom
->primary_principal
= principal
;
443 mto
->mtime
= mfrom
->mtime
= time(NULL
);
445 HEIMDAL_MUTEX_unlock(&mcc_mutex
);
446 mcc_destroy(context
, from
);
451 static krb5_error_code KRB5_CALLCONV
452 mcc_default_name(krb5_context context
, char **str
)
454 *str
= strdup("MEMORY:");
456 krb5_set_error_message(context
, ENOMEM
,
457 N_("malloc: out of memory", ""));
463 static krb5_error_code KRB5_CALLCONV
464 mcc_lastchange(krb5_context context
, krb5_ccache id
, krb5_timestamp
*mtime
)
466 *mtime
= MCACHE(id
)->mtime
;
470 static krb5_error_code KRB5_CALLCONV
471 mcc_set_kdc_offset(krb5_context context
, krb5_ccache id
, krb5_deltat kdc_offset
)
473 krb5_mcache
*m
= MCACHE(id
);
474 m
->kdc_offset
= kdc_offset
;
478 static krb5_error_code KRB5_CALLCONV
479 mcc_get_kdc_offset(krb5_context context
, krb5_ccache id
, krb5_deltat
*kdc_offset
)
481 krb5_mcache
*m
= MCACHE(id
);
482 *kdc_offset
= m
->kdc_offset
;
488 * Variable containing the MEMORY based credential cache implemention.
490 * @ingroup krb5_ccache
493 KRB5_LIB_VARIABLE
const krb5_cc_ops krb5_mcc_ops
= {
503 NULL
, /* mcc_retrieve */