2 * Copyright (c) 1997 - 2008 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"
39 * @page krb5_ccache_intro The credential cache functions
40 * @section section_krb5_ccache Kerberos credential caches
42 * krb5_ccache structure holds a Kerberos credential cache.
44 * Heimdal support the follow types of credential caches:
47 * Store the credential in a database
49 * Store the credential in memory
51 * Store the credential in memory
53 * A credential cache server based solution for Mac OS X
55 * A credential cache server based solution for all platforms
59 * This is a minimalistic version of klist:
64 main (int argc, char **argv)
67 krb5_cc_cursor cursor;
72 if (krb5_init_context (&context) != 0)
73 errx(1, "krb5_context");
75 ret = krb5_cc_default (context, &id);
77 krb5_err(context, 1, ret, "krb5_cc_default");
79 ret = krb5_cc_start_seq_get(context, id, &cursor);
81 krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
83 while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){
86 krb5_unparse_name(context, creds.server, &principal);
87 printf("principal: %s\\n", principal);
89 krb5_free_cred_contents (context, &creds);
91 ret = krb5_cc_end_seq_get(context, id, &cursor);
93 krb5_err(context, 1, ret, "krb5_cc_end_seq_get");
95 krb5_cc_close(context, id);
97 krb5_free_context(context);
103 static const krb5_cc_ops
*
104 cc_get_prefix_ops(krb5_context context
,
106 const char **residual
);
109 * Add a new ccache type with operations `ops', overwriting any
110 * existing one if `override'.
112 * @param context a Kerberos context
113 * @param ops type of plugin symbol
114 * @param override flag to select if the registration is to overide
115 * an existing ops with the same name.
117 * @return Return an error code or 0, see krb5_get_error_message().
119 * @ingroup krb5_ccache
122 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
123 krb5_cc_register(krb5_context context
,
124 const krb5_cc_ops
*ops
,
125 krb5_boolean override
)
129 for(i
= 0; i
< context
->num_cc_ops
&& context
->cc_ops
[i
]->prefix
; i
++) {
130 if(strcmp(context
->cc_ops
[i
]->prefix
, ops
->prefix
) == 0) {
132 krb5_set_error_message(context
,
134 N_("cache type %s already exists", "type"),
136 return KRB5_CC_TYPE_EXISTS
;
141 if(i
== context
->num_cc_ops
) {
142 const krb5_cc_ops
**o
= realloc(rk_UNCONST(context
->cc_ops
),
143 (context
->num_cc_ops
+ 1) *
144 sizeof(context
->cc_ops
[0]));
146 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
147 N_("malloc: out of memory", ""));
148 return KRB5_CC_NOMEM
;
151 context
->cc_ops
[context
->num_cc_ops
] = NULL
;
152 context
->num_cc_ops
++;
154 context
->cc_ops
[i
] = ops
;
159 * Allocate the memory for a `id' and the that function table to
160 * `ops'. Returns 0 or and error code.
163 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
164 _krb5_cc_allocate(krb5_context context
,
165 const krb5_cc_ops
*ops
,
170 p
= calloc(1, sizeof(*p
));
172 krb5_set_error_message(context
, KRB5_CC_NOMEM
,
173 N_("malloc: out of memory", ""));
174 return KRB5_CC_NOMEM
;
183 * Allocate memory for a new ccache in `id' with operations `ops'
184 * and name `residual'. Return 0 or an error code.
187 static krb5_error_code
188 allocate_ccache(krb5_context context
,
189 const krb5_cc_ops
*ops
,
190 const char *residual
,
191 const char *subsidiary
,
194 krb5_error_code ret
= 0;
195 char *exp_residual
= NULL
;
198 filepath
= (strcmp("FILE", ops
->prefix
) == 0
199 || strcmp("DIR", ops
->prefix
) == 0
200 || strcmp("SCC", ops
->prefix
) == 0);
203 ret
= _krb5_expand_path_tokens(context
, residual
, filepath
, &exp_residual
);
205 ret
= _krb5_cc_allocate(context
, ops
, id
);
208 if ((*id
)->ops
->version
< KRB5_CC_OPS_VERSION_5
209 || (*id
)->ops
->resolve_2
== NULL
) {
210 ret
= (*id
)->ops
->resolve(context
, id
, exp_residual
);
212 ret
= (*id
)->ops
->resolve_2(context
, id
, exp_residual
, subsidiary
);
225 * Find and allocate a ccache in `id' from the specification in `residual'.
226 * If the ccache name doesn't contain any colon, interpret it as a file name.
228 * @param context a Kerberos context.
229 * @param name string name of a credential cache.
230 * @param id return pointer to a found credential cache.
232 * @return Return 0 or an error code. In case of an error, id is set
233 * to NULL, see krb5_get_error_message().
235 * @ingroup krb5_ccache
239 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
240 krb5_cc_resolve(krb5_context context
,
244 const krb5_cc_ops
*ops
;
245 const char *residual
= NULL
;
249 ops
= cc_get_prefix_ops(context
, name
, &residual
);
251 ops
= &krb5_fcc_ops
; /* residual will point to name */
253 return allocate_ccache(context
, ops
, residual
, NULL
, id
);
258 get_default_cc_type_win32(krb5_context context
)
264 * If the MSLSA ccache type has a principal name,
265 * use it as the default.
267 ret
= krb5_cc_resolve(context
, "MSLSA:", &id
);
269 krb5_principal princ
;
270 ret
= krb5_cc_get_principal(context
, id
, &princ
);
271 krb5_cc_close(context
, id
);
273 krb5_free_principal(context
, princ
);
279 * If the API: ccache can be resolved,
280 * use it as the default.
282 ret
= krb5_cc_resolve(context
, "API:", &id
);
284 krb5_cc_close(context
, id
);
293 get_default_cc_type(krb5_context context
, int simple
)
295 const char *def_ccname
;
296 const char *def_cctype
=
297 krb5_config_get_string_default(context
, NULL
,
298 secure_getenv("KRB5CCTYPE"),
299 "libdefaults", "default_cc_type", NULL
);
300 const char *def_cccol
=
301 krb5_config_get_string(context
, NULL
, "libdefaults",
302 "default_cc_collection", NULL
);
303 const krb5_cc_ops
*ops
;
305 if (!simple
&& (def_ccname
= krb5_cc_default_name(context
))) {
306 ops
= cc_get_prefix_ops(context
, def_ccname
, NULL
);
310 if (!def_cctype
&& def_cccol
) {
311 ops
= cc_get_prefix_ops(context
, def_cccol
, NULL
);
316 if (def_cctype
== NULL
)
317 def_cctype
= get_default_cc_type_win32(context
);
319 if (def_cctype
== NULL
)
320 def_cctype
= KRB5_DEFAULT_CCTYPE
->prefix
;
325 * Find and allocate a ccache in `id' for the subsidiary cache named by
326 * `subsidiary' in the collection named by `collection'.
328 * @param context a Kerberos context.
329 * @param cctype string name of a credential cache collection type.
330 * @param collection string name of a credential cache collection.
331 * @param subsidiary string name of a credential cache in a collection.
332 * @param id return pointer to a found credential cache.
334 * @return Return 0 or an error code. In case of an error, id is set
335 * to NULL, see krb5_get_error_message().
337 * @ingroup krb5_ccache
341 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
342 krb5_cc_resolve_sub(krb5_context context
,
344 const char *collection
,
345 const char *subsidiary
,
348 const krb5_cc_ops
*ops
= NULL
;
352 /* Get the cctype from the collection, maybe */
353 if (cctype
== NULL
&& collection
)
354 ops
= cc_get_prefix_ops(context
, collection
, &collection
);
357 ops
= cc_get_prefix_ops(context
, get_default_cc_type(context
, 0), NULL
);
360 krb5_set_error_message(context
, KRB5_CC_UNKNOWN_TYPE
,
361 N_("unknown ccache type %s", ""), cctype
);
362 return KRB5_CC_UNKNOWN_TYPE
;
365 return allocate_ccache(context
, ops
, collection
, subsidiary
, id
);
370 * Find and allocate a ccache in `id' from the specification in `residual', but
371 * specific to the given principal `principal' by using the principal name as
372 * the name of a "subsidiary" credentials cache in the collection named by
373 * `name'. If the ccache name doesn't contain any colon, interpret it as a
376 * @param context a Kerberos context.
377 * @param name string name of a credential cache.
378 * @param principal principal name of desired credentials.
379 * @param id return pointer to a found credential cache.
381 * @return Return 0 or an error code. In case of an error, id is set
382 * to NULL, see krb5_get_error_message().
384 * @ingroup krb5_ccache
387 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
388 krb5_cc_resolve_for(krb5_context context
,
391 krb5_const_principal principal
,
399 ret
= krb5_unparse_name(context
, principal
, &p
);
403 * Subsidiary components cannot have various chars in them that are used as
404 * separators. ':' is used for subsidiary separators in all ccache types
405 * except FILE, where '+' is used instead because we can't use ':' in file
406 * paths on Windows and because ':' is not in the POSIX safe set.
408 for (s
= p
; *s
; s
++) {
418 ret
= krb5_cc_resolve_sub(context
, cctype
, name
, p
, id
);
424 * Generates a new unique ccache of `type` in `id'. If `type' is NULL,
425 * the library chooses the default credential cache type. The supplied
426 * `hint' (that can be NULL) is a string that the credential cache
427 * type can use to base the name of the credential on, this is to make
428 * it easier for the user to differentiate the credentials.
430 * @return Return an error code or 0, see krb5_get_error_message().
432 * @ingroup krb5_ccache
435 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
436 krb5_cc_new_unique(krb5_context context
, const char *type
,
437 const char *hint
, krb5_ccache
*id
)
439 const krb5_cc_ops
*ops
;
443 type
= get_default_cc_type(context
, 1);
445 ops
= krb5_cc_get_prefix_ops(context
, type
);
447 krb5_set_error_message(context
, KRB5_CC_UNKNOWN_TYPE
,
448 "Credential cache type %s is unknown", type
);
449 return KRB5_CC_UNKNOWN_TYPE
;
452 ret
= _krb5_cc_allocate(context
, ops
, id
);
455 ret
= (*id
)->ops
->gen_new(context
, id
);
464 * Return the name of the ccache `id'
466 * @ingroup krb5_ccache
470 KRB5_LIB_FUNCTION
const char* KRB5_LIB_CALL
471 krb5_cc_get_name(krb5_context context
,
474 const char *name
= NULL
;
476 if (id
->ops
->version
< KRB5_CC_OPS_VERSION_5
477 || id
->ops
->get_name_2
== NULL
)
478 return id
->ops
->get_name(context
, id
);
480 (void) id
->ops
->get_name_2(context
, id
, &name
, NULL
, NULL
);
485 * Return the name of the ccache collection associated with `id'
487 * @ingroup krb5_ccache
491 KRB5_LIB_FUNCTION
const char* KRB5_LIB_CALL
492 krb5_cc_get_collection(krb5_context context
, krb5_ccache id
)
494 const char *name
= NULL
;
496 if (id
->ops
->version
< KRB5_CC_OPS_VERSION_5
497 || id
->ops
->get_name_2
== NULL
)
500 (void) id
->ops
->get_name_2(context
, id
, NULL
, &name
, NULL
);
505 * Return the name of the subsidiary ccache of `id'
507 * @ingroup krb5_ccache
511 KRB5_LIB_FUNCTION
const char* KRB5_LIB_CALL
512 krb5_cc_get_subsidiary(krb5_context context
, krb5_ccache id
)
514 const char *name
= NULL
;
516 if (id
->ops
->version
>= KRB5_CC_OPS_VERSION_5
517 && id
->ops
->get_name_2
!= NULL
)
518 (void) id
->ops
->get_name_2(context
, id
, NULL
, NULL
, &name
);
523 * Return the type of the ccache `id'.
525 * @ingroup krb5_ccache
529 KRB5_LIB_FUNCTION
const char* KRB5_LIB_CALL
530 krb5_cc_get_type(krb5_context context
,
533 return id
->ops
->prefix
;
537 * Return the complete resolvable name the cache
539 * @param context a Kerberos context
540 * @param id return pointer to a found credential cache
541 * @param str the returned name of a credential cache, free with krb5_xfree()
543 * @return Returns 0 or an error (and then *str is set to NULL).
545 * @ingroup krb5_ccache
549 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
550 krb5_cc_get_full_name(krb5_context context
,
554 const char *type
, *name
;
558 type
= krb5_cc_get_type(context
, id
);
560 krb5_set_error_message(context
, KRB5_CC_UNKNOWN_TYPE
,
561 "cache has no name of type");
562 return KRB5_CC_UNKNOWN_TYPE
;
565 name
= krb5_cc_get_name(context
, id
);
567 krb5_set_error_message(context
, KRB5_CC_BADNAME
,
568 "cache of type %s has no name", type
);
569 return KRB5_CC_BADNAME
;
572 if (asprintf(str
, "%s:%s", type
, name
) == -1) {
574 return krb5_enomem(context
);
580 * Return krb5_cc_ops of a the ccache `id'.
582 * @ingroup krb5_ccache
586 KRB5_LIB_FUNCTION
const krb5_cc_ops
* KRB5_LIB_CALL
587 krb5_cc_get_ops(krb5_context context
, krb5_ccache id
)
593 * Expand variables in `str' into `res'
596 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
597 _krb5_expand_default_cc_name(krb5_context context
, const char *str
, char **res
)
601 filepath
= (strncmp("FILE:", str
, 5) == 0
602 || strncmp("DIR:", str
, 4) == 0
603 || strncmp("SCC:", str
, 4) == 0);
605 return _krb5_expand_path_tokens(context
, str
, filepath
, res
);
609 * Return non-zero if envirnoment that will determine default krb5cc
614 environment_changed(krb5_context context
)
618 /* if the cc name was set, don't change it */
619 if (context
->default_cc_name_set
)
622 /* XXX performance: always ask KCM/API if default name has changed */
623 if (context
->default_cc_name
&&
624 (strncmp(context
->default_cc_name
, "KCM:", 4) == 0 ||
625 strncmp(context
->default_cc_name
, "API:", 4) == 0))
628 e
= secure_getenv("KRB5CCNAME");
630 if (context
->default_cc_name_env
) {
631 free(context
->default_cc_name_env
);
632 context
->default_cc_name_env
= NULL
;
636 if (context
->default_cc_name_env
== NULL
)
638 if (strcmp(e
, context
->default_cc_name_env
) != 0)
645 * Switch the default default credential cache for a specific
646 * credcache type (and name for some implementations).
648 * @return Return an error code or 0, see krb5_get_error_message().
650 * @ingroup krb5_ccache
653 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
654 krb5_cc_switch(krb5_context context
, krb5_ccache id
)
657 _krb5_set_default_cc_name_to_registry(context
, id
);
660 if (id
->ops
->version
== KRB5_CC_OPS_VERSION_0
661 || id
->ops
->set_default
== NULL
)
664 return (*id
->ops
->set_default
)(context
, id
);
668 * Return true if the default credential cache support switch
670 * @ingroup krb5_ccache
673 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
674 krb5_cc_support_switch(krb5_context context
, const char *type
)
676 const krb5_cc_ops
*ops
;
678 ops
= krb5_cc_get_prefix_ops(context
, type
);
679 if (ops
&& ops
->version
> KRB5_CC_OPS_VERSION_0
&& ops
->set_default
)
685 * Set the default cc name for `context' to `name'.
687 * @ingroup krb5_ccache
690 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
691 krb5_cc_set_default_name(krb5_context context
, const char *name
)
693 krb5_error_code ret
= 0;
699 if ((e
= secure_getenv("KRB5CCNAME"))) {
700 if ((p
= strdup(e
)) == NULL
)
701 return krb5_enomem(context
);
703 free(context
->default_cc_name_env
);
704 context
->default_cc_name_env
= p
;
706 if ((p
= strdup(e
)) == NULL
)
707 return krb5_enomem(context
);
710 * We're resetting the default ccache name. Recall that we got
711 * this from the environment, which might change.
713 context
->default_cc_name_set
= 0;
714 } else if ((e
= krb5_cc_configured_default_name(context
))) {
715 if ((p
= strdup(e
)) == NULL
)
716 return krb5_enomem(context
);
719 * Since $KRB5CCNAME was not set, and since we got the default
720 * ccache name from configuration, we'll not want
721 * environment_changed() to return true to avoid re-doing the
722 * krb5_cc_configured_default_name() call unnecessarily.
724 * XXX Perhaps if we got the ccache name from the registry then
725 * we'd want to recheck it? If so we might need an indication
726 * from krb5_cc_configured_default_name() about that!
728 context
->default_cc_name_set
= 1;
731 int filepath
= (strncmp("FILE:", name
, 5) == 0 ||
732 strncmp("DIR:", name
, 4) == 0 ||
733 strncmp("SCC:", name
, 4) == 0);
735 ret
= _krb5_expand_path_tokens(context
, name
, filepath
, &p
);
740 * Since the default ccache name was set explicitly, we won't want
741 * environment_changed() to return true until the default ccache name
744 context
->default_cc_name_set
= 1;
747 free(context
->default_cc_name
);
748 context
->default_cc_name
= p
;
753 * Return a pointer to a context static string containing the default
756 * @return String to the default credential cache name.
758 * @ingroup krb5_ccache
762 KRB5_LIB_FUNCTION
const char* KRB5_LIB_CALL
763 krb5_cc_default_name(krb5_context context
)
765 if (context
->default_cc_name
== NULL
|| environment_changed(context
))
766 krb5_cc_set_default_name(context
, NULL
);
768 return context
->default_cc_name
;
771 KRB5_LIB_FUNCTION
const char * KRB5_LIB_CALL
772 krb5_cc_configured_default_name(krb5_context context
)
774 krb5_error_code ret
= 0;
780 const krb5_cc_ops
*ops
;
782 if (context
->configured_default_cc_name
)
783 return context
->configured_default_cc_name
;
786 if ((expanded
= _krb5_get_default_cc_name_from_registry(context
)))
787 return context
->configured_default_cc_name
= expanded
;
790 /* If there's a configured default, expand the tokens and use it */
791 cfg
= krb5_config_get_string(context
, NULL
, "libdefaults",
792 "default_cc_name", NULL
);
794 cfg
= krb5_config_get_string(context
, NULL
, "libdefaults",
795 "default_ccache_name", NULL
);
797 ret
= _krb5_expand_default_cc_name(context
, cfg
, &expanded
);
799 krb5_set_error_message(context
, ret
,
800 "token expansion failed for %s", cfg
);
803 return context
->configured_default_cc_name
= expanded
;
806 /* Else try a configured default ccache type's default */
807 cfg
= get_default_cc_type(context
, 1);
808 if ((ops
= krb5_cc_get_prefix_ops(context
, cfg
)) == NULL
) {
809 krb5_set_error_message(context
, KRB5_CC_UNKNOWN_TYPE
,
810 "unknown configured credential cache "
815 /* The get_default_name() method expands any tokens */
816 ret
= (*ops
->get_default_name
)(context
, &expanded
);
818 krb5_set_error_message(context
, ret
, "failed to find a default "
819 "ccache for default ccache type %s", cfg
);
822 return context
->configured_default_cc_name
= expanded
;
825 KRB5_LIB_FUNCTION
char * KRB5_LIB_CALL
826 krb5_cccol_get_default_ccname(krb5_context context
)
828 const char *cfg
= get_default_cc_type(context
, 1);
829 char *cccol_default_ccname
;
830 const krb5_cc_ops
*ops
= krb5_cc_get_prefix_ops(context
, cfg
);
832 (void) (*ops
->get_default_name
)(context
, &cccol_default_ccname
);
833 return cccol_default_ccname
;
837 * Open the default ccache in `id'.
839 * @return Return an error code or 0, see krb5_get_error_message().
841 * @ingroup krb5_ccache
844 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
845 krb5_cc_default(krb5_context context
,
848 const char *p
= krb5_cc_default_name(context
);
852 return krb5_enomem(context
);
853 return krb5_cc_resolve(context
, p
, id
);
857 * Open the named subsidiary cache from the default ccache collection in `id'.
859 * @return Return an error code or 0, see krb5_get_error_message().
861 * @ingroup krb5_ccache
864 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
865 krb5_cc_default_sub(krb5_context context
,
866 const char *subsidiary
,
869 return krb5_cc_resolve_sub(context
, get_default_cc_type(context
, 0), NULL
,
874 * Open the default ccache in `id' that corresponds to the given principal.
876 * @return Return an error code or 0, see krb5_get_error_message().
878 * @ingroup krb5_ccache
881 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
882 krb5_cc_default_for(krb5_context context
,
883 krb5_const_principal principal
,
886 return krb5_cc_resolve_for(context
, get_default_cc_type(context
, 0), NULL
,
891 * Create a new ccache in `id' for `primary_principal'.
893 * @return Return an error code or 0, see krb5_get_error_message().
895 * @ingroup krb5_ccache
899 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
900 krb5_cc_initialize(krb5_context context
,
902 krb5_principal primary_principal
)
906 ret
= (*id
->ops
->init
)(context
, id
, primary_principal
);
908 id
->cc_kx509_done
= 0;
909 id
->cc_initialized
= 1;
910 id
->cc_need_start_realm
= 1;
911 id
->cc_start_tgt_stored
= 0;
918 * Remove the ccache `id'.
920 * @return Return an error code or 0, see krb5_get_error_message().
922 * @ingroup krb5_ccache
926 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
927 krb5_cc_destroy(krb5_context context
,
930 krb5_error_code ret2
= 0;
935 * Destroy associated hx509 PKIX credential store created by krb5_kx509*().
937 if (krb5_cc_get_config(context
, id
, NULL
, "kx509store", &d
) == 0) {
940 if ((name
= strndup(d
.data
, d
.length
)) == NULL
) {
941 ret2
= krb5_enomem(context
);
944 ret
= hx509_certs_init(context
->hx509ctx
, name
, 0, NULL
, &certs
);
946 ret2
= hx509_certs_destroy(context
->hx509ctx
, &certs
);
948 hx509_certs_free(&certs
);
953 ret
= (*id
->ops
->destroy
)(context
, id
);
954 (void) krb5_cc_close(context
, id
);
955 return ret
? ret
: ret2
;
959 * Stop using the ccache `id' and free the related resources.
961 * @return Return an error code or 0, see krb5_get_error_message().
963 * @ingroup krb5_ccache
967 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
968 krb5_cc_close(krb5_context context
,
977 * We want to automatically acquire a PKIX credential using kx509.
979 * This can be slow if we're generating an RSA key. Plus it means talking
982 * We only want to do this when:
984 * - krb5_cc_initialize() was called on this ccache handle,
985 * - a start TGT was stored (actually, a cross-realm TGT would do),
989 * - we aren't creating a gss_cred_id_t for a delegated credential.
991 * We only have a heuristic for the last condition: that `id' is not a
992 * MEMORY ccache, which is what's used for delegated credentials.
994 * We really only want to do this when storing a credential in a user's
995 * default ccache, but we leave it to krb5_kx509() to do that check.
997 * XXX Perhaps we should do what krb5_kx509() does here, and just call
998 * krb5_kx509_ext() (renamed to krb5_kx509()). Then we wouldn't need
999 * the delegated cred handle heuristic.
1001 if (id
->cc_initialized
&& id
->cc_start_tgt_stored
&& !id
->cc_kx509_done
&&
1002 strcmp("MEMORY", krb5_cc_get_type(context
, id
)) != 0) {
1003 krb5_boolean enabled
;
1005 krb5_appdefault_boolean(context
, NULL
, NULL
, "enable_kx509", FALSE
,
1008 _krb5_debug(context
, 2, "attempting to fetch a certificate using "
1010 ret
= krb5_kx509(context
, id
, NULL
);
1012 _krb5_debug(context
, 2, "failed to fetch a certificate");
1014 _krb5_debug(context
, 2, "fetched a certificate");
1018 ret
= (*id
->ops
->close
)(context
, id
);
1024 * Store `creds' in the ccache `id'.
1026 * @return Return an error code or 0, see krb5_get_error_message().
1028 * @ingroup krb5_ccache
1032 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1033 krb5_cc_store_cred(krb5_context context
,
1037 krb5_error_code ret
;
1039 const char *cfg
= "";
1041 /* Automatic cc_config-setting and other actions */
1042 if (krb5_principal_get_num_comp(context
, creds
->server
) > 1 &&
1043 krb5_is_config_principal(context
, creds
->server
))
1044 cfg
= krb5_principal_get_comp_string(context
, creds
->server
, 1);
1046 if (id
->cc_initialized
&& !id
->cc_need_start_realm
&&
1047 strcmp(cfg
, "start_realm") == 0)
1050 ret
= (*id
->ops
->store
)(context
, id
, creds
);
1054 if (id
->cc_initialized
&& !id
->cc_start_tgt_stored
&&
1055 id
->cc_need_start_realm
&&
1056 krb5_principal_is_root_krbtgt(context
, creds
->server
)) {
1057 /* Mark the first root TGT's realm as the start realm */
1058 id
->cc_start_tgt_stored
= 1;
1059 realm
.length
= strlen(creds
->server
->realm
);
1060 realm
.data
= creds
->server
->realm
;
1061 (void) krb5_cc_set_config(context
, id
, NULL
, "start_realm", &realm
);
1062 id
->cc_need_start_realm
= 0;
1063 } else if (id
->cc_initialized
&& id
->cc_start_tgt_stored
&&
1064 !id
->cc_kx509_done
&& strcmp(cfg
, "kx509cert") == 0) {
1066 * Do not attempt kx509 at cc close time -- we're copying a ccache and
1067 * we've already got a cert (and private key).
1069 id
->cc_kx509_done
= 1;
1070 } else if (id
->cc_initialized
&& id
->cc_start_tgt_stored
&&
1071 !id
->cc_kx509_done
&& strcmp(cfg
, "kx509_service_status") == 0) {
1073 * Do not attempt kx509 at cc close time -- we're copying a ccache and
1074 * we know the kx509 service is not available.
1076 id
->cc_kx509_done
= 1;
1077 } else if (id
->cc_initialized
&& strcmp(cfg
, "start_realm") == 0) {
1079 * If the caller is storing a start_realm ccconfig, then stop looking
1080 * for root TGTs to mark as the start_realm.
1082 * By honoring any start_realm cc config stored, we interop both, with
1083 * ccache implementations that don't preserve insertion order, and
1084 * Kerberos implementations that store this cc config before the TGT.
1086 id
->cc_need_start_realm
= 0;
1092 * Retrieve the credential identified by `mcreds' (and `whichfields')
1093 * from `id' in `creds'. 'creds' must be free by the caller using
1094 * krb5_free_cred_contents.
1096 * @param context A Kerberos 5 context
1097 * @param id a Kerberos 5 credential cache
1098 * @param whichfields what fields to use for matching credentials, same
1099 * flags as whichfields in krb5_compare_creds()
1100 * @param mcreds template credential to use for comparing
1101 * @param creds returned credential, free with krb5_free_cred_contents()
1103 * @return Return an error code or 0, see krb5_get_error_message().
1105 * @ingroup krb5_ccache
1109 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1110 krb5_cc_retrieve_cred(krb5_context context
,
1112 krb5_flags whichfields
,
1113 const krb5_creds
*mcreds
,
1116 krb5_error_code ret
;
1117 krb5_cc_cursor cursor
;
1119 if (id
->ops
->retrieve
!= NULL
) {
1120 return (*id
->ops
->retrieve
)(context
, id
, whichfields
,
1124 ret
= krb5_cc_start_seq_get(context
, id
, &cursor
);
1127 while((ret
= krb5_cc_next_cred(context
, id
, &cursor
, creds
)) == 0){
1128 if(krb5_compare_creds(context
, whichfields
, mcreds
, creds
)){
1132 krb5_free_cred_contents (context
, creds
);
1134 krb5_cc_end_seq_get(context
, id
, &cursor
);
1139 * Return the principal of `id' in `principal'.
1141 * @return Return an error code or 0, see krb5_get_error_message().
1143 * @ingroup krb5_ccache
1147 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1148 krb5_cc_get_principal(krb5_context context
,
1150 krb5_principal
*principal
)
1152 return (*id
->ops
->get_princ
)(context
, id
, principal
);
1156 * Start iterating over `id', `cursor' is initialized to the
1157 * beginning. Caller must free the cursor with krb5_cc_end_seq_get().
1159 * @return Return an error code or 0, see krb5_get_error_message().
1161 * @ingroup krb5_ccache
1165 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1166 krb5_cc_start_seq_get (krb5_context context
,
1167 const krb5_ccache id
,
1168 krb5_cc_cursor
*cursor
)
1170 return (*id
->ops
->get_first
)(context
, id
, cursor
);
1174 * Retrieve the next cred pointed to by (`id', `cursor') in `creds'
1175 * and advance `cursor'.
1177 * @return Return an error code or 0, see krb5_get_error_message().
1179 * @ingroup krb5_ccache
1183 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1184 krb5_cc_next_cred (krb5_context context
,
1185 const krb5_ccache id
,
1186 krb5_cc_cursor
*cursor
,
1189 return (*id
->ops
->get_next
)(context
, id
, cursor
, creds
);
1193 * Destroy the cursor `cursor'.
1195 * @ingroup krb5_ccache
1199 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1200 krb5_cc_end_seq_get (krb5_context context
,
1201 const krb5_ccache id
,
1202 krb5_cc_cursor
*cursor
)
1204 return (*id
->ops
->end_get
)(context
, id
, cursor
);
1208 * Remove the credential identified by `cred', `which' from `id'.
1210 * @ingroup krb5_ccache
1214 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1215 krb5_cc_remove_cred(krb5_context context
,
1220 if(id
->ops
->remove_cred
== NULL
) {
1221 krb5_set_error_message(context
,
1223 "ccache %s does not support remove_cred",
1225 return EACCES
; /* XXX */
1227 return (*id
->ops
->remove_cred
)(context
, id
, which
, cred
);
1231 * Set the flags of `id' to `flags'.
1233 * @ingroup krb5_ccache
1237 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1238 krb5_cc_set_flags(krb5_context context
,
1242 return (*id
->ops
->set_flags
)(context
, id
, flags
);
1246 * Get the flags of `id', store them in `flags'.
1248 * @ingroup krb5_ccache
1251 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1252 krb5_cc_get_flags(krb5_context context
,
1261 * Copy the contents of `from' to `to' if the given match function
1264 * @param context A Kerberos 5 context.
1265 * @param from the cache to copy data from.
1266 * @param to the cache to copy data to.
1267 * @param match a match function that should return TRUE if cred argument should be copied, if NULL, all credentials are copied.
1268 * @param matchctx context passed to match function.
1269 * @param matched set to true if there was a credential that matched, may be NULL.
1271 * @return Return an error code or 0, see krb5_get_error_message().
1273 * @ingroup krb5_ccache
1276 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1277 krb5_cc_copy_match_f(krb5_context context
,
1278 const krb5_ccache from
,
1280 krb5_boolean (*match
)(krb5_context
, void *, const krb5_creds
*),
1282 unsigned int *matched
)
1284 krb5_error_code ret
;
1285 krb5_cc_cursor cursor
;
1287 krb5_principal princ
;
1292 ret
= krb5_cc_get_principal(context
, from
, &princ
);
1295 ret
= krb5_cc_initialize(context
, to
, princ
);
1297 krb5_free_principal(context
, princ
);
1300 ret
= krb5_cc_start_seq_get(context
, from
, &cursor
);
1302 krb5_free_principal(context
, princ
);
1306 while ((ret
= krb5_cc_next_cred(context
, from
, &cursor
, &cred
)) == 0) {
1307 if (match
== NULL
|| (*match
)(context
, matchctx
, &cred
)) {
1310 ret
= krb5_cc_store_cred(context
, to
, &cred
);
1314 krb5_free_cred_contents(context
, &cred
);
1316 krb5_cc_end_seq_get(context
, from
, &cursor
);
1317 krb5_free_principal(context
, princ
);
1318 if (ret
== KRB5_CC_END
)
1324 * Just like krb5_cc_copy_match_f(), but copy everything.
1326 * @ingroup @krb5_ccache
1329 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1330 krb5_cc_copy_cache(krb5_context context
,
1331 const krb5_ccache from
,
1334 return krb5_cc_copy_match_f(context
, from
, to
, NULL
, NULL
, NULL
);
1338 * Return the version of `id'.
1340 * @ingroup krb5_ccache
1344 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1345 krb5_cc_get_version(krb5_context context
,
1346 const krb5_ccache id
)
1348 if(id
->ops
->get_version
)
1349 return (*id
->ops
->get_version
)(context
, id
);
1355 * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred
1357 * @ingroup krb5_ccache
1361 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
1362 krb5_cc_clear_mcred(krb5_creds
*mcred
)
1364 memset(mcred
, 0, sizeof(*mcred
));
1368 * Get the cc ops that is registered in `context' to handle the
1369 * prefix. prefix can be a complete credential cache name or a
1370 * prefix, the function will only use part up to the first colon (:)
1371 * if there is one. If prefix the argument is NULL, the default ccache
1372 * implemtation is returned.
1374 * @return Returns NULL if ops not found.
1376 * @ingroup krb5_ccache
1380 KRB5_LIB_FUNCTION
const krb5_cc_ops
* KRB5_LIB_CALL
1381 krb5_cc_get_prefix_ops(krb5_context context
, const char *prefix
)
1383 return cc_get_prefix_ops(context
, prefix
, NULL
);
1387 * Get the cc ops that is registered in `context' to handle the
1388 * prefix. prefix can be a complete credential cache name or a
1389 * prefix, the function will only use part up to the first colon (:)
1390 * if there is one. If prefix the argument is NULL, the default ccache
1391 * implementation is returned.
1393 * If residual is non-NULL, it is set to the residual component of
1394 * prefix (if present) or the prefix itself.
1396 * @return Returns NULL if ops not found.
1398 * @ingroup krb5_ccache
1402 static const krb5_cc_ops
*
1403 cc_get_prefix_ops(krb5_context context
,
1405 const char **residual
)
1413 return KRB5_DEFAULT_CCTYPE
;
1415 /* Is absolute path? Or UNC path? */
1416 if (ISPATHSEP(prefix
[0]))
1417 return &krb5_fcc_ops
;
1420 /* Is drive letter? */
1421 if (isalpha((unsigned char)prefix
[0]) && prefix
[1] == ':')
1422 return &krb5_fcc_ops
;
1425 for(i
= 0; i
< context
->num_cc_ops
&& context
->cc_ops
[i
]->prefix
; i
++) {
1426 size_t prefix_len
= strlen(context
->cc_ops
[i
]->prefix
);
1428 if (strncmp(context
->cc_ops
[i
]->prefix
, prefix
, prefix_len
) == 0 &&
1429 (prefix
[prefix_len
] == ':' || prefix
[prefix_len
] == '\0')) {
1431 if (prefix
[prefix_len
] == ':' && prefix
[prefix_len
+ 1] != '\0')
1432 *residual
= &prefix
[prefix_len
+ 1];
1437 return context
->cc_ops
[i
];
1444 struct krb5_cc_cache_cursor_data
{
1445 const krb5_cc_ops
*ops
;
1446 krb5_cc_cursor cursor
;
1450 * Start iterating over all caches of specified type. See also
1451 * krb5_cccol_cursor_new().
1453 * @param context A Kerberos 5 context
1454 * @param type optional type to iterate over, if NULL, the default cache is used.
1455 * @param cursor cursor should be freed with krb5_cc_cache_end_seq_get().
1457 * @return Return an error code or 0, see krb5_get_error_message().
1459 * @ingroup krb5_ccache
1463 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1464 krb5_cc_cache_get_first (krb5_context context
,
1466 krb5_cc_cache_cursor
*cursor
)
1468 const krb5_cc_ops
*ops
;
1469 krb5_error_code ret
;
1472 type
= krb5_cc_default_name(context
);
1474 ops
= krb5_cc_get_prefix_ops(context
, type
);
1476 krb5_set_error_message(context
, KRB5_CC_UNKNOWN_TYPE
,
1477 "Unknown type \"%s\" when iterating "
1478 "trying to iterate the credential caches", type
);
1479 return KRB5_CC_UNKNOWN_TYPE
;
1482 if (ops
->get_cache_first
== NULL
) {
1483 krb5_set_error_message(context
, KRB5_CC_NOSUPP
,
1484 N_("Credential cache type %s doesn't support "
1485 "iterations over caches", "type"),
1487 return KRB5_CC_NOSUPP
;
1490 *cursor
= calloc(1, sizeof(**cursor
));
1491 if (*cursor
== NULL
)
1492 return krb5_enomem(context
);
1494 (*cursor
)->ops
= ops
;
1496 ret
= ops
->get_cache_first(context
, &(*cursor
)->cursor
);
1505 * Retrieve the next cache pointed to by (`cursor') in `id'
1506 * and advance `cursor'.
1508 * @param context A Kerberos 5 context
1509 * @param cursor the iterator cursor, returned by krb5_cc_cache_get_first()
1510 * @param id next ccache
1512 * @return Return 0 or an error code. Returns KRB5_CC_END when the end
1513 * of caches is reached, see krb5_get_error_message().
1515 * @ingroup krb5_ccache
1519 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1520 krb5_cc_cache_next (krb5_context context
,
1521 krb5_cc_cache_cursor cursor
,
1524 return cursor
->ops
->get_cache_next(context
, cursor
->cursor
, id
);
1528 * Destroy the cursor `cursor'.
1530 * @return Return an error code or 0, see krb5_get_error_message().
1532 * @ingroup krb5_ccache
1536 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1537 krb5_cc_cache_end_seq_get (krb5_context context
,
1538 krb5_cc_cache_cursor cursor
)
1540 krb5_error_code ret
;
1541 ret
= cursor
->ops
->end_cache_get(context
, cursor
->cursor
);
1548 * Search for a matching credential cache that have the
1549 * `principal' as the default principal. On success, `id' needs to be
1550 * freed with krb5_cc_close() or krb5_cc_destroy().
1552 * @param context A Kerberos 5 context
1553 * @param client The principal to search for
1554 * @param id the returned credential cache
1556 * @return On failure, error code is returned and `id' is set to NULL.
1558 * @ingroup krb5_ccache
1562 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1563 krb5_cc_cache_match (krb5_context context
,
1564 krb5_principal client
,
1567 krb5_cccol_cursor cursor
;
1568 krb5_error_code ret
;
1569 krb5_ccache cache
= NULL
;
1570 krb5_ccache expired_match
= NULL
;
1574 ret
= krb5_cccol_cursor_new (context
, &cursor
);
1578 while (krb5_cccol_cursor_next(context
, cursor
, &cache
) == 0 && cache
!= NULL
) {
1579 krb5_principal principal
;
1583 ret
= krb5_cc_get_principal(context
, cache
, &principal
);
1587 if (client
->name
.name_string
.len
== 0)
1588 match
= (strcmp(client
->realm
, principal
->realm
) == 0);
1590 match
= krb5_principal_compare(context
, principal
, client
);
1591 krb5_free_principal(context
, principal
);
1596 if (expired_match
== NULL
&&
1597 (krb5_cc_get_lifetime(context
, cache
, &lifetime
) != 0 || lifetime
== 0)) {
1598 expired_match
= cache
;
1606 krb5_cc_close(context
, cache
);
1610 krb5_cccol_cursor_free(context
, &cursor
);
1612 if (cache
== NULL
&& expired_match
) {
1613 cache
= expired_match
;
1614 expired_match
= NULL
;
1615 } else if (expired_match
) {
1616 krb5_cc_close(context
, expired_match
);
1617 } else if (cache
== NULL
) {
1620 (void) krb5_unparse_name(context
, client
, &str
);
1621 krb5_set_error_message(context
, KRB5_CC_NOTFOUND
,
1622 N_("Principal %s not found in any "
1623 "credential cache", ""),
1624 str
? str
: "<out of memory>");
1627 return KRB5_CC_NOTFOUND
;
1636 * Move the content from one credential cache to another. The
1637 * operation is an atomic switch.
1639 * @param context a Kerberos context
1640 * @param from the credential cache to move the content from
1641 * @param to the credential cache to move the content to
1643 * @return On sucess, from is destroyed and closed. On failure, error code is
1644 * returned and from and to are both still allocated; see
1645 * krb5_get_error_message().
1647 * @ingroup krb5_ccache
1650 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1651 krb5_cc_move(krb5_context context
, krb5_ccache from
, krb5_ccache to
)
1653 krb5_error_code ret
= ENOTSUP
;
1654 krb5_principal princ
= NULL
;
1656 if (to
->ops
->move
&&
1657 strcmp(from
->ops
->prefix
, to
->ops
->prefix
) == 0) {
1659 * NOTE: to->ops->move() is expected to call
1660 * krb5_cc_destroy(context, from) on success.
1662 ret
= (*to
->ops
->move
)(context
, from
, to
);
1665 if (ret
!= EXDEV
&& ret
!= ENOTSUP
&& ret
!= KRB5_CC_NOSUPP
&&
1666 ret
!= KRB5_FCC_INTERNAL
)
1668 /* Fallback to high-level copy */
1669 } /* Else high-level copy */
1672 * Initialize destination, copy the source's contents to the destination,
1673 * then destroy the source on success.
1675 * It'd be nice if we could destroy any half-built destination if the copy
1676 * fails, but the interface is not documented as doing so.
1678 ret
= krb5_cc_get_principal(context
, from
, &princ
);
1680 ret
= krb5_cc_initialize(context
, to
, princ
);
1681 krb5_free_principal(context
, princ
);
1683 ret
= krb5_cc_copy_cache(context
, from
, to
);
1685 krb5_cc_destroy(context
, from
);
1689 #define KRB5_CONF_NAME "krb5_ccache_conf_data"
1690 #define KRB5_REALM_NAME "X-CACHECONF:"
1692 static krb5_error_code
1693 build_conf_principals(krb5_context context
, krb5_ccache id
,
1694 krb5_const_principal principal
,
1695 const char *name
, krb5_creds
*cred
)
1697 krb5_principal client
;
1698 krb5_error_code ret
;
1701 memset(cred
, 0, sizeof(*cred
));
1703 ret
= krb5_cc_get_principal(context
, id
, &client
);
1708 ret
= krb5_unparse_name(context
, principal
, &pname
);
1713 ret
= krb5_make_principal(context
, &cred
->server
,
1715 KRB5_CONF_NAME
, name
, pname
, NULL
);
1718 krb5_free_principal(context
, client
);
1721 ret
= krb5_copy_principal(context
, client
, &cred
->client
);
1722 krb5_free_principal(context
, client
);
1727 * Return TRUE (non zero) if the principal is a configuration
1728 * principal (generated part of krb5_cc_set_config()). Returns FALSE
1729 * (zero) if not a configuration principal.
1731 * @param context a Kerberos context
1732 * @param principal principal to check if it a configuration principal
1734 * @ingroup krb5_ccache
1737 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1738 krb5_is_config_principal(krb5_context context
,
1739 krb5_const_principal principal
)
1741 if (strcmp(principal
->realm
, KRB5_REALM_NAME
) != 0)
1744 if (principal
->name
.name_string
.len
== 0 ||
1745 strcmp(principal
->name
.name_string
.val
[0], KRB5_CONF_NAME
) != 0)
1752 * Store some configuration for the credential cache in the cache.
1753 * Existing configuration under the same name is over-written.
1755 * @param context a Kerberos context
1756 * @param id the credential cache to store the data for
1757 * @param principal configuration for a specific principal, if
1758 * NULL, global for the whole cache.
1759 * @param name name under which the configuraion is stored.
1760 * @param data data to store, if NULL, configure is removed.
1762 * @ingroup krb5_ccache
1765 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1766 krb5_cc_set_config(krb5_context context
, krb5_ccache id
,
1767 krb5_const_principal principal
,
1768 const char *name
, krb5_data
*data
)
1770 krb5_error_code ret
;
1773 ret
= build_conf_principals(context
, id
, principal
, name
, &cred
);
1777 /* Remove old configuration */
1778 ret
= krb5_cc_remove_cred(context
, id
, 0, &cred
);
1779 if (ret
&& ret
!= KRB5_CC_NOTFOUND
&& ret
!= KRB5_CC_NOSUPP
&&
1780 ret
!= KRB5_FCC_INTERNAL
)
1784 /* not that anyone care when this expire */
1785 cred
.times
.authtime
= time(NULL
);
1786 cred
.times
.endtime
= cred
.times
.authtime
+ 3600 * 24 * 30;
1788 ret
= krb5_data_copy(&cred
.ticket
, data
->data
, data
->length
);
1792 ret
= krb5_cc_store_cred(context
, id
, &cred
);
1796 krb5_free_cred_contents (context
, &cred
);
1801 * Get some configuration for the credential cache in the cache.
1803 * @param context a Kerberos context
1804 * @param id the credential cache to store the data for
1805 * @param principal configuration for a specific principal, if
1806 * NULL, global for the whole cache.
1807 * @param name name under which the configuraion is stored.
1808 * @param data data to fetched, free with krb5_data_free()
1809 * @return 0 on success, KRB5_CC_NOTFOUND or KRB5_CC_END if not found,
1810 * or other system error.
1812 * @ingroup krb5_ccache
1816 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1817 krb5_cc_get_config(krb5_context context
, krb5_ccache id
,
1818 krb5_const_principal principal
,
1819 const char *name
, krb5_data
*data
)
1821 krb5_creds mcred
, cred
;
1822 krb5_error_code ret
;
1824 memset(&cred
, 0, sizeof(cred
));
1825 krb5_data_zero(data
);
1827 ret
= build_conf_principals(context
, id
, principal
, name
, &mcred
);
1831 ret
= krb5_cc_retrieve_cred(context
, id
, 0, &mcred
, &cred
);
1835 ret
= krb5_data_copy(data
, cred
.ticket
.data
, cred
.ticket
.length
);
1838 krb5_free_cred_contents (context
, &cred
);
1839 krb5_free_cred_contents (context
, &mcred
);
1847 struct krb5_cccol_cursor_data
{
1849 krb5_cc_cache_cursor cursor
;
1853 * Get a new cache interation cursor that will interate over all
1854 * credentials caches independent of type.
1856 * @param context a Kerberos context
1857 * @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free().
1859 * @return Returns 0 or and error code, see krb5_get_error_message().
1861 * @ingroup krb5_ccache
1864 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1865 krb5_cccol_cursor_new(krb5_context context
, krb5_cccol_cursor
*cursor
)
1867 *cursor
= calloc(1, sizeof(**cursor
));
1868 if (*cursor
== NULL
)
1869 return krb5_enomem(context
);
1871 (*cursor
)->cursor
= NULL
;
1877 * Get next credential cache from the iteration.
1879 * @param context A Kerberos 5 context
1880 * @param cursor the iteration cursor
1881 * @param cache the returned cursor, pointer is set to NULL on failure
1882 * and a cache on success. The returned cache needs to be freed
1883 * with krb5_cc_close() or destroyed with krb5_cc_destroy().
1884 * MIT Kerberos behavies slightly diffrent and sets cache to NULL
1885 * when all caches are iterated over and return 0.
1887 * @return Return 0 or and error, KRB5_CC_END is returned at the end
1888 * of iteration. See krb5_get_error_message().
1890 * @ingroup krb5_ccache
1894 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1895 krb5_cccol_cursor_next(krb5_context context
, krb5_cccol_cursor cursor
,
1898 krb5_error_code ret
= 0;
1902 while (cursor
->idx
< context
->num_cc_ops
) {
1904 if (cursor
->cursor
== NULL
) {
1905 ret
= krb5_cc_cache_get_first (context
,
1906 context
->cc_ops
[cursor
->idx
]->prefix
,
1913 ret
= krb5_cc_cache_next(context
, cursor
->cursor
, cache
);
1917 krb5_cc_cache_end_seq_get(context
, cursor
->cursor
);
1918 cursor
->cursor
= NULL
;
1919 if (ret
!= KRB5_CC_END
)
1924 if (cursor
->idx
>= context
->num_cc_ops
) {
1925 krb5_set_error_message(context
, KRB5_CC_END
,
1926 N_("Reached end of credential caches", ""));
1934 * End an iteration and free all resources, can be done before end is reached.
1936 * @param context A Kerberos 5 context
1937 * @param cursor the iteration cursor to be freed.
1939 * @return Return 0 or and error, KRB5_CC_END is returned at the end
1940 * of iteration. See krb5_get_error_message().
1942 * @ingroup krb5_ccache
1945 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1946 krb5_cccol_cursor_free(krb5_context context
, krb5_cccol_cursor
*cursor
)
1948 krb5_cccol_cursor c
= *cursor
;
1953 krb5_cc_cache_end_seq_get(context
, c
->cursor
);
1960 * Return the last time the credential cache was modified.
1962 * @param context A Kerberos 5 context
1963 * @param id The credential cache to probe
1964 * @param mtime the last modification time, set to 0 on error.
1966 * @return Return 0 or and error. See krb5_get_error_message().
1968 * @ingroup krb5_ccache
1972 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1973 krb5_cc_last_change_time(krb5_context context
,
1975 krb5_timestamp
*mtime
)
1979 if (id
->ops
->version
< KRB5_CC_OPS_VERSION_2
1980 || id
->ops
->lastchange
== NULL
)
1981 return KRB5_CC_NOSUPP
;
1983 return (*id
->ops
->lastchange
)(context
, id
, mtime
);
1987 * Return the last modfication time for a cache collection. The query
1988 * can be limited to a specific cache type. If the function return 0
1989 * and mtime is 0, there was no credentials in the caches.
1991 * @param context A Kerberos 5 context
1992 * @param type The credential cache to probe, if NULL, all type are traversed.
1993 * @param mtime the last modification time, set to 0 on error.
1995 * @return Return 0 or and error. See krb5_get_error_message().
1997 * @ingroup krb5_ccache
2000 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2001 krb5_cccol_last_change_time(krb5_context context
,
2003 krb5_timestamp
*mtime
)
2005 krb5_cccol_cursor cursor
;
2006 krb5_error_code ret
;
2008 krb5_timestamp t
= 0;
2012 ret
= krb5_cccol_cursor_new (context
, &cursor
);
2016 while (krb5_cccol_cursor_next(context
, cursor
, &id
) == 0 && id
!= NULL
) {
2018 if (type
&& strcmp(krb5_cc_get_type(context
, id
), type
) != 0)
2021 ret
= krb5_cc_last_change_time(context
, id
, &t
);
2022 krb5_cc_close(context
, id
);
2029 krb5_cccol_cursor_free(context
, &cursor
);
2034 * Return a friendly name on credential cache. Free the result with krb5_xfree().
2036 * @return Return an error code or 0, see krb5_get_error_message().
2038 * @ingroup krb5_ccache
2041 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2042 krb5_cc_get_friendly_name(krb5_context context
,
2046 krb5_error_code ret
;
2049 ret
= krb5_cc_get_config(context
, id
, NULL
, "FriendlyName", &data
);
2051 krb5_principal principal
;
2052 ret
= krb5_cc_get_principal(context
, id
, &principal
);
2055 ret
= krb5_unparse_name(context
, principal
, name
);
2056 krb5_free_principal(context
, principal
);
2058 ret
= asprintf(name
, "%.*s", (int)data
.length
, (char *)data
.data
);
2059 krb5_data_free(&data
);
2061 ret
= krb5_enomem(context
);
2070 * Set the friendly name on credential cache.
2072 * @return Return an error code or 0, see krb5_get_error_message().
2074 * @ingroup krb5_ccache
2077 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2078 krb5_cc_set_friendly_name(krb5_context context
,
2084 data
.data
= rk_UNCONST(name
);
2085 data
.length
= strlen(name
);
2087 return krb5_cc_set_config(context
, id
, NULL
, "FriendlyName", &data
);
2091 * Get the lifetime of the initial ticket in the cache
2093 * Get the lifetime of the initial ticket in the cache, if the initial
2094 * ticket was not found, the error code KRB5_CC_END is returned.
2096 * @param context A Kerberos 5 context.
2097 * @param id a credential cache
2098 * @param t the relative lifetime of the initial ticket
2100 * @return Return an error code or 0, see krb5_get_error_message().
2102 * @ingroup krb5_ccache
2105 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2106 krb5_cc_get_lifetime(krb5_context context
, krb5_ccache id
, time_t *t
)
2108 krb5_data config_start_realm
;
2110 krb5_cc_cursor cursor
;
2111 krb5_error_code ret
;
2113 time_t now
, endtime
= 0;
2116 krb5_timeofday(context
, &now
);
2118 ret
= krb5_cc_get_config(context
, id
, NULL
, "start_realm", &config_start_realm
);
2120 start_realm
= strndup(config_start_realm
.data
, config_start_realm
.length
);
2121 krb5_data_free(&config_start_realm
);
2123 krb5_principal client
;
2125 ret
= krb5_cc_get_principal(context
, id
, &client
);
2128 start_realm
= strdup(krb5_principal_get_realm(context
, client
));
2129 krb5_free_principal(context
, client
);
2131 if (start_realm
== NULL
)
2132 return krb5_enomem(context
);
2134 ret
= krb5_cc_start_seq_get(context
, id
, &cursor
);
2140 while ((ret
= krb5_cc_next_cred(context
, id
, &cursor
, &cred
)) == 0) {
2142 * If we find the start krbtgt in the cache, use that as the lifespan.
2144 if (krb5_principal_is_root_krbtgt(context
, cred
.server
) &&
2145 strcmp(cred
.server
->realm
, start_realm
) == 0) {
2146 if (now
< cred
.times
.endtime
)
2147 endtime
= cred
.times
.endtime
;
2148 krb5_free_cred_contents(context
, &cred
);
2152 * Skip config entries
2154 if (krb5_is_config_principal(context
, cred
.server
)) {
2155 krb5_free_cred_contents(context
, &cred
);
2159 * If there was no krbtgt, use the shortest lifetime of
2160 * service tickets that have yet to expire. If all
2161 * credentials are expired, krb5_cc_get_lifetime() will fail.
2163 if ((endtime
== 0 || cred
.times
.endtime
< endtime
) && now
< cred
.times
.endtime
)
2164 endtime
= cred
.times
.endtime
;
2165 krb5_free_cred_contents(context
, &cred
);
2169 /* if we found an endtime use that */
2175 krb5_cc_end_seq_get(context
, id
, &cursor
);
2181 * Set the time offset betwen the client and the KDC
2183 * If the backend doesn't support KDC offset, use the context global setting.
2185 * @param context A Kerberos 5 context.
2186 * @param id a credential cache
2187 * @param offset the offset in seconds
2189 * @return Return an error code or 0, see krb5_get_error_message().
2191 * @ingroup krb5_ccache
2194 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2195 krb5_cc_set_kdc_offset(krb5_context context
, krb5_ccache id
, krb5_deltat offset
)
2197 if (id
->ops
->version
< KRB5_CC_OPS_VERSION_3
2198 || id
->ops
->set_kdc_offset
== NULL
) {
2199 context
->kdc_sec_offset
= offset
;
2200 context
->kdc_usec_offset
= 0;
2203 return (*id
->ops
->set_kdc_offset
)(context
, id
, offset
);
2207 * Get the time offset betwen the client and the KDC
2209 * If the backend doesn't support KDC offset, use the context global setting.
2211 * @param context A Kerberos 5 context.
2212 * @param id a credential cache
2213 * @param offset the offset in seconds
2215 * @return Return an error code or 0, see krb5_get_error_message().
2217 * @ingroup krb5_ccache
2220 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2221 krb5_cc_get_kdc_offset(krb5_context context
, krb5_ccache id
, krb5_deltat
*offset
)
2223 if (id
->ops
->version
< KRB5_CC_OPS_VERSION_3
2224 || id
->ops
->get_kdc_offset
== NULL
) {
2225 *offset
= context
->kdc_sec_offset
;
2228 return (*id
->ops
->get_kdc_offset
)(context
, id
, offset
);
2232 #define REGPATH_MIT_KRB5 "SOFTWARE\\MIT\\Kerberos5"
2235 _get_default_cc_name_from_registry(krb5_context context
, HKEY hkBase
)
2239 char *ccname
= NULL
;
2241 code
= RegOpenKeyEx(hkBase
,
2243 0, KEY_READ
, &hk_k5
);
2245 if (code
!= ERROR_SUCCESS
)
2248 ccname
= heim_parse_reg_value_as_string(context
->hcontext
, hk_k5
, "ccname",
2256 KRB5_LIB_FUNCTION
char * KRB5_LIB_CALL
2257 _krb5_get_default_cc_name_from_registry(krb5_context context
)
2261 ccname
= _get_default_cc_name_from_registry(context
, HKEY_CURRENT_USER
);
2263 ccname
= _get_default_cc_name_from_registry(context
,
2264 HKEY_LOCAL_MACHINE
);
2269 KRB5_LIB_FUNCTION
int KRB5_LIB_CALL
2270 _krb5_set_default_cc_name_to_registry(krb5_context context
, krb5_ccache id
)
2275 char * ccname
= NULL
;
2277 code
= RegOpenKeyEx(HKEY_CURRENT_USER
,
2279 0, KEY_READ
|KEY_WRITE
, &hk_k5
);
2281 if (code
!= ERROR_SUCCESS
)
2284 ret
= asprintf(&ccname
, "%s:%s", krb5_cc_get_type(context
, id
), krb5_cc_get_name(context
, id
));
2288 ret
= heim_store_string_to_reg_value(context
->hcontext
, hk_k5
, "ccname",
2289 REG_SZ
, ccname
, -1, 0);