2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
34 #include "krb5_locl.h"
36 RCSID("$Id: cache.c,v 1.77 2005/12/13 15:42:36 lha Exp $");
39 * Add a new ccache type with operations `ops', overwriting any
40 * existing one if `override'.
41 * Return an error code or 0.
44 krb5_error_code KRB5_LIB_FUNCTION
45 krb5_cc_register(krb5_context context
,
46 const krb5_cc_ops
*ops
,
47 krb5_boolean override
)
51 for(i
= 0; i
< context
->num_cc_ops
&& context
->cc_ops
[i
].prefix
; i
++) {
52 if(strcmp(context
->cc_ops
[i
].prefix
, ops
->prefix
) == 0) {
54 krb5_set_error_string(context
,
55 "ccache type %s already exists",
57 return KRB5_CC_TYPE_EXISTS
;
62 if(i
== context
->num_cc_ops
) {
63 krb5_cc_ops
*o
= realloc(context
->cc_ops
,
64 (context
->num_cc_ops
+ 1) *
65 sizeof(*context
->cc_ops
));
67 krb5_set_error_string(context
, "malloc: out of memory");
70 context
->num_cc_ops
++;
72 memset(context
->cc_ops
+ i
, 0,
73 (context
->num_cc_ops
- i
) * sizeof(*context
->cc_ops
));
75 memcpy(&context
->cc_ops
[i
], ops
, sizeof(context
->cc_ops
[i
]));
80 * Allocate the memory for a `id' and the that function table to
81 * `ops'. Returns 0 or and error code.
85 _krb5_cc_allocate(krb5_context context
,
86 const krb5_cc_ops
*ops
,
91 p
= malloc (sizeof(*p
));
93 krb5_set_error_string(context
, "malloc: out of memory");
103 * Allocate memory for a new ccache in `id' with operations `ops'
104 * and name `residual'.
105 * Return 0 or an error code.
108 static krb5_error_code
109 allocate_ccache (krb5_context context
,
110 const krb5_cc_ops
*ops
,
111 const char *residual
,
116 ret
= _krb5_cc_allocate(context
, ops
, id
);
119 ret
= (*id
)->ops
->resolve(context
, id
, residual
);
126 * Find and allocate a ccache in `id' from the specification in `residual'.
127 * If the ccache name doesn't contain any colon, interpret it as a file name.
128 * Return 0 or an error code.
131 krb5_error_code KRB5_LIB_FUNCTION
132 krb5_cc_resolve(krb5_context context
,
138 for(i
= 0; i
< context
->num_cc_ops
&& context
->cc_ops
[i
].prefix
; i
++) {
139 size_t prefix_len
= strlen(context
->cc_ops
[i
].prefix
);
141 if(strncmp(context
->cc_ops
[i
].prefix
, name
, prefix_len
) == 0
142 && name
[prefix_len
] == ':') {
143 return allocate_ccache (context
, &context
->cc_ops
[i
],
144 name
+ prefix_len
+ 1,
148 if (strchr (name
, ':') == NULL
)
149 return allocate_ccache (context
, &krb5_fcc_ops
, name
, id
);
151 krb5_set_error_string(context
, "unknown ccache type %s", name
);
152 return KRB5_CC_UNKNOWN_TYPE
;
157 * Generate a new ccache of type `ops' in `id'.
158 * Return 0 or an error code.
161 krb5_error_code KRB5_LIB_FUNCTION
162 krb5_cc_gen_new(krb5_context context
,
163 const krb5_cc_ops
*ops
,
168 ret
= _krb5_cc_allocate(context
, ops
, id
);
171 return (*id
)->ops
->gen_new(context
, id
);
175 * Generates a new unique ccache of `type` in `id'. If `type' is NULL,
176 * the library chooses the default credential cache type. The supplied
177 * `hint' (that can be NULL) is a string that the credential cache
178 * type can use to base the name of the credential on, this is to make
179 * its easier for the user to differentiate the credentials.
181 * Returns 0 or an error code.
184 krb5_error_code KRB5_LIB_FUNCTION
185 krb5_cc_new_unique(krb5_context context
, const char *type
,
186 const char *hint
, krb5_ccache
*id
)
188 const krb5_cc_ops
*ops
;
193 ops
= krb5_cc_get_prefix_ops(context
, type
);
195 krb5_set_error_string(context
, "Credential cache type %s is unknown",
197 return KRB5_CC_UNKNOWN_TYPE
;
200 return krb5_cc_gen_new(context
, ops
, id
);
204 * Return the name of the ccache `id'
207 const char* KRB5_LIB_FUNCTION
208 krb5_cc_get_name(krb5_context context
,
211 return id
->ops
->get_name(context
, id
);
215 * Return the type of the ccache `id'.
218 const char* KRB5_LIB_FUNCTION
219 krb5_cc_get_type(krb5_context context
,
222 return id
->ops
->prefix
;
226 * Return the complete resolvable name the ccache `id' in `str´.
227 * `str` should be freed with free(3).
228 * Returns 0 or an error (and then *str is set to NULL).
231 krb5_error_code KRB5_LIB_FUNCTION
232 krb5_cc_get_full_name(krb5_context context
,
236 const char *type
, *name
;
240 type
= krb5_cc_get_type(context
, id
);
242 krb5_set_error_string(context
, "cache have no name of type");
243 return KRB5_CC_UNKNOWN_TYPE
;
246 name
= krb5_cc_get_name(context
, id
);
248 krb5_set_error_string(context
, "cache of type %s have no name", type
);
249 return KRB5_CC_BADNAME
;
252 if (asprintf(str
, "%s:%s", type
, name
) == -1) {
253 krb5_set_error_string(context
, "malloc - out of memory");
261 * Return krb5_cc_ops of a the ccache `id'.
265 krb5_cc_get_ops(krb5_context context
, krb5_ccache id
)
271 * Expand variables in `str' into `res'
275 _krb5_expand_default_cc_name(krb5_context context
, const char *str
, char **res
)
277 size_t tlen
, len
= 0;
278 char *tmp
, *tmp2
, *append
;
282 while (str
&& *str
) {
283 tmp
= strstr(str
, "%{");
284 if (tmp
&& tmp
!= str
) {
285 append
= malloc((tmp
- str
) + 1);
287 memcpy(append
, str
, tmp
- str
);
288 append
[tmp
- str
] = '\0';
292 tmp2
= strchr(tmp
, '}');
296 krb5_set_error_string(context
, "variable missing }");
297 return KRB5_CONFIG_BADFORMAT
;
299 if (strncasecmp(tmp
, "%{uid}", 6) == 0)
300 asprintf(&append
, "%u", (unsigned)getuid());
301 else if (strncasecmp(tmp
, "%{null}", 7) == 0)
306 krb5_set_error_string(context
,
307 "expand default cache unknown "
309 (int)(tmp2
- tmp
) - 2, tmp
+ 2);
310 return KRB5_CONFIG_BADFORMAT
;
314 append
= strdup(str
);
317 if (append
== NULL
) {
320 krb5_set_error_string(context
, "malloc - out of memory");
324 tlen
= strlen(append
);
325 tmp
= realloc(*res
, len
+ tlen
+ 1);
329 krb5_set_error_string(context
, "malloc - out of memory");
333 memcpy(*res
+ len
, append
, tlen
+ 1);
341 * Set the default cc name for `context' to `name'.
344 krb5_error_code KRB5_LIB_FUNCTION
345 krb5_cc_set_default_name(krb5_context context
, const char *name
)
347 krb5_error_code ret
= 0;
351 const char *e
= NULL
;
354 e
= getenv("KRB5CCNAME");
359 e
= krb5_config_get_string(context
, NULL
, "libdefaults",
360 "default_cc_name", NULL
);
362 e
= KRB5_DEFAULT_CCNAME
;
363 ret
= _krb5_expand_default_cc_name(context
, e
, &p
);
371 krb5_set_error_string(context
, "malloc - out of memory");
375 if (context
->default_cc_name
)
376 free(context
->default_cc_name
);
378 context
->default_cc_name
= p
;
384 * Return a pointer to a context static string containing the default
388 const char* KRB5_LIB_FUNCTION
389 krb5_cc_default_name(krb5_context context
)
391 if (context
->default_cc_name
== NULL
)
392 krb5_cc_set_default_name(context
, NULL
);
394 return context
->default_cc_name
;
398 * Open the default ccache in `id'.
399 * Return 0 or an error code.
402 krb5_error_code KRB5_LIB_FUNCTION
403 krb5_cc_default(krb5_context context
,
406 const char *p
= krb5_cc_default_name(context
);
409 krb5_set_error_string(context
, "malloc - out of memory");
412 return krb5_cc_resolve(context
, p
, id
);
416 * Create a new ccache in `id' for `primary_principal'.
417 * Return 0 or an error code.
420 krb5_error_code KRB5_LIB_FUNCTION
421 krb5_cc_initialize(krb5_context context
,
423 krb5_principal primary_principal
)
425 return id
->ops
->init(context
, id
, primary_principal
);
430 * Remove the ccache `id'.
431 * Return 0 or an error code.
434 krb5_error_code KRB5_LIB_FUNCTION
435 krb5_cc_destroy(krb5_context context
,
440 ret
= id
->ops
->destroy(context
, id
);
441 krb5_cc_close (context
, id
);
446 * Stop using the ccache `id' and free the related resources.
447 * Return 0 or an error code.
450 krb5_error_code KRB5_LIB_FUNCTION
451 krb5_cc_close(krb5_context context
,
455 ret
= id
->ops
->close(context
, id
);
461 * Store `creds' in the ccache `id'.
462 * Return 0 or an error code.
465 krb5_error_code KRB5_LIB_FUNCTION
466 krb5_cc_store_cred(krb5_context context
,
470 return id
->ops
->store(context
, id
, creds
);
474 * Retrieve the credential identified by `mcreds' (and `whichfields')
475 * from `id' in `creds'.
476 * Return 0 or an error code.
479 krb5_error_code KRB5_LIB_FUNCTION
480 krb5_cc_retrieve_cred(krb5_context context
,
482 krb5_flags whichfields
,
483 const krb5_creds
*mcreds
,
487 krb5_cc_cursor cursor
;
489 if (id
->ops
->retrieve
!= NULL
) {
490 return id
->ops
->retrieve(context
, id
, whichfields
,
494 krb5_cc_start_seq_get(context
, id
, &cursor
);
495 while((ret
= krb5_cc_next_cred(context
, id
, &cursor
, creds
)) == 0){
496 if(krb5_compare_creds(context
, whichfields
, mcreds
, creds
)){
500 krb5_free_cred_contents (context
, creds
);
502 krb5_cc_end_seq_get(context
, id
, &cursor
);
507 * Return the principal of `id' in `principal'.
508 * Return 0 or an error code.
511 krb5_error_code KRB5_LIB_FUNCTION
512 krb5_cc_get_principal(krb5_context context
,
514 krb5_principal
*principal
)
516 return id
->ops
->get_princ(context
, id
, principal
);
520 * Start iterating over `id', `cursor' is initialized to the
522 * Return 0 or an error code.
525 krb5_error_code KRB5_LIB_FUNCTION
526 krb5_cc_start_seq_get (krb5_context context
,
527 const krb5_ccache id
,
528 krb5_cc_cursor
*cursor
)
530 return id
->ops
->get_first(context
, id
, cursor
);
534 * Retrieve the next cred pointed to by (`id', `cursor') in `creds'
535 * and advance `cursor'.
536 * Return 0 or an error code.
539 krb5_error_code KRB5_LIB_FUNCTION
540 krb5_cc_next_cred (krb5_context context
,
541 const krb5_ccache id
,
542 krb5_cc_cursor
*cursor
,
545 return id
->ops
->get_next(context
, id
, cursor
, creds
);
548 /* like krb5_cc_next_cred, but allow for selective retrieval */
550 krb5_error_code KRB5_LIB_FUNCTION
551 krb5_cc_next_cred_match(krb5_context context
,
552 const krb5_ccache id
,
553 krb5_cc_cursor
* cursor
,
555 krb5_flags whichfields
,
556 const krb5_creds
* mcreds
)
560 ret
= krb5_cc_next_cred(context
, id
, cursor
, creds
);
563 if (mcreds
== NULL
|| krb5_compare_creds(context
, whichfields
, mcreds
, creds
))
565 krb5_free_cred_contents(context
, creds
);
570 * Destroy the cursor `cursor'.
573 krb5_error_code KRB5_LIB_FUNCTION
574 krb5_cc_end_seq_get (krb5_context context
,
575 const krb5_ccache id
,
576 krb5_cc_cursor
*cursor
)
578 return id
->ops
->end_get(context
, id
, cursor
);
582 * Remove the credential identified by `cred', `which' from `id'.
585 krb5_error_code KRB5_LIB_FUNCTION
586 krb5_cc_remove_cred(krb5_context context
,
591 if(id
->ops
->remove_cred
== NULL
) {
592 krb5_set_error_string(context
,
593 "ccache %s does not support remove_cred",
595 return EACCES
; /* XXX */
597 return (*id
->ops
->remove_cred
)(context
, id
, which
, cred
);
601 * Set the flags of `id' to `flags'.
604 krb5_error_code KRB5_LIB_FUNCTION
605 krb5_cc_set_flags(krb5_context context
,
609 return id
->ops
->set_flags(context
, id
, flags
);
613 * Copy the contents of `from' to `to'.
616 krb5_error_code KRB5_LIB_FUNCTION
617 krb5_cc_copy_cache_match(krb5_context context
,
618 const krb5_ccache from
,
620 krb5_flags whichfields
,
621 const krb5_creds
* mcreds
,
622 unsigned int *matched
)
625 krb5_cc_cursor cursor
;
627 krb5_principal princ
;
629 ret
= krb5_cc_get_principal(context
, from
, &princ
);
632 ret
= krb5_cc_initialize(context
, to
, princ
);
634 krb5_free_principal(context
, princ
);
637 ret
= krb5_cc_start_seq_get(context
, from
, &cursor
);
639 krb5_free_principal(context
, princ
);
645 krb5_cc_next_cred_match(context
, from
, &cursor
, &cred
,
646 whichfields
, mcreds
) == 0) {
649 ret
= krb5_cc_store_cred(context
, to
, &cred
);
650 krb5_free_cred_contents(context
, &cred
);
652 krb5_cc_end_seq_get(context
, from
, &cursor
);
653 krb5_free_principal(context
, princ
);
657 krb5_error_code KRB5_LIB_FUNCTION
658 krb5_cc_copy_cache(krb5_context context
,
659 const krb5_ccache from
,
662 return krb5_cc_copy_cache_match(context
, from
, to
, 0, NULL
, NULL
);
666 * Return the version of `id'.
669 krb5_error_code KRB5_LIB_FUNCTION
670 krb5_cc_get_version(krb5_context context
,
671 const krb5_ccache id
)
673 if(id
->ops
->get_version
)
674 return id
->ops
->get_version(context
, id
);
680 * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred
683 void KRB5_LIB_FUNCTION
684 krb5_cc_clear_mcred(krb5_creds
*mcred
)
686 memset(mcred
, 0, sizeof(*mcred
));
690 * Get the cc ops that is registered in `context' to handle the
691 * `prefix'. `prefix' can be a complete credential cache name or a
692 * prefix, the function will only use part up to the first colon (:)
693 * if there is one. Returns NULL if ops not found.
697 krb5_cc_get_prefix_ops(krb5_context context
, const char *prefix
)
702 if (prefix
[0] == '/')
703 return &krb5_fcc_ops
;
707 krb5_set_error_string(context
, "malloc - out of memory");
714 for(i
= 0; i
< context
->num_cc_ops
&& context
->cc_ops
[i
].prefix
; i
++) {
715 if(strcmp(context
->cc_ops
[i
].prefix
, p
) == 0) {
717 return &context
->cc_ops
[i
];
724 struct krb5_cc_cache_cursor_data
{
725 const krb5_cc_ops
*ops
;
726 krb5_cc_cursor cursor
;
730 * Start iterating over all caches of `type'. If `type' is NULL, the
731 * default type is * used. `cursor' is initialized to the beginning.
732 * Return 0 or an error code.
735 krb5_error_code KRB5_LIB_FUNCTION
736 krb5_cc_cache_get_first (krb5_context context
,
738 krb5_cc_cache_cursor
*cursor
)
740 const krb5_cc_ops
*ops
;
744 type
= krb5_cc_default_name(context
);
746 ops
= krb5_cc_get_prefix_ops(context
, type
);
748 krb5_set_error_string(context
, "Unknown type \"%s\" when iterating "
749 "trying to iterate the credential caches", type
);
750 return KRB5_CC_UNKNOWN_TYPE
;
753 if (ops
->get_cache_first
== NULL
) {
754 krb5_set_error_string(context
, "Credential cache type %s doesn't support "
755 "iterations over caches", ops
->prefix
);
756 return KRB5_CC_NOSUPP
;
759 *cursor
= calloc(1, sizeof(**cursor
));
760 if (*cursor
== NULL
) {
761 krb5_set_error_string(context
, "malloc - out of memory");
765 (*cursor
)->ops
= ops
;
767 ret
= ops
->get_cache_first(context
, &(*cursor
)->cursor
);
776 * Retrieve the next cache pointed to by (`cursor') in `id'
777 * and advance `cursor'.
778 * Return 0 or an error code.
781 krb5_error_code KRB5_LIB_FUNCTION
782 krb5_cc_cache_next (krb5_context context
,
783 krb5_cc_cache_cursor cursor
,
786 return cursor
->ops
->get_cache_next(context
, cursor
->cursor
, id
);
790 * Destroy the cursor `cursor'.
793 krb5_error_code KRB5_LIB_FUNCTION
794 krb5_cc_cache_end_seq_get (krb5_context context
,
795 krb5_cc_cache_cursor cursor
)
798 ret
= cursor
->ops
->end_cache_get(context
, cursor
->cursor
);
805 * Search for a matching credential cache of type `type' that have the
806 * `principal' as the default principal. If NULL is used for `type',
807 * the default type is used. On success, `id' needs to be freed with
808 * krb5_cc_close or krb5_cc_destroy. On failure, error code is
809 * returned and `id' is set to NULL.
812 krb5_error_code KRB5_LIB_FUNCTION
813 krb5_cc_cache_match (krb5_context context
,
814 krb5_principal client
,
818 krb5_cc_cache_cursor cursor
;
820 krb5_ccache cache
= NULL
;
824 ret
= krb5_cc_cache_get_first (context
, type
, &cursor
);
828 while ((ret
= krb5_cc_cache_next (context
, cursor
, &cache
)) == 0) {
829 krb5_principal principal
;
831 ret
= krb5_cc_get_principal(context
, cache
, &principal
);
835 match
= krb5_principal_compare(context
, principal
, client
);
836 krb5_free_principal(context
, principal
);
841 krb5_cc_close(context
, cache
);
845 krb5_cc_cache_end_seq_get(context
, cursor
);
850 krb5_unparse_name(context
, client
, &str
);
852 krb5_set_error_string(context
, "Principal %s not found in a "
853 "credential cache", str
? str
: "<out of memory>");
856 return KRB5_CC_NOTFOUND
;