155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
755682Smarkm *
8233294Sstas * Redistribution and use in source and binary forms, with or without
9233294Sstas * modification, are permitted provided that the following conditions
10233294Sstas * are met:
1155682Smarkm *
12233294Sstas * 1. Redistributions of source code must retain the above copyright
13233294Sstas *    notice, this list of conditions and the following disclaimer.
1455682Smarkm *
15233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
16233294Sstas *    notice, this list of conditions and the following disclaimer in the
17233294Sstas *    documentation and/or other materials provided with the distribution.
1855682Smarkm *
19233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
20233294Sstas *    may be used to endorse or promote products derived from this software
21233294Sstas *    without specific prior written permission.
22233294Sstas *
23233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33233294Sstas * SUCH DAMAGE.
3455682Smarkm */
3555682Smarkm
3655682Smarkm#include "krb5_locl.h"
3755682Smarkm
38233294Sstas/**
39233294Sstas * @page krb5_ccache_intro The credential cache functions
40233294Sstas * @section section_krb5_ccache Kerberos credential caches
41233294Sstas *
42233294Sstas * krb5_ccache structure holds a Kerberos credential cache.
43233294Sstas *
44233294Sstas * Heimdal support the follow types of credential caches:
45233294Sstas *
46233294Sstas * - SCC
47233294Sstas *   Store the credential in a database
48233294Sstas * - FILE
49233294Sstas *   Store the credential in memory
50233294Sstas * - MEMORY
51233294Sstas *   Store the credential in memory
52233294Sstas * - API
53233294Sstas *   A credential cache server based solution for Mac OS X
54233294Sstas * - KCM
55233294Sstas *   A credential cache server based solution for all platforms
56233294Sstas *
57233294Sstas * @subsection Example
58233294Sstas *
59233294Sstas * This is a minimalistic version of klist:
60233294Sstas@code
61233294Sstas#include <krb5.h>
6255682Smarkm
63233294Sstasint
64233294Sstasmain (int argc, char **argv)
65233294Sstas{
66233294Sstas    krb5_context context;
67233294Sstas    krb5_cc_cursor cursor;
68233294Sstas    krb5_error_code ret;
69233294Sstas    krb5_ccache id;
70233294Sstas    krb5_creds creds;
71233294Sstas
72233294Sstas    if (krb5_init_context (&context) != 0)
73233294Sstas	errx(1, "krb5_context");
74233294Sstas
75233294Sstas    ret = krb5_cc_default (context, &id);
76233294Sstas    if (ret)
77233294Sstas	krb5_err(context, 1, ret, "krb5_cc_default");
78233294Sstas
79233294Sstas    ret = krb5_cc_start_seq_get(context, id, &cursor);
80233294Sstas    if (ret)
81233294Sstas	krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
82233294Sstas
83233294Sstas    while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){
84233294Sstas        char *principal;
85233294Sstas
86233294Sstas	krb5_unparse_name(context, creds.server, &principal);
87233294Sstas	printf("principal: %s\\n", principal);
88233294Sstas	free(principal);
89233294Sstas	krb5_free_cred_contents (context, &creds);
90233294Sstas    }
91233294Sstas    ret = krb5_cc_end_seq_get(context, id, &cursor);
92233294Sstas    if (ret)
93233294Sstas	krb5_err(context, 1, ret, "krb5_cc_end_seq_get");
94233294Sstas
95233294Sstas    krb5_cc_close(context, id);
96233294Sstas
97233294Sstas    krb5_free_context(context);
98233294Sstas    return 0;
99233294Sstas}
100233294Sstas* @endcode
101233294Sstas*/
102233294Sstas
103178825Sdfr/**
10455682Smarkm * Add a new ccache type with operations `ops', overwriting any
10555682Smarkm * existing one if `override'.
106178825Sdfr *
107178825Sdfr * @param context a Keberos context
108178825Sdfr * @param ops type of plugin symbol
109178825Sdfr * @param override flag to select if the registration is to overide
110178825Sdfr * an existing ops with the same name.
111178825Sdfr *
112233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
113178825Sdfr *
114178825Sdfr * @ingroup krb5_ccache
11555682Smarkm */
11655682Smarkm
117233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
118233294Sstaskrb5_cc_register(krb5_context context,
119233294Sstas		 const krb5_cc_ops *ops,
12055682Smarkm		 krb5_boolean override)
12155682Smarkm{
12255682Smarkm    int i;
12355682Smarkm
124233294Sstas    for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
125233294Sstas	if(strcmp(context->cc_ops[i]->prefix, ops->prefix) == 0) {
126102644Snectar	    if(!override) {
127233294Sstas		krb5_set_error_message(context,
128233294Sstas				       KRB5_CC_TYPE_EXISTS,
129233294Sstas				       N_("cache type %s already exists", "type"),
130233294Sstas				       ops->prefix);
13155682Smarkm		return KRB5_CC_TYPE_EXISTS;
13278527Sassar	    }
133102644Snectar	    break;
13455682Smarkm	}
13555682Smarkm    }
13655682Smarkm    if(i == context->num_cc_ops) {
137233294Sstas	const krb5_cc_ops **o = realloc(rk_UNCONST(context->cc_ops),
138233294Sstas					(context->num_cc_ops + 1) *
139233294Sstas					sizeof(context->cc_ops[0]));
14078527Sassar	if(o == NULL) {
141233294Sstas	    krb5_set_error_message(context, KRB5_CC_NOMEM,
142233294Sstas				   N_("malloc: out of memory", ""));
14355682Smarkm	    return KRB5_CC_NOMEM;
14478527Sassar	}
145233294Sstas	context->cc_ops = o;
146233294Sstas	context->cc_ops[context->num_cc_ops] = NULL;
14755682Smarkm	context->num_cc_ops++;
14855682Smarkm    }
149233294Sstas    context->cc_ops[i] = ops;
15055682Smarkm    return 0;
15155682Smarkm}
15255682Smarkm
15355682Smarkm/*
154178825Sdfr * Allocate the memory for a `id' and the that function table to
155178825Sdfr * `ops'. Returns 0 or and error code.
156178825Sdfr */
157178825Sdfr
158178825Sdfrkrb5_error_code
159233294Sstas_krb5_cc_allocate(krb5_context context,
160178825Sdfr		  const krb5_cc_ops *ops,
161178825Sdfr		  krb5_ccache *id)
162178825Sdfr{
163178825Sdfr    krb5_ccache p;
164178825Sdfr
165178825Sdfr    p = malloc (sizeof(*p));
166178825Sdfr    if(p == NULL) {
167233294Sstas	krb5_set_error_message(context, KRB5_CC_NOMEM,
168233294Sstas			       N_("malloc: out of memory", ""));
169178825Sdfr	return KRB5_CC_NOMEM;
170178825Sdfr    }
171178825Sdfr    p->ops = ops;
172178825Sdfr    *id = p;
173178825Sdfr
174178825Sdfr    return 0;
175178825Sdfr}
176178825Sdfr
177178825Sdfr/*
17855682Smarkm * Allocate memory for a new ccache in `id' with operations `ops'
179178825Sdfr * and name `residual'. Return 0 or an error code.
18055682Smarkm */
18155682Smarkm
18255682Smarkmstatic krb5_error_code
18355682Smarkmallocate_ccache (krb5_context context,
18455682Smarkm		 const krb5_cc_ops *ops,
18555682Smarkm		 const char *residual,
18655682Smarkm		 krb5_ccache *id)
18755682Smarkm{
18855682Smarkm    krb5_error_code ret;
189233294Sstas#ifdef KRB5_USE_PATH_TOKENS
190233294Sstas    char * exp_residual = NULL;
19155682Smarkm
192233294Sstas    ret = _krb5_expand_path_tokens(context, residual, &exp_residual);
193178825Sdfr    if (ret)
194178825Sdfr	return ret;
195233294Sstas
196233294Sstas    residual = exp_residual;
197233294Sstas#endif
198233294Sstas
199233294Sstas    ret = _krb5_cc_allocate(context, ops, id);
200233294Sstas    if (ret) {
201233294Sstas#ifdef KRB5_USE_PATH_TOKENS
202233294Sstas	if (exp_residual)
203233294Sstas	    free(exp_residual);
204233294Sstas#endif
205233294Sstas	return ret;
206233294Sstas    }
207233294Sstas
208178825Sdfr    ret = (*id)->ops->resolve(context, id, residual);
209233294Sstas    if(ret) {
210178825Sdfr	free(*id);
211233294Sstas        *id = NULL;
212233294Sstas    }
213233294Sstas
214233294Sstas#ifdef KRB5_USE_PATH_TOKENS
215233294Sstas    if (exp_residual)
216233294Sstas	free(exp_residual);
217233294Sstas#endif
218233294Sstas
21955682Smarkm    return ret;
22055682Smarkm}
22155682Smarkm
222233294Sstasstatic int
223233294Sstasis_possible_path_name(const char * name)
224233294Sstas{
225233294Sstas    const char * colon;
226233294Sstas
227233294Sstas    if ((colon = strchr(name, ':')) == NULL)
228233294Sstas        return TRUE;
229233294Sstas
230233294Sstas#ifdef _WIN32
231233294Sstas    /* <drive letter>:\path\to\cache ? */
232233294Sstas
233233294Sstas    if (colon == name + 1 &&
234233294Sstas        strchr(colon + 1, ':') == NULL)
235233294Sstas        return TRUE;
236233294Sstas#endif
237233294Sstas
238233294Sstas    return FALSE;
239233294Sstas}
240233294Sstas
241178825Sdfr/**
24255682Smarkm * Find and allocate a ccache in `id' from the specification in `residual'.
24355682Smarkm * If the ccache name doesn't contain any colon, interpret it as a file name.
244178825Sdfr *
245178825Sdfr * @param context a Keberos context.
246178825Sdfr * @param name string name of a credential cache.
247178825Sdfr * @param id return pointer to a found credential cache.
248178825Sdfr *
249178825Sdfr * @return Return 0 or an error code. In case of an error, id is set
250233294Sstas * to NULL, see krb5_get_error_message().
251178825Sdfr *
252178825Sdfr * @ingroup krb5_ccache
25355682Smarkm */
25455682Smarkm
255178825Sdfr
256233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
25755682Smarkmkrb5_cc_resolve(krb5_context context,
25855682Smarkm		const char *name,
25955682Smarkm		krb5_ccache *id)
26055682Smarkm{
26155682Smarkm    int i;
26255682Smarkm
263178825Sdfr    *id = NULL;
264178825Sdfr
265233294Sstas    for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
266233294Sstas	size_t prefix_len = strlen(context->cc_ops[i]->prefix);
26755682Smarkm
268233294Sstas	if(strncmp(context->cc_ops[i]->prefix, name, prefix_len) == 0
26955682Smarkm	   && name[prefix_len] == ':') {
270233294Sstas	    return allocate_ccache (context, context->cc_ops[i],
27155682Smarkm				    name + prefix_len + 1,
27255682Smarkm				    id);
27355682Smarkm	}
27455682Smarkm    }
275233294Sstas    if (is_possible_path_name(name))
27655682Smarkm	return allocate_ccache (context, &krb5_fcc_ops, name, id);
27778527Sassar    else {
278233294Sstas	krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
279233294Sstas			       N_("unknown ccache type %s", "name"), name);
28055682Smarkm	return KRB5_CC_UNKNOWN_TYPE;
28178527Sassar    }
28255682Smarkm}
28355682Smarkm
284178825Sdfr/**
285178825Sdfr * Generates a new unique ccache of `type` in `id'. If `type' is NULL,
286178825Sdfr * the library chooses the default credential cache type. The supplied
287178825Sdfr * `hint' (that can be NULL) is a string that the credential cache
288178825Sdfr * type can use to base the name of the credential on, this is to make
289178825Sdfr * it easier for the user to differentiate the credentials.
290178825Sdfr *
291233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
292178825Sdfr *
293178825Sdfr * @ingroup krb5_ccache
294178825Sdfr */
295178825Sdfr
296233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
297233294Sstaskrb5_cc_new_unique(krb5_context context, const char *type,
298178825Sdfr		   const char *hint, krb5_ccache *id)
299178825Sdfr{
300233294Sstas    const krb5_cc_ops *ops;
301178825Sdfr    krb5_error_code ret;
302178825Sdfr
303233294Sstas    ops = krb5_cc_get_prefix_ops(context, type);
304233294Sstas    if (ops == NULL) {
305233294Sstas	krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
306233294Sstas			      "Credential cache type %s is unknown", type);
307233294Sstas	return KRB5_CC_UNKNOWN_TYPE;
30878527Sassar    }
309178825Sdfr
310178825Sdfr    ret = _krb5_cc_allocate(context, ops, id);
311178825Sdfr    if (ret)
312178825Sdfr	return ret;
313233294Sstas    ret = (*id)->ops->gen_new(context, id);
314233294Sstas    if (ret) {
315233294Sstas	free(*id);
316233294Sstas	*id = NULL;
317233294Sstas    }
318233294Sstas    return ret;
31955682Smarkm}
32055682Smarkm
321178825Sdfr/**
32255682Smarkm * Return the name of the ccache `id'
323178825Sdfr *
324178825Sdfr * @ingroup krb5_ccache
32555682Smarkm */
32655682Smarkm
327178825Sdfr
328233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
32955682Smarkmkrb5_cc_get_name(krb5_context context,
33055682Smarkm		 krb5_ccache id)
33155682Smarkm{
33255682Smarkm    return id->ops->get_name(context, id);
33355682Smarkm}
33455682Smarkm
335178825Sdfr/**
33655682Smarkm * Return the type of the ccache `id'.
337178825Sdfr *
338178825Sdfr * @ingroup krb5_ccache
33955682Smarkm */
34055682Smarkm
341178825Sdfr
342233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
34355682Smarkmkrb5_cc_get_type(krb5_context context,
34455682Smarkm		 krb5_ccache id)
34555682Smarkm{
34655682Smarkm    return id->ops->prefix;
34755682Smarkm}
34855682Smarkm
349178825Sdfr/**
350233294Sstas * Return the complete resolvable name the cache
351233294Sstas
352233294Sstas * @param context a Keberos context
353233294Sstas * @param id return pointer to a found credential cache
354233294Sstas * @param str the returned name of a credential cache, free with krb5_xfree()
355178825Sdfr *
356233294Sstas * @return Returns 0 or an error (and then *str is set to NULL).
357233294Sstas *
358178825Sdfr * @ingroup krb5_ccache
359178825Sdfr */
360178825Sdfr
361178825Sdfr
362233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
363178825Sdfrkrb5_cc_get_full_name(krb5_context context,
364178825Sdfr		      krb5_ccache id,
365178825Sdfr		      char **str)
366178825Sdfr{
367178825Sdfr    const char *type, *name;
368178825Sdfr
369178825Sdfr    *str = NULL;
370178825Sdfr
371178825Sdfr    type = krb5_cc_get_type(context, id);
372178825Sdfr    if (type == NULL) {
373233294Sstas	krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
374233294Sstas			       "cache have no name of type");
375178825Sdfr	return KRB5_CC_UNKNOWN_TYPE;
376178825Sdfr    }
377178825Sdfr
378178825Sdfr    name = krb5_cc_get_name(context, id);
379178825Sdfr    if (name == NULL) {
380233294Sstas	krb5_set_error_message(context, KRB5_CC_BADNAME,
381233294Sstas			       "cache of type %s have no name", type);
382178825Sdfr	return KRB5_CC_BADNAME;
383178825Sdfr    }
384233294Sstas
385178825Sdfr    if (asprintf(str, "%s:%s", type, name) == -1) {
386233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
387178825Sdfr	*str = NULL;
388178825Sdfr	return ENOMEM;
389178825Sdfr    }
390178825Sdfr    return 0;
391178825Sdfr}
392178825Sdfr
393178825Sdfr/**
394120945Snectar * Return krb5_cc_ops of a the ccache `id'.
395178825Sdfr *
396178825Sdfr * @ingroup krb5_ccache
39755682Smarkm */
39855682Smarkm
399178825Sdfr
400233294SstasKRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL
401120945Snectarkrb5_cc_get_ops(krb5_context context, krb5_ccache id)
402120945Snectar{
403120945Snectar    return id->ops;
404120945Snectar}
405120945Snectar
406120945Snectar/*
407178825Sdfr * Expand variables in `str' into `res'
408178825Sdfr */
409178825Sdfr
410178825Sdfrkrb5_error_code
411178825Sdfr_krb5_expand_default_cc_name(krb5_context context, const char *str, char **res)
412178825Sdfr{
413233294Sstas    return _krb5_expand_path_tokens(context, str, res);
414178825Sdfr}
415178825Sdfr
416178825Sdfr/*
417178825Sdfr * Return non-zero if envirnoment that will determine default krb5cc
418178825Sdfr * name has changed.
419178825Sdfr */
420178825Sdfr
421178825Sdfrstatic int
422178825Sdfrenvironment_changed(krb5_context context)
423178825Sdfr{
424178825Sdfr    const char *e;
425178825Sdfr
426178825Sdfr    /* if the cc name was set, don't change it */
427178825Sdfr    if (context->default_cc_name_set)
428178825Sdfr	return 0;
429178825Sdfr
430233294Sstas    /* XXX performance: always ask KCM/API if default name has changed */
431233294Sstas    if (context->default_cc_name &&
432233294Sstas	(strncmp(context->default_cc_name, "KCM:", 4) == 0 ||
433233294Sstas	 strncmp(context->default_cc_name, "API:", 4) == 0))
434233294Sstas	return 1;
435233294Sstas
436178825Sdfr    if(issuid())
437178825Sdfr	return 0;
438178825Sdfr
439178825Sdfr    e = getenv("KRB5CCNAME");
440178825Sdfr    if (e == NULL) {
441178825Sdfr	if (context->default_cc_name_env) {
442178825Sdfr	    free(context->default_cc_name_env);
443178825Sdfr	    context->default_cc_name_env = NULL;
444178825Sdfr	    return 1;
445178825Sdfr	}
446178825Sdfr    } else {
447178825Sdfr	if (context->default_cc_name_env == NULL)
448178825Sdfr	    return 1;
449178825Sdfr	if (strcmp(e, context->default_cc_name_env) != 0)
450178825Sdfr	    return 1;
451178825Sdfr    }
452178825Sdfr    return 0;
453178825Sdfr}
454178825Sdfr
455178825Sdfr/**
456233294Sstas * Switch the default default credential cache for a specific
457233294Sstas * credcache type (and name for some implementations).
458233294Sstas *
459233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
460233294Sstas *
461233294Sstas * @ingroup krb5_ccache
462233294Sstas */
463233294Sstas
464233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
465233294Sstaskrb5_cc_switch(krb5_context context, krb5_ccache id)
466233294Sstas{
467233294Sstas#ifdef _WIN32
468233294Sstas    _krb5_set_default_cc_name_to_registry(context, id);
469233294Sstas#endif
470233294Sstas
471233294Sstas    if (id->ops->set_default == NULL)
472233294Sstas	return 0;
473233294Sstas
474233294Sstas    return (*id->ops->set_default)(context, id);
475233294Sstas}
476233294Sstas
477233294Sstas/**
478233294Sstas * Return true if the default credential cache support switch
479233294Sstas *
480233294Sstas * @ingroup krb5_ccache
481233294Sstas */
482233294Sstas
483233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
484233294Sstaskrb5_cc_support_switch(krb5_context context, const char *type)
485233294Sstas{
486233294Sstas    const krb5_cc_ops *ops;
487233294Sstas
488233294Sstas    ops = krb5_cc_get_prefix_ops(context, type);
489233294Sstas    if (ops && ops->set_default)
490233294Sstas	return 1;
491233294Sstas    return FALSE;
492233294Sstas}
493233294Sstas
494233294Sstas/**
495120945Snectar * Set the default cc name for `context' to `name'.
496178825Sdfr *
497178825Sdfr * @ingroup krb5_ccache
498120945Snectar */
499120945Snectar
500233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
501120945Snectarkrb5_cc_set_default_name(krb5_context context, const char *name)
502120945Snectar{
503120945Snectar    krb5_error_code ret = 0;
504233294Sstas    char *p = NULL, *exp_p = NULL;
505120945Snectar
506120945Snectar    if (name == NULL) {
507178825Sdfr	const char *e = NULL;
508178825Sdfr
509178825Sdfr	if(!issuid()) {
510178825Sdfr	    e = getenv("KRB5CCNAME");
511178825Sdfr	    if (e) {
512178825Sdfr		p = strdup(e);
513178825Sdfr		if (context->default_cc_name_env)
514178825Sdfr		    free(context->default_cc_name_env);
515178825Sdfr		context->default_cc_name_env = strdup(e);
516178825Sdfr	    }
517178825Sdfr	}
518233294Sstas
519233294Sstas#ifdef _WIN32
520233294Sstas        if (e == NULL) {
521233294Sstas            e = p = _krb5_get_default_cc_name_from_registry(context);
522233294Sstas        }
523233294Sstas#endif
524178825Sdfr	if (e == NULL) {
525178825Sdfr	    e = krb5_config_get_string(context, NULL, "libdefaults",
526178825Sdfr				       "default_cc_name", NULL);
527178825Sdfr	    if (e) {
528178825Sdfr		ret = _krb5_expand_default_cc_name(context, e, &p);
529178825Sdfr		if (ret)
530178825Sdfr		    return ret;
531178825Sdfr	    }
532178825Sdfr	    if (e == NULL) {
533178825Sdfr		const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE;
534233294Sstas		e = krb5_config_get_string(context, NULL, "libdefaults",
535233294Sstas					   "default_cc_type", NULL);
536233294Sstas		if (e) {
537233294Sstas		    ops = krb5_cc_get_prefix_ops(context, e);
538233294Sstas		    if (ops == NULL) {
539233294Sstas			krb5_set_error_message(context,
540233294Sstas					       KRB5_CC_UNKNOWN_TYPE,
541233294Sstas					       "Credential cache type %s "
542233294Sstas					      "is unknown", e);
543233294Sstas			return KRB5_CC_UNKNOWN_TYPE;
544233294Sstas		    }
545233294Sstas		}
546233294Sstas		ret = (*ops->get_default_name)(context, &p);
547178825Sdfr		if (ret)
548178825Sdfr		    return ret;
549178825Sdfr	    }
550178825Sdfr	}
551178825Sdfr	context->default_cc_name_set = 0;
552178825Sdfr    } else {
553120945Snectar	p = strdup(name);
554178825Sdfr	context->default_cc_name_set = 1;
555178825Sdfr    }
556120945Snectar
557178825Sdfr    if (p == NULL) {
558233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
559120945Snectar	return ENOMEM;
560178825Sdfr    }
561120945Snectar
562233294Sstas    ret = _krb5_expand_path_tokens(context, p, &exp_p);
563233294Sstas    free(p);
564233294Sstas    if (ret)
565233294Sstas	return ret;
566233294Sstas
567120945Snectar    if (context->default_cc_name)
568120945Snectar	free(context->default_cc_name);
569120945Snectar
570233294Sstas    context->default_cc_name = exp_p;
571120945Snectar
572233294Sstas    return 0;
573120945Snectar}
574120945Snectar
575178825Sdfr/**
576178825Sdfr * Return a pointer to a context static string containing the default
577178825Sdfr * ccache name.
578178825Sdfr *
579178825Sdfr * @return String to the default credential cache name.
580178825Sdfr *
581178825Sdfr * @ingroup krb5_ccache
582120945Snectar */
583120945Snectar
584178825Sdfr
585233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
58655682Smarkmkrb5_cc_default_name(krb5_context context)
58755682Smarkm{
588178825Sdfr    if (context->default_cc_name == NULL || environment_changed(context))
589120945Snectar	krb5_cc_set_default_name(context, NULL);
59055682Smarkm
591120945Snectar    return context->default_cc_name;
59255682Smarkm}
59355682Smarkm
594178825Sdfr/**
59555682Smarkm * Open the default ccache in `id'.
596178825Sdfr *
597233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
598178825Sdfr *
599178825Sdfr * @ingroup krb5_ccache
60055682Smarkm */
60155682Smarkm
602178825Sdfr
603233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
60455682Smarkmkrb5_cc_default(krb5_context context,
60555682Smarkm		krb5_ccache *id)
60655682Smarkm{
607120945Snectar    const char *p = krb5_cc_default_name(context);
608120945Snectar
609178825Sdfr    if (p == NULL) {
610233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
611120945Snectar	return ENOMEM;
612178825Sdfr    }
613120945Snectar    return krb5_cc_resolve(context, p, id);
61455682Smarkm}
61555682Smarkm
616178825Sdfr/**
61755682Smarkm * Create a new ccache in `id' for `primary_principal'.
618178825Sdfr *
619233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
620178825Sdfr *
621178825Sdfr * @ingroup krb5_ccache
62255682Smarkm */
62355682Smarkm
624178825Sdfr
625233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
62655682Smarkmkrb5_cc_initialize(krb5_context context,
62755682Smarkm		   krb5_ccache id,
62855682Smarkm		   krb5_principal primary_principal)
62955682Smarkm{
630178825Sdfr    return (*id->ops->init)(context, id, primary_principal);
63155682Smarkm}
63255682Smarkm
63355682Smarkm
634178825Sdfr/**
63555682Smarkm * Remove the ccache `id'.
636178825Sdfr *
637233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
638178825Sdfr *
639178825Sdfr * @ingroup krb5_ccache
64055682Smarkm */
64155682Smarkm
642178825Sdfr
643233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
64455682Smarkmkrb5_cc_destroy(krb5_context context,
64555682Smarkm		krb5_ccache id)
64655682Smarkm{
64755682Smarkm    krb5_error_code ret;
64855682Smarkm
649178825Sdfr    ret = (*id->ops->destroy)(context, id);
65055682Smarkm    krb5_cc_close (context, id);
65155682Smarkm    return ret;
65255682Smarkm}
65355682Smarkm
654178825Sdfr/**
65555682Smarkm * Stop using the ccache `id' and free the related resources.
656178825Sdfr *
657233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
658178825Sdfr *
659178825Sdfr * @ingroup krb5_ccache
66055682Smarkm */
66155682Smarkm
662178825Sdfr
663233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
66455682Smarkmkrb5_cc_close(krb5_context context,
66555682Smarkm	      krb5_ccache id)
66655682Smarkm{
66755682Smarkm    krb5_error_code ret;
668178825Sdfr    ret = (*id->ops->close)(context, id);
66955682Smarkm    free(id);
67055682Smarkm    return ret;
67155682Smarkm}
67255682Smarkm
673178825Sdfr/**
67455682Smarkm * Store `creds' in the ccache `id'.
675178825Sdfr *
676233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
677178825Sdfr *
678178825Sdfr * @ingroup krb5_ccache
67955682Smarkm */
68055682Smarkm
681178825Sdfr
682233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
68355682Smarkmkrb5_cc_store_cred(krb5_context context,
68455682Smarkm		   krb5_ccache id,
68555682Smarkm		   krb5_creds *creds)
68655682Smarkm{
687178825Sdfr    return (*id->ops->store)(context, id, creds);
68855682Smarkm}
68955682Smarkm
690178825Sdfr/**
69155682Smarkm * Retrieve the credential identified by `mcreds' (and `whichfields')
692178825Sdfr * from `id' in `creds'. 'creds' must be free by the caller using
693178825Sdfr * krb5_free_cred_contents.
694178825Sdfr *
695233294Sstas * @param context A Kerberos 5 context
696233294Sstas * @param id a Kerberos 5 credential cache
697233294Sstas * @param whichfields what fields to use for matching credentials, same
698233294Sstas *        flags as whichfields in krb5_compare_creds()
699233294Sstas * @param mcreds template credential to use for comparing
700233294Sstas * @param creds returned credential, free with krb5_free_cred_contents()
701178825Sdfr *
702233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
703233294Sstas *
704178825Sdfr * @ingroup krb5_ccache
70555682Smarkm */
70655682Smarkm
707178825Sdfr
708233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
70955682Smarkmkrb5_cc_retrieve_cred(krb5_context context,
71055682Smarkm		      krb5_ccache id,
71155682Smarkm		      krb5_flags whichfields,
71255682Smarkm		      const krb5_creds *mcreds,
71355682Smarkm		      krb5_creds *creds)
71455682Smarkm{
71555682Smarkm    krb5_error_code ret;
71655682Smarkm    krb5_cc_cursor cursor;
717178825Sdfr
718178825Sdfr    if (id->ops->retrieve != NULL) {
719178825Sdfr	return (*id->ops->retrieve)(context, id, whichfields,
720178825Sdfr				    mcreds, creds);
721178825Sdfr    }
722178825Sdfr
723178825Sdfr    ret = krb5_cc_start_seq_get(context, id, &cursor);
724178825Sdfr    if (ret)
725178825Sdfr	return ret;
72678527Sassar    while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){
72755682Smarkm	if(krb5_compare_creds(context, whichfields, mcreds, creds)){
72855682Smarkm	    ret = 0;
72955682Smarkm	    break;
73055682Smarkm	}
731178825Sdfr	krb5_free_cred_contents (context, creds);
73255682Smarkm    }
73355682Smarkm    krb5_cc_end_seq_get(context, id, &cursor);
73455682Smarkm    return ret;
73555682Smarkm}
73655682Smarkm
737178825Sdfr/**
73855682Smarkm * Return the principal of `id' in `principal'.
739178825Sdfr *
740233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
741178825Sdfr *
742178825Sdfr * @ingroup krb5_ccache
74355682Smarkm */
74455682Smarkm
745178825Sdfr
746233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
74755682Smarkmkrb5_cc_get_principal(krb5_context context,
74855682Smarkm		      krb5_ccache id,
74955682Smarkm		      krb5_principal *principal)
75055682Smarkm{
751178825Sdfr    return (*id->ops->get_princ)(context, id, principal);
75255682Smarkm}
75355682Smarkm
754178825Sdfr/**
75555682Smarkm * Start iterating over `id', `cursor' is initialized to the
756233294Sstas * beginning.  Caller must free the cursor with krb5_cc_end_seq_get().
757178825Sdfr *
758233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
759178825Sdfr *
760178825Sdfr * @ingroup krb5_ccache
76155682Smarkm */
76255682Smarkm
763178825Sdfr
764233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
76555682Smarkmkrb5_cc_start_seq_get (krb5_context context,
76655682Smarkm		       const krb5_ccache id,
76755682Smarkm		       krb5_cc_cursor *cursor)
76855682Smarkm{
769178825Sdfr    return (*id->ops->get_first)(context, id, cursor);
77055682Smarkm}
77155682Smarkm
772178825Sdfr/**
77355682Smarkm * Retrieve the next cred pointed to by (`id', `cursor') in `creds'
77455682Smarkm * and advance `cursor'.
775178825Sdfr *
776233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
777178825Sdfr *
778178825Sdfr * @ingroup krb5_ccache
77955682Smarkm */
78055682Smarkm
781178825Sdfr
782233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
78355682Smarkmkrb5_cc_next_cred (krb5_context context,
78455682Smarkm		   const krb5_ccache id,
78578527Sassar		   krb5_cc_cursor *cursor,
78678527Sassar		   krb5_creds *creds)
78755682Smarkm{
788178825Sdfr    return (*id->ops->get_next)(context, id, cursor, creds);
78955682Smarkm}
79055682Smarkm
791178825Sdfr/**
79255682Smarkm * Destroy the cursor `cursor'.
793178825Sdfr *
794178825Sdfr * @ingroup krb5_ccache
79555682Smarkm */
79655682Smarkm
797178825Sdfr
798233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
79955682Smarkmkrb5_cc_end_seq_get (krb5_context context,
80055682Smarkm		     const krb5_ccache id,
80155682Smarkm		     krb5_cc_cursor *cursor)
80255682Smarkm{
803178825Sdfr    return (*id->ops->end_get)(context, id, cursor);
80455682Smarkm}
80555682Smarkm
806178825Sdfr/**
80755682Smarkm * Remove the credential identified by `cred', `which' from `id'.
808178825Sdfr *
809178825Sdfr * @ingroup krb5_ccache
81055682Smarkm */
81155682Smarkm
812178825Sdfr
813233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
81455682Smarkmkrb5_cc_remove_cred(krb5_context context,
81555682Smarkm		    krb5_ccache id,
81655682Smarkm		    krb5_flags which,
81755682Smarkm		    krb5_creds *cred)
81855682Smarkm{
81978527Sassar    if(id->ops->remove_cred == NULL) {
820233294Sstas	krb5_set_error_message(context,
821233294Sstas			       EACCES,
822233294Sstas			       "ccache %s does not support remove_cred",
823233294Sstas			       id->ops->prefix);
82472445Sassar	return EACCES; /* XXX */
82578527Sassar    }
82672445Sassar    return (*id->ops->remove_cred)(context, id, which, cred);
82755682Smarkm}
82855682Smarkm
829178825Sdfr/**
83055682Smarkm * Set the flags of `id' to `flags'.
831178825Sdfr *
832178825Sdfr * @ingroup krb5_ccache
83355682Smarkm */
83455682Smarkm
835178825Sdfr
836233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
83755682Smarkmkrb5_cc_set_flags(krb5_context context,
83855682Smarkm		  krb5_ccache id,
83955682Smarkm		  krb5_flags flags)
84055682Smarkm{
841178825Sdfr    return (*id->ops->set_flags)(context, id, flags);
84255682Smarkm}
843233294Sstas
844178825Sdfr/**
845233294Sstas * Get the flags of `id', store them in `flags'.
846178825Sdfr *
847178825Sdfr * @ingroup krb5_ccache
84855682Smarkm */
84955682Smarkm
850233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
851233294Sstaskrb5_cc_get_flags(krb5_context context,
852233294Sstas		  krb5_ccache id,
853233294Sstas		  krb5_flags *flags)
854233294Sstas{
855233294Sstas    *flags = 0;
856233294Sstas    return 0;
857233294Sstas}
858178825Sdfr
859233294Sstas/**
860233294Sstas * Copy the contents of `from' to `to' if the given match function
861233294Sstas * return true.
862233294Sstas *
863233294Sstas * @param context A Kerberos 5 context.
864233294Sstas * @param from the cache to copy data from.
865233294Sstas * @param to the cache to copy data to.
866233294Sstas * @param match a match function that should return TRUE if cred argument should be copied, if NULL, all credentials are copied.
867233294Sstas * @param matchctx context passed to match function.
868233294Sstas * @param matched set to true if there was a credential that matched, may be NULL.
869233294Sstas *
870233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
871233294Sstas *
872233294Sstas * @ingroup krb5_ccache
873233294Sstas */
874233294Sstas
875233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
876233294Sstaskrb5_cc_copy_match_f(krb5_context context,
877233294Sstas		     const krb5_ccache from,
878233294Sstas		     krb5_ccache to,
879233294Sstas		     krb5_boolean (*match)(krb5_context, void *, const krb5_creds *),
880233294Sstas		     void *matchctx,
881233294Sstas		     unsigned int *matched)
88255682Smarkm{
88355682Smarkm    krb5_error_code ret;
88455682Smarkm    krb5_cc_cursor cursor;
88555682Smarkm    krb5_creds cred;
88655682Smarkm    krb5_principal princ;
88755682Smarkm
888233294Sstas    if (matched)
889233294Sstas	*matched = 0;
890233294Sstas
89155682Smarkm    ret = krb5_cc_get_principal(context, from, &princ);
892178825Sdfr    if (ret)
89355682Smarkm	return ret;
89455682Smarkm    ret = krb5_cc_initialize(context, to, princ);
895178825Sdfr    if (ret) {
89655682Smarkm	krb5_free_principal(context, princ);
89755682Smarkm	return ret;
89855682Smarkm    }
89955682Smarkm    ret = krb5_cc_start_seq_get(context, from, &cursor);
900178825Sdfr    if (ret) {
90155682Smarkm	krb5_free_principal(context, princ);
90255682Smarkm	return ret;
90355682Smarkm    }
904233294Sstas
905233294Sstas    while ((ret = krb5_cc_next_cred(context, from, &cursor, &cred)) == 0) {
906233294Sstas	   if (match == NULL || (*match)(context, matchctx, &cred) == 0) {
907233294Sstas	       if (matched)
908233294Sstas		   (*matched)++;
909233294Sstas	       ret = krb5_cc_store_cred(context, to, &cred);
910233294Sstas	       if (ret)
911233294Sstas		   break;
912233294Sstas	   }
913233294Sstas	   krb5_free_cred_contents(context, &cred);
91455682Smarkm    }
91555682Smarkm    krb5_cc_end_seq_get(context, from, &cursor);
91655682Smarkm    krb5_free_principal(context, princ);
917233294Sstas    if (ret == KRB5_CC_END)
918233294Sstas	ret = 0;
91955682Smarkm    return ret;
92055682Smarkm}
92155682Smarkm
922178825Sdfr/**
923233294Sstas * Just like krb5_cc_copy_match_f(), but copy everything.
924178825Sdfr *
925233294Sstas * @ingroup @krb5_ccache
926178825Sdfr */
927178825Sdfr
928233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
929178825Sdfrkrb5_cc_copy_cache(krb5_context context,
930178825Sdfr		   const krb5_ccache from,
931178825Sdfr		   krb5_ccache to)
932178825Sdfr{
933233294Sstas    return krb5_cc_copy_match_f(context, from, to, NULL, NULL, NULL);
934178825Sdfr}
935178825Sdfr
936178825Sdfr/**
93755682Smarkm * Return the version of `id'.
938178825Sdfr *
939178825Sdfr * @ingroup krb5_ccache
94055682Smarkm */
94155682Smarkm
942178825Sdfr
943233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
94455682Smarkmkrb5_cc_get_version(krb5_context context,
94555682Smarkm		    const krb5_ccache id)
94655682Smarkm{
94755682Smarkm    if(id->ops->get_version)
948178825Sdfr	return (*id->ops->get_version)(context, id);
94955682Smarkm    else
95055682Smarkm	return 0;
95155682Smarkm}
952178825Sdfr
953178825Sdfr/**
954178825Sdfr * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred
955178825Sdfr *
956178825Sdfr * @ingroup krb5_ccache
957178825Sdfr */
958178825Sdfr
959178825Sdfr
960233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
961178825Sdfrkrb5_cc_clear_mcred(krb5_creds *mcred)
962178825Sdfr{
963178825Sdfr    memset(mcred, 0, sizeof(*mcred));
964178825Sdfr}
965178825Sdfr
966178825Sdfr/**
967178825Sdfr * Get the cc ops that is registered in `context' to handle the
968233294Sstas * prefix. prefix can be a complete credential cache name or a
969178825Sdfr * prefix, the function will only use part up to the first colon (:)
970233294Sstas * if there is one. If prefix the argument is NULL, the default ccache
971233294Sstas * implemtation is returned.
972178825Sdfr *
973233294Sstas * @return Returns NULL if ops not found.
974233294Sstas *
975178825Sdfr * @ingroup krb5_ccache
976178825Sdfr */
977178825Sdfr
978178825Sdfr
979233294SstasKRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL
980178825Sdfrkrb5_cc_get_prefix_ops(krb5_context context, const char *prefix)
981178825Sdfr{
982178825Sdfr    char *p, *p1;
983178825Sdfr    int i;
984233294Sstas
985233294Sstas    if (prefix == NULL)
986233294Sstas	return KRB5_DEFAULT_CCTYPE;
987178825Sdfr    if (prefix[0] == '/')
988178825Sdfr	return &krb5_fcc_ops;
989178825Sdfr
990178825Sdfr    p = strdup(prefix);
991178825Sdfr    if (p == NULL) {
992233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
993178825Sdfr	return NULL;
994178825Sdfr    }
995178825Sdfr    p1 = strchr(p, ':');
996178825Sdfr    if (p1)
997178825Sdfr	*p1 = '\0';
998178825Sdfr
999233294Sstas    for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
1000233294Sstas	if(strcmp(context->cc_ops[i]->prefix, p) == 0) {
1001178825Sdfr	    free(p);
1002233294Sstas	    return context->cc_ops[i];
1003178825Sdfr	}
1004178825Sdfr    }
1005178825Sdfr    free(p);
1006178825Sdfr    return NULL;
1007178825Sdfr}
1008178825Sdfr
1009178825Sdfrstruct krb5_cc_cache_cursor_data {
1010178825Sdfr    const krb5_cc_ops *ops;
1011178825Sdfr    krb5_cc_cursor cursor;
1012178825Sdfr};
1013178825Sdfr
1014178825Sdfr/**
1015233294Sstas * Start iterating over all caches of specified type. See also
1016233294Sstas * krb5_cccol_cursor_new().
1017233294Sstas
1018233294Sstas * @param context A Kerberos 5 context
1019233294Sstas * @param type optional type to iterate over, if NULL, the default cache is used.
1020233294Sstas * @param cursor cursor should be freed with krb5_cc_cache_end_seq_get().
1021178825Sdfr *
1022233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
1023178825Sdfr *
1024178825Sdfr * @ingroup krb5_ccache
1025178825Sdfr */
1026178825Sdfr
1027178825Sdfr
1028233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1029178825Sdfrkrb5_cc_cache_get_first (krb5_context context,
1030178825Sdfr			 const char *type,
1031178825Sdfr			 krb5_cc_cache_cursor *cursor)
1032178825Sdfr{
1033178825Sdfr    const krb5_cc_ops *ops;
1034178825Sdfr    krb5_error_code ret;
1035178825Sdfr
1036178825Sdfr    if (type == NULL)
1037178825Sdfr	type = krb5_cc_default_name(context);
1038178825Sdfr
1039178825Sdfr    ops = krb5_cc_get_prefix_ops(context, type);
1040178825Sdfr    if (ops == NULL) {
1041233294Sstas	krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
1042233294Sstas			       "Unknown type \"%s\" when iterating "
1043233294Sstas			       "trying to iterate the credential caches", type);
1044178825Sdfr	return KRB5_CC_UNKNOWN_TYPE;
1045178825Sdfr    }
1046178825Sdfr
1047178825Sdfr    if (ops->get_cache_first == NULL) {
1048233294Sstas	krb5_set_error_message(context, KRB5_CC_NOSUPP,
1049233294Sstas			       N_("Credential cache type %s doesn't support "
1050233294Sstas				 "iterations over caches", "type"),
1051233294Sstas			       ops->prefix);
1052178825Sdfr	return KRB5_CC_NOSUPP;
1053178825Sdfr    }
1054178825Sdfr
1055178825Sdfr    *cursor = calloc(1, sizeof(**cursor));
1056178825Sdfr    if (*cursor == NULL) {
1057233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1058178825Sdfr	return ENOMEM;
1059178825Sdfr    }
1060178825Sdfr
1061178825Sdfr    (*cursor)->ops = ops;
1062178825Sdfr
1063178825Sdfr    ret = ops->get_cache_first(context, &(*cursor)->cursor);
1064178825Sdfr    if (ret) {
1065178825Sdfr	free(*cursor);
1066178825Sdfr	*cursor = NULL;
1067178825Sdfr    }
1068178825Sdfr    return ret;
1069178825Sdfr}
1070178825Sdfr
1071178825Sdfr/**
1072178825Sdfr * Retrieve the next cache pointed to by (`cursor') in `id'
1073178825Sdfr * and advance `cursor'.
1074178825Sdfr *
1075233294Sstas * @param context A Kerberos 5 context
1076233294Sstas * @param cursor the iterator cursor, returned by krb5_cc_cache_get_first()
1077233294Sstas * @param id next ccache
1078178825Sdfr *
1079233294Sstas * @return Return 0 or an error code. Returns KRB5_CC_END when the end
1080233294Sstas *         of caches is reached, see krb5_get_error_message().
1081233294Sstas *
1082178825Sdfr * @ingroup krb5_ccache
1083178825Sdfr */
1084178825Sdfr
1085178825Sdfr
1086233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1087178825Sdfrkrb5_cc_cache_next (krb5_context context,
1088178825Sdfr		   krb5_cc_cache_cursor cursor,
1089178825Sdfr		   krb5_ccache *id)
1090178825Sdfr{
1091178825Sdfr    return cursor->ops->get_cache_next(context, cursor->cursor, id);
1092178825Sdfr}
1093178825Sdfr
1094178825Sdfr/**
1095178825Sdfr * Destroy the cursor `cursor'.
1096178825Sdfr *
1097233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
1098178825Sdfr *
1099178825Sdfr * @ingroup krb5_ccache
1100178825Sdfr */
1101178825Sdfr
1102178825Sdfr
1103233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1104178825Sdfrkrb5_cc_cache_end_seq_get (krb5_context context,
1105178825Sdfr			   krb5_cc_cache_cursor cursor)
1106178825Sdfr{
1107178825Sdfr    krb5_error_code ret;
1108178825Sdfr    ret = cursor->ops->end_cache_get(context, cursor->cursor);
1109178825Sdfr    cursor->ops = NULL;
1110178825Sdfr    free(cursor);
1111178825Sdfr    return ret;
1112178825Sdfr}
1113178825Sdfr
1114178825Sdfr/**
1115233294Sstas * Search for a matching credential cache that have the
1116233294Sstas * `principal' as the default principal. On success, `id' needs to be
1117233294Sstas * freed with krb5_cc_close() or krb5_cc_destroy().
1118178825Sdfr *
1119233294Sstas * @param context A Kerberos 5 context
1120233294Sstas * @param client The principal to search for
1121233294Sstas * @param id the returned credential cache
1122233294Sstas *
1123178825Sdfr * @return On failure, error code is returned and `id' is set to NULL.
1124178825Sdfr *
1125178825Sdfr * @ingroup krb5_ccache
1126178825Sdfr */
1127178825Sdfr
1128178825Sdfr
1129233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1130178825Sdfrkrb5_cc_cache_match (krb5_context context,
1131178825Sdfr		     krb5_principal client,
1132178825Sdfr		     krb5_ccache *id)
1133178825Sdfr{
1134233294Sstas    krb5_cccol_cursor cursor;
1135178825Sdfr    krb5_error_code ret;
1136178825Sdfr    krb5_ccache cache = NULL;
1137178825Sdfr
1138178825Sdfr    *id = NULL;
1139178825Sdfr
1140233294Sstas    ret = krb5_cccol_cursor_new (context, &cursor);
1141178825Sdfr    if (ret)
1142178825Sdfr	return ret;
1143178825Sdfr
1144233294Sstas    while (krb5_cccol_cursor_next (context, cursor, &cache) == 0 && cache != NULL) {
1145178825Sdfr	krb5_principal principal;
1146178825Sdfr
1147178825Sdfr	ret = krb5_cc_get_principal(context, cache, &principal);
1148178825Sdfr	if (ret == 0) {
1149178825Sdfr	    krb5_boolean match;
1150233294Sstas
1151178825Sdfr	    match = krb5_principal_compare(context, principal, client);
1152178825Sdfr	    krb5_free_principal(context, principal);
1153178825Sdfr	    if (match)
1154178825Sdfr		break;
1155178825Sdfr	}
1156178825Sdfr
1157178825Sdfr	krb5_cc_close(context, cache);
1158178825Sdfr	cache = NULL;
1159178825Sdfr    }
1160178825Sdfr
1161233294Sstas    krb5_cccol_cursor_free(context, &cursor);
1162178825Sdfr
1163178825Sdfr    if (cache == NULL) {
1164178825Sdfr	char *str;
1165178825Sdfr
1166178825Sdfr	krb5_unparse_name(context, client, &str);
1167178825Sdfr
1168233294Sstas	krb5_set_error_message(context, KRB5_CC_NOTFOUND,
1169233294Sstas			       N_("Principal %s not found in any "
1170233294Sstas				  "credential cache", ""),
1171233294Sstas			       str ? str : "<out of memory>");
1172178825Sdfr	if (str)
1173178825Sdfr	    free(str);
1174178825Sdfr	return KRB5_CC_NOTFOUND;
1175178825Sdfr    }
1176178825Sdfr    *id = cache;
1177178825Sdfr
1178178825Sdfr    return 0;
1179178825Sdfr}
1180178825Sdfr
1181178825Sdfr/**
1182178825Sdfr * Move the content from one credential cache to another. The
1183233294Sstas * operation is an atomic switch.
1184178825Sdfr *
1185178825Sdfr * @param context a Keberos context
1186178825Sdfr * @param from the credential cache to move the content from
1187178825Sdfr * @param to the credential cache to move the content to
1188178825Sdfr
1189178825Sdfr * @return On sucess, from is freed. On failure, error code is
1190233294Sstas * returned and from and to are both still allocated, see krb5_get_error_message().
1191178825Sdfr *
1192178825Sdfr * @ingroup krb5_ccache
1193178825Sdfr */
1194178825Sdfr
1195233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1196178825Sdfrkrb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
1197178825Sdfr{
1198178825Sdfr    krb5_error_code ret;
1199178825Sdfr
1200178825Sdfr    if (strcmp(from->ops->prefix, to->ops->prefix) != 0) {
1201233294Sstas	krb5_set_error_message(context, KRB5_CC_NOSUPP,
1202233294Sstas			       N_("Moving credentials between diffrent "
1203233294Sstas				 "types not yet supported", ""));
1204178825Sdfr	return KRB5_CC_NOSUPP;
1205178825Sdfr    }
1206178825Sdfr
1207178825Sdfr    ret = (*to->ops->move)(context, from, to);
1208178825Sdfr    if (ret == 0) {
1209178825Sdfr	memset(from, 0, sizeof(*from));
1210178825Sdfr	free(from);
1211178825Sdfr    }
1212178825Sdfr    return ret;
1213178825Sdfr}
1214233294Sstas
1215233294Sstas#define KRB5_CONF_NAME "krb5_ccache_conf_data"
1216233294Sstas#define KRB5_REALM_NAME "X-CACHECONF:"
1217233294Sstas
1218233294Sstasstatic krb5_error_code
1219233294Sstasbuild_conf_principals(krb5_context context, krb5_ccache id,
1220233294Sstas		      krb5_const_principal principal,
1221233294Sstas		      const char *name, krb5_creds *cred)
1222233294Sstas{
1223233294Sstas    krb5_principal client;
1224233294Sstas    krb5_error_code ret;
1225233294Sstas    char *pname = NULL;
1226233294Sstas
1227233294Sstas    memset(cred, 0, sizeof(*cred));
1228233294Sstas
1229233294Sstas    ret = krb5_cc_get_principal(context, id, &client);
1230233294Sstas    if (ret)
1231233294Sstas	return ret;
1232233294Sstas
1233233294Sstas    if (principal) {
1234233294Sstas	ret = krb5_unparse_name(context, principal, &pname);
1235233294Sstas	if (ret)
1236233294Sstas	    return ret;
1237233294Sstas    }
1238233294Sstas
1239233294Sstas    ret = krb5_make_principal(context, &cred->server,
1240233294Sstas			      KRB5_REALM_NAME,
1241233294Sstas			      KRB5_CONF_NAME, name, pname, NULL);
1242233294Sstas    free(pname);
1243233294Sstas    if (ret) {
1244233294Sstas	krb5_free_principal(context, client);
1245233294Sstas	return ret;
1246233294Sstas    }
1247233294Sstas    ret = krb5_copy_principal(context, client, &cred->client);
1248233294Sstas    krb5_free_principal(context, client);
1249233294Sstas    return ret;
1250233294Sstas}
1251233294Sstas
1252233294Sstas/**
1253233294Sstas * Return TRUE (non zero) if the principal is a configuration
1254233294Sstas * principal (generated part of krb5_cc_set_config()). Returns FALSE
1255233294Sstas * (zero) if not a configuration principal.
1256233294Sstas *
1257233294Sstas * @param context a Keberos context
1258233294Sstas * @param principal principal to check if it a configuration principal
1259233294Sstas *
1260233294Sstas * @ingroup krb5_ccache
1261233294Sstas */
1262233294Sstas
1263233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1264233294Sstaskrb5_is_config_principal(krb5_context context,
1265233294Sstas			 krb5_const_principal principal)
1266233294Sstas{
1267233294Sstas    if (strcmp(principal->realm, KRB5_REALM_NAME) != 0)
1268233294Sstas	return FALSE;
1269233294Sstas
1270233294Sstas    if (principal->name.name_string.len == 0 ||
1271233294Sstas	strcmp(principal->name.name_string.val[0], KRB5_CONF_NAME) != 0)
1272233294Sstas	return FALSE;
1273233294Sstas
1274233294Sstas    return TRUE;
1275233294Sstas}
1276233294Sstas
1277233294Sstas/**
1278233294Sstas * Store some configuration for the credential cache in the cache.
1279233294Sstas * Existing configuration under the same name is over-written.
1280233294Sstas *
1281233294Sstas * @param context a Keberos context
1282233294Sstas * @param id the credential cache to store the data for
1283233294Sstas * @param principal configuration for a specific principal, if
1284233294Sstas * NULL, global for the whole cache.
1285233294Sstas * @param name name under which the configuraion is stored.
1286233294Sstas * @param data data to store, if NULL, configure is removed.
1287233294Sstas *
1288233294Sstas * @ingroup krb5_ccache
1289233294Sstas */
1290233294Sstas
1291233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1292233294Sstaskrb5_cc_set_config(krb5_context context, krb5_ccache id,
1293233294Sstas		   krb5_const_principal principal,
1294233294Sstas		   const char *name, krb5_data *data)
1295233294Sstas{
1296233294Sstas    krb5_error_code ret;
1297233294Sstas    krb5_creds cred;
1298233294Sstas
1299233294Sstas    ret = build_conf_principals(context, id, principal, name, &cred);
1300233294Sstas    if (ret)
1301233294Sstas	goto out;
1302233294Sstas
1303233294Sstas    /* Remove old configuration */
1304233294Sstas    ret = krb5_cc_remove_cred(context, id, 0, &cred);
1305233294Sstas    if (ret && ret != KRB5_CC_NOTFOUND)
1306233294Sstas        goto out;
1307233294Sstas
1308233294Sstas    if (data) {
1309233294Sstas	/* not that anyone care when this expire */
1310233294Sstas	cred.times.authtime = time(NULL);
1311233294Sstas	cred.times.endtime = cred.times.authtime + 3600 * 24 * 30;
1312233294Sstas
1313233294Sstas	ret = krb5_data_copy(&cred.ticket, data->data, data->length);
1314233294Sstas	if (ret)
1315233294Sstas	    goto out;
1316233294Sstas
1317233294Sstas	ret = krb5_cc_store_cred(context, id, &cred);
1318233294Sstas    }
1319233294Sstas
1320233294Sstasout:
1321233294Sstas    krb5_free_cred_contents (context, &cred);
1322233294Sstas    return ret;
1323233294Sstas}
1324233294Sstas
1325233294Sstas/**
1326233294Sstas * Get some configuration for the credential cache in the cache.
1327233294Sstas *
1328233294Sstas * @param context a Keberos context
1329233294Sstas * @param id the credential cache to store the data for
1330233294Sstas * @param principal configuration for a specific principal, if
1331233294Sstas * NULL, global for the whole cache.
1332233294Sstas * @param name name under which the configuraion is stored.
1333233294Sstas * @param data data to fetched, free with krb5_data_free()
1334233294Sstas *
1335233294Sstas * @ingroup krb5_ccache
1336233294Sstas */
1337233294Sstas
1338233294Sstas
1339233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1340233294Sstaskrb5_cc_get_config(krb5_context context, krb5_ccache id,
1341233294Sstas		   krb5_const_principal principal,
1342233294Sstas		   const char *name, krb5_data *data)
1343233294Sstas{
1344233294Sstas    krb5_creds mcred, cred;
1345233294Sstas    krb5_error_code ret;
1346233294Sstas
1347233294Sstas    memset(&cred, 0, sizeof(cred));
1348233294Sstas    krb5_data_zero(data);
1349233294Sstas
1350233294Sstas    ret = build_conf_principals(context, id, principal, name, &mcred);
1351233294Sstas    if (ret)
1352233294Sstas	goto out;
1353233294Sstas
1354233294Sstas    ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred);
1355233294Sstas    if (ret)
1356233294Sstas	goto out;
1357233294Sstas
1358233294Sstas    ret = krb5_data_copy(data, cred.ticket.data, cred.ticket.length);
1359233294Sstas
1360233294Sstasout:
1361233294Sstas    krb5_free_cred_contents (context, &cred);
1362233294Sstas    krb5_free_cred_contents (context, &mcred);
1363233294Sstas    return ret;
1364233294Sstas}
1365233294Sstas
1366233294Sstas/*
1367233294Sstas *
1368233294Sstas */
1369233294Sstas
1370233294Sstasstruct krb5_cccol_cursor_data {
1371233294Sstas    int idx;
1372233294Sstas    krb5_cc_cache_cursor cursor;
1373233294Sstas};
1374233294Sstas
1375233294Sstas/**
1376233294Sstas * Get a new cache interation cursor that will interate over all
1377233294Sstas * credentials caches independent of type.
1378233294Sstas *
1379233294Sstas * @param context a Keberos context
1380233294Sstas * @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free().
1381233294Sstas *
1382233294Sstas * @return Returns 0 or and error code, see krb5_get_error_message().
1383233294Sstas *
1384233294Sstas * @ingroup krb5_ccache
1385233294Sstas */
1386233294Sstas
1387233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1388233294Sstaskrb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor)
1389233294Sstas{
1390233294Sstas    *cursor = calloc(1, sizeof(**cursor));
1391233294Sstas    if (*cursor == NULL) {
1392233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1393233294Sstas	return ENOMEM;
1394233294Sstas    }
1395233294Sstas    (*cursor)->idx = 0;
1396233294Sstas    (*cursor)->cursor = NULL;
1397233294Sstas
1398233294Sstas    return 0;
1399233294Sstas}
1400233294Sstas
1401233294Sstas/**
1402233294Sstas * Get next credential cache from the iteration.
1403233294Sstas *
1404233294Sstas * @param context A Kerberos 5 context
1405233294Sstas * @param cursor the iteration cursor
1406233294Sstas * @param cache the returned cursor, pointer is set to NULL on failure
1407233294Sstas *        and a cache on success. The returned cache needs to be freed
1408233294Sstas *        with krb5_cc_close() or destroyed with krb5_cc_destroy().
1409233294Sstas *        MIT Kerberos behavies slightly diffrent and sets cache to NULL
1410233294Sstas *        when all caches are iterated over and return 0.
1411233294Sstas *
1412233294Sstas * @return Return 0 or and error, KRB5_CC_END is returned at the end
1413233294Sstas *        of iteration. See krb5_get_error_message().
1414233294Sstas *
1415233294Sstas * @ingroup krb5_ccache
1416233294Sstas */
1417233294Sstas
1418233294Sstas
1419233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1420233294Sstaskrb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor,
1421233294Sstas		       krb5_ccache *cache)
1422233294Sstas{
1423233294Sstas    krb5_error_code ret;
1424233294Sstas
1425233294Sstas    *cache = NULL;
1426233294Sstas
1427233294Sstas    while (cursor->idx < context->num_cc_ops) {
1428233294Sstas
1429233294Sstas	if (cursor->cursor == NULL) {
1430233294Sstas	    ret = krb5_cc_cache_get_first (context,
1431233294Sstas					   context->cc_ops[cursor->idx]->prefix,
1432233294Sstas					   &cursor->cursor);
1433233294Sstas	    if (ret) {
1434233294Sstas		cursor->idx++;
1435233294Sstas		continue;
1436233294Sstas	    }
1437233294Sstas	}
1438233294Sstas	ret = krb5_cc_cache_next(context, cursor->cursor, cache);
1439233294Sstas	if (ret == 0)
1440233294Sstas	    break;
1441233294Sstas
1442233294Sstas	krb5_cc_cache_end_seq_get(context, cursor->cursor);
1443233294Sstas	cursor->cursor = NULL;
1444233294Sstas	if (ret != KRB5_CC_END)
1445233294Sstas	    break;
1446233294Sstas
1447233294Sstas	cursor->idx++;
1448233294Sstas    }
1449233294Sstas    if (cursor->idx >= context->num_cc_ops) {
1450233294Sstas	krb5_set_error_message(context, KRB5_CC_END,
1451233294Sstas			       N_("Reached end of credential caches", ""));
1452233294Sstas	return KRB5_CC_END;
1453233294Sstas    }
1454233294Sstas
1455233294Sstas    return 0;
1456233294Sstas}
1457233294Sstas
1458233294Sstas/**
1459233294Sstas * End an iteration and free all resources, can be done before end is reached.
1460233294Sstas *
1461233294Sstas * @param context A Kerberos 5 context
1462233294Sstas * @param cursor the iteration cursor to be freed.
1463233294Sstas *
1464233294Sstas * @return Return 0 or and error, KRB5_CC_END is returned at the end
1465233294Sstas *        of iteration. See krb5_get_error_message().
1466233294Sstas *
1467233294Sstas * @ingroup krb5_ccache
1468233294Sstas */
1469233294Sstas
1470233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1471233294Sstaskrb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor)
1472233294Sstas{
1473233294Sstas    krb5_cccol_cursor c = *cursor;
1474233294Sstas
1475233294Sstas    *cursor = NULL;
1476233294Sstas    if (c) {
1477233294Sstas	if (c->cursor)
1478233294Sstas	    krb5_cc_cache_end_seq_get(context, c->cursor);
1479233294Sstas	free(c);
1480233294Sstas    }
1481233294Sstas    return 0;
1482233294Sstas}
1483233294Sstas
1484233294Sstas/**
1485233294Sstas * Return the last time the credential cache was modified.
1486233294Sstas *
1487233294Sstas * @param context A Kerberos 5 context
1488233294Sstas * @param id The credential cache to probe
1489233294Sstas * @param mtime the last modification time, set to 0 on error.
1490233294Sstas
1491233294Sstas * @return Return 0 or and error. See krb5_get_error_message().
1492233294Sstas *
1493233294Sstas * @ingroup krb5_ccache
1494233294Sstas */
1495233294Sstas
1496233294Sstas
1497233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1498233294Sstaskrb5_cc_last_change_time(krb5_context context,
1499233294Sstas			 krb5_ccache id,
1500233294Sstas			 krb5_timestamp *mtime)
1501233294Sstas{
1502233294Sstas    *mtime = 0;
1503233294Sstas    return (*id->ops->lastchange)(context, id, mtime);
1504233294Sstas}
1505233294Sstas
1506233294Sstas/**
1507233294Sstas * Return the last modfication time for a cache collection. The query
1508233294Sstas * can be limited to a specific cache type. If the function return 0
1509233294Sstas * and mtime is 0, there was no credentials in the caches.
1510233294Sstas *
1511233294Sstas * @param context A Kerberos 5 context
1512233294Sstas * @param type The credential cache to probe, if NULL, all type are traversed.
1513233294Sstas * @param mtime the last modification time, set to 0 on error.
1514233294Sstas
1515233294Sstas * @return Return 0 or and error. See krb5_get_error_message().
1516233294Sstas *
1517233294Sstas * @ingroup krb5_ccache
1518233294Sstas */
1519233294Sstas
1520233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1521233294Sstaskrb5_cccol_last_change_time(krb5_context context,
1522233294Sstas			    const char *type,
1523233294Sstas			    krb5_timestamp *mtime)
1524233294Sstas{
1525233294Sstas    krb5_cccol_cursor cursor;
1526233294Sstas    krb5_error_code ret;
1527233294Sstas    krb5_ccache id;
1528233294Sstas    krb5_timestamp t = 0;
1529233294Sstas
1530233294Sstas    *mtime = 0;
1531233294Sstas
1532233294Sstas    ret = krb5_cccol_cursor_new (context, &cursor);
1533233294Sstas    if (ret)
1534233294Sstas	return ret;
1535233294Sstas
1536233294Sstas    while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) {
1537233294Sstas
1538233294Sstas	if (type && strcmp(krb5_cc_get_type(context, id), type) != 0)
1539233294Sstas	    continue;
1540233294Sstas
1541233294Sstas	ret = krb5_cc_last_change_time(context, id, &t);
1542233294Sstas	krb5_cc_close(context, id);
1543233294Sstas	if (ret)
1544233294Sstas	    continue;
1545233294Sstas	if (t > *mtime)
1546233294Sstas	    *mtime = t;
1547233294Sstas    }
1548233294Sstas
1549233294Sstas    krb5_cccol_cursor_free(context, &cursor);
1550233294Sstas
1551233294Sstas    return 0;
1552233294Sstas}
1553233294Sstas/**
1554233294Sstas * Return a friendly name on credential cache. Free the result with krb5_xfree().
1555233294Sstas *
1556233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
1557233294Sstas *
1558233294Sstas * @ingroup krb5_ccache
1559233294Sstas */
1560233294Sstas
1561233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1562233294Sstaskrb5_cc_get_friendly_name(krb5_context context,
1563233294Sstas			  krb5_ccache id,
1564233294Sstas			  char **name)
1565233294Sstas{
1566233294Sstas    krb5_error_code ret;
1567233294Sstas    krb5_data data;
1568233294Sstas
1569233294Sstas    ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data);
1570233294Sstas    if (ret) {
1571233294Sstas	krb5_principal principal;
1572233294Sstas	ret = krb5_cc_get_principal(context, id, &principal);
1573233294Sstas	if (ret)
1574233294Sstas	    return ret;
1575233294Sstas	ret = krb5_unparse_name(context, principal, name);
1576233294Sstas	krb5_free_principal(context, principal);
1577233294Sstas    } else {
1578233294Sstas	ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data);
1579233294Sstas	krb5_data_free(&data);
1580233294Sstas	if (ret <= 0) {
1581233294Sstas	    ret = ENOMEM;
1582233294Sstas	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1583233294Sstas	} else
1584233294Sstas	    ret = 0;
1585233294Sstas    }
1586233294Sstas
1587233294Sstas    return ret;
1588233294Sstas}
1589233294Sstas
1590233294Sstas/**
1591233294Sstas * Set the friendly name on credential cache.
1592233294Sstas *
1593233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
1594233294Sstas *
1595233294Sstas * @ingroup krb5_ccache
1596233294Sstas */
1597233294Sstas
1598233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1599233294Sstaskrb5_cc_set_friendly_name(krb5_context context,
1600233294Sstas			  krb5_ccache id,
1601233294Sstas			  const char *name)
1602233294Sstas{
1603233294Sstas    krb5_data data;
1604233294Sstas
1605233294Sstas    data.data = rk_UNCONST(name);
1606233294Sstas    data.length = strlen(name);
1607233294Sstas
1608233294Sstas    return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data);
1609233294Sstas}
1610233294Sstas
1611233294Sstas/**
1612233294Sstas * Get the lifetime of the initial ticket in the cache
1613233294Sstas *
1614233294Sstas * Get the lifetime of the initial ticket in the cache, if the initial
1615233294Sstas * ticket was not found, the error code KRB5_CC_END is returned.
1616233294Sstas *
1617233294Sstas * @param context A Kerberos 5 context.
1618233294Sstas * @param id a credential cache
1619233294Sstas * @param t the relative lifetime of the initial ticket
1620233294Sstas *
1621233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
1622233294Sstas *
1623233294Sstas * @ingroup krb5_ccache
1624233294Sstas */
1625233294Sstas
1626233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1627233294Sstaskrb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t)
1628233294Sstas{
1629233294Sstas    krb5_cc_cursor cursor;
1630233294Sstas    krb5_error_code ret;
1631233294Sstas    krb5_creds cred;
1632233294Sstas    time_t now;
1633233294Sstas
1634233294Sstas    *t = 0;
1635233294Sstas    now = time(NULL);
1636233294Sstas
1637233294Sstas    ret = krb5_cc_start_seq_get(context, id, &cursor);
1638233294Sstas    if (ret)
1639233294Sstas	return ret;
1640233294Sstas
1641233294Sstas    while ((ret = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) {
1642233294Sstas	if (cred.flags.b.initial) {
1643233294Sstas	    if (now < cred.times.endtime)
1644233294Sstas		*t = cred.times.endtime - now;
1645233294Sstas	    krb5_free_cred_contents(context, &cred);
1646233294Sstas	    break;
1647233294Sstas	}
1648233294Sstas	krb5_free_cred_contents(context, &cred);
1649233294Sstas    }
1650233294Sstas
1651233294Sstas    krb5_cc_end_seq_get(context, id, &cursor);
1652233294Sstas
1653233294Sstas    return ret;
1654233294Sstas}
1655233294Sstas
1656233294Sstas/**
1657233294Sstas * Set the time offset betwen the client and the KDC
1658233294Sstas *
1659233294Sstas * If the backend doesn't support KDC offset, use the context global setting.
1660233294Sstas *
1661233294Sstas * @param context A Kerberos 5 context.
1662233294Sstas * @param id a credential cache
1663233294Sstas * @param offset the offset in seconds
1664233294Sstas *
1665233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
1666233294Sstas *
1667233294Sstas * @ingroup krb5_ccache
1668233294Sstas */
1669233294Sstas
1670233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1671233294Sstaskrb5_cc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat offset)
1672233294Sstas{
1673233294Sstas    if (id->ops->set_kdc_offset == NULL) {
1674233294Sstas	context->kdc_sec_offset = offset;
1675233294Sstas	context->kdc_usec_offset = 0;
1676233294Sstas	return 0;
1677233294Sstas    }
1678233294Sstas    return (*id->ops->set_kdc_offset)(context, id, offset);
1679233294Sstas}
1680233294Sstas
1681233294Sstas/**
1682233294Sstas * Get the time offset betwen the client and the KDC
1683233294Sstas *
1684233294Sstas * If the backend doesn't support KDC offset, use the context global setting.
1685233294Sstas *
1686233294Sstas * @param context A Kerberos 5 context.
1687233294Sstas * @param id a credential cache
1688233294Sstas * @param offset the offset in seconds
1689233294Sstas *
1690233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
1691233294Sstas *
1692233294Sstas * @ingroup krb5_ccache
1693233294Sstas */
1694233294Sstas
1695233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1696233294Sstaskrb5_cc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *offset)
1697233294Sstas{
1698233294Sstas    if (id->ops->get_kdc_offset == NULL) {
1699233294Sstas	*offset = context->kdc_sec_offset;
1700233294Sstas	return 0;
1701233294Sstas    }
1702233294Sstas    return (*id->ops->get_kdc_offset)(context, id, offset);
1703233294Sstas}
1704233294Sstas
1705233294Sstas
1706233294Sstas#ifdef _WIN32
1707233294Sstas
1708233294Sstas#define REGPATH_MIT_KRB5 "SOFTWARE\\MIT\\Kerberos5"
1709233294Sstaschar *
1710233294Sstas_krb5_get_default_cc_name_from_registry(krb5_context context)
1711233294Sstas{
1712233294Sstas    HKEY hk_k5 = 0;
1713233294Sstas    LONG code;
1714233294Sstas    char * ccname = NULL;
1715233294Sstas
1716233294Sstas    code = RegOpenKeyEx(HKEY_CURRENT_USER,
1717233294Sstas                        REGPATH_MIT_KRB5,
1718233294Sstas                        0, KEY_READ, &hk_k5);
1719233294Sstas
1720233294Sstas    if (code != ERROR_SUCCESS)
1721233294Sstas        return NULL;
1722233294Sstas
1723233294Sstas    ccname = _krb5_parse_reg_value_as_string(context, hk_k5, "ccname",
1724233294Sstas                                             REG_NONE, 0);
1725233294Sstas
1726233294Sstas    RegCloseKey(hk_k5);
1727233294Sstas
1728233294Sstas    return ccname;
1729233294Sstas}
1730233294Sstas
1731233294Sstasint
1732233294Sstas_krb5_set_default_cc_name_to_registry(krb5_context context, krb5_ccache id)
1733233294Sstas{
1734233294Sstas    HKEY hk_k5 = 0;
1735233294Sstas    LONG code;
1736233294Sstas    int ret = -1;
1737233294Sstas    char * ccname = NULL;
1738233294Sstas
1739233294Sstas    code = RegOpenKeyEx(HKEY_CURRENT_USER,
1740233294Sstas                        REGPATH_MIT_KRB5,
1741233294Sstas                        0, KEY_READ|KEY_WRITE, &hk_k5);
1742233294Sstas
1743233294Sstas    if (code != ERROR_SUCCESS)
1744233294Sstas        return -1;
1745233294Sstas
1746233294Sstas    ret = asprintf(&ccname, "%s:%s", krb5_cc_get_type(context, id), krb5_cc_get_name(context, id));
1747233294Sstas    if (ret < 0)
1748233294Sstas        goto cleanup;
1749233294Sstas
1750233294Sstas    ret = _krb5_store_string_to_reg_value(context, hk_k5, "ccname",
1751233294Sstas                                          REG_SZ, ccname, -1, 0);
1752233294Sstas
1753233294Sstas  cleanup:
1754233294Sstas
1755233294Sstas    if (ccname)
1756233294Sstas        free(ccname);
1757233294Sstas
1758233294Sstas    RegCloseKey(hk_k5);
1759233294Sstas
1760233294Sstas    return ret;
1761233294Sstas}
1762233294Sstas
1763233294Sstas#endif
1764