Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : *
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : *
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.
18 : *
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.
22 : *
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
33 : * SUCH DAMAGE.
34 : */
35 :
36 : #include "krb5_locl.h"
37 :
38 : /**
39 : * @page krb5_ccache_intro The credential cache functions
40 : * @section section_krb5_ccache Kerberos credential caches
41 : *
42 : * krb5_ccache structure holds a Kerberos credential cache.
43 : *
44 : * Heimdal support the follow types of credential caches:
45 : *
46 : * - SCC
47 : * Store the credential in a database
48 : * - FILE
49 : * Store the credential in memory
50 : * - MEMORY
51 : * Store the credential in memory
52 : * - API
53 : * A credential cache server based solution for Mac OS X
54 : * - KCM
55 : * A credential cache server based solution for all platforms
56 : *
57 : * @subsection Example
58 : *
59 : * This is a minimalistic version of klist:
60 : @code
61 : #include <krb5.h>
62 :
63 : int
64 : main (int argc, char **argv)
65 : {
66 : krb5_context context;
67 : krb5_cc_cursor cursor;
68 : krb5_error_code ret;
69 : krb5_ccache id;
70 : krb5_creds creds;
71 :
72 : if (krb5_init_context (&context) != 0)
73 : errx(1, "krb5_context");
74 :
75 : ret = krb5_cc_default (context, &id);
76 : if (ret)
77 : krb5_err(context, 1, ret, "krb5_cc_default");
78 :
79 : ret = krb5_cc_start_seq_get(context, id, &cursor);
80 : if (ret)
81 : krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
82 :
83 : while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){
84 : char *principal;
85 :
86 : krb5_unparse_name(context, creds.server, &principal);
87 : printf("principal: %s\\n", principal);
88 : free(principal);
89 : krb5_free_cred_contents (context, &creds);
90 : }
91 : ret = krb5_cc_end_seq_get(context, id, &cursor);
92 : if (ret)
93 : krb5_err(context, 1, ret, "krb5_cc_end_seq_get");
94 :
95 : krb5_cc_close(context, id);
96 :
97 : krb5_free_context(context);
98 : return 0;
99 : }
100 : * @endcode
101 : */
102 :
103 : static const krb5_cc_ops *
104 : cc_get_prefix_ops(krb5_context context,
105 : const char *prefix,
106 : const char **residual);
107 :
108 : /**
109 : * Add a new ccache type with operations `ops', overwriting any
110 : * existing one if `override'.
111 : *
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.
116 : *
117 : * @return Return an error code or 0, see krb5_get_error_message().
118 : *
119 : * @ingroup krb5_ccache
120 : */
121 :
122 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
123 3960020 : krb5_cc_register(krb5_context context,
124 : const krb5_cc_ops *ops,
125 : krb5_boolean override)
126 : {
127 97550 : int i;
128 :
129 11880060 : for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
130 7920040 : if(strcmp(context->cc_ops[i]->prefix, ops->prefix) == 0) {
131 0 : if(!override) {
132 0 : krb5_set_error_message(context,
133 : KRB5_CC_TYPE_EXISTS,
134 0 : N_("cache type %s already exists", "type"),
135 0 : ops->prefix);
136 0 : return KRB5_CC_TYPE_EXISTS;
137 : }
138 0 : break;
139 : }
140 : }
141 3960020 : if(i == context->num_cc_ops) {
142 3960020 : const krb5_cc_ops **o = realloc(rk_UNCONST(context->cc_ops),
143 3960020 : (context->num_cc_ops + 1) *
144 : sizeof(context->cc_ops[0]));
145 3960020 : if(o == NULL) {
146 0 : krb5_set_error_message(context, KRB5_CC_NOMEM,
147 0 : N_("malloc: out of memory", ""));
148 0 : return KRB5_CC_NOMEM;
149 : }
150 3960020 : context->cc_ops = o;
151 3960020 : context->cc_ops[context->num_cc_ops] = NULL;
152 3960020 : context->num_cc_ops++;
153 : }
154 3960020 : context->cc_ops[i] = ops;
155 3960020 : return 0;
156 : }
157 :
158 : /*
159 : * Allocate the memory for a `id' and the that function table to
160 : * `ops'. Returns 0 or and error code.
161 : */
162 :
163 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
164 338802 : _krb5_cc_allocate(krb5_context context,
165 : const krb5_cc_ops *ops,
166 : krb5_ccache *id)
167 : {
168 4286 : krb5_ccache p;
169 :
170 338802 : p = calloc(1, sizeof(*p));
171 338802 : if (p == NULL) {
172 0 : krb5_set_error_message(context, KRB5_CC_NOMEM,
173 0 : N_("malloc: out of memory", ""));
174 0 : return KRB5_CC_NOMEM;
175 : }
176 338802 : p->ops = ops;
177 338802 : *id = p;
178 :
179 338802 : return 0;
180 : }
181 :
182 : /*
183 : * Allocate memory for a new ccache in `id' with operations `ops'
184 : * and name `residual'. Return 0 or an error code.
185 : */
186 :
187 : static krb5_error_code
188 315517 : allocate_ccache(krb5_context context,
189 : const krb5_cc_ops *ops,
190 : const char *residual,
191 : const char *subsidiary,
192 : krb5_ccache *id)
193 : {
194 315517 : krb5_error_code ret = 0;
195 315517 : char *exp_residual = NULL;
196 4286 : int filepath;
197 :
198 631034 : filepath = (strcmp("FILE", ops->prefix) == 0
199 260987 : || strcmp("DIR", ops->prefix) == 0
200 576504 : || strcmp("SCC", ops->prefix) == 0);
201 :
202 315517 : if (residual)
203 315517 : ret = _krb5_expand_path_tokens(context, residual, filepath, &exp_residual);
204 315517 : if (ret == 0)
205 315517 : ret = _krb5_cc_allocate(context, ops, id);
206 :
207 315517 : if (ret == 0) {
208 315517 : if ((*id)->ops->version < KRB5_CC_OPS_VERSION_5
209 315517 : || (*id)->ops->resolve_2 == NULL) {
210 0 : ret = (*id)->ops->resolve(context, id, exp_residual);
211 : } else {
212 315517 : ret = (*id)->ops->resolve_2(context, id, exp_residual, subsidiary);
213 : }
214 : }
215 315517 : if (ret) {
216 0 : free(*id);
217 0 : *id = NULL;
218 : }
219 315517 : free(exp_residual);
220 315517 : return ret;
221 : }
222 :
223 :
224 : /**
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.
227 : *
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.
231 : *
232 : * @return Return 0 or an error code. In case of an error, id is set
233 : * to NULL, see krb5_get_error_message().
234 : *
235 : * @ingroup krb5_ccache
236 : */
237 :
238 :
239 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
240 315517 : krb5_cc_resolve(krb5_context context,
241 : const char *name,
242 : krb5_ccache *id)
243 : {
244 4286 : const krb5_cc_ops *ops;
245 315517 : const char *residual = NULL;
246 :
247 315517 : *id = NULL;
248 :
249 315517 : ops = cc_get_prefix_ops(context, name, &residual);
250 315517 : if (ops == NULL)
251 563 : ops = &krb5_fcc_ops; /* residual will point to name */
252 :
253 315517 : return allocate_ccache(context, ops, residual, NULL, id);
254 : }
255 :
256 : #ifdef _WIN32
257 : static const char *
258 : get_default_cc_type_win32(krb5_context context)
259 : {
260 : krb5_error_code ret;
261 : krb5_ccache id;
262 :
263 : /*
264 : * If the MSLSA ccache type has a principal name,
265 : * use it as the default.
266 : */
267 : ret = krb5_cc_resolve(context, "MSLSA:", &id);
268 : if (ret == 0) {
269 : krb5_principal princ;
270 : ret = krb5_cc_get_principal(context, id, &princ);
271 : krb5_cc_close(context, id);
272 : if (ret == 0) {
273 : krb5_free_principal(context, princ);
274 : return "MSLSA";
275 : }
276 : }
277 :
278 : /*
279 : * If the API: ccache can be resolved,
280 : * use it as the default.
281 : */
282 : ret = krb5_cc_resolve(context, "API:", &id);
283 : if (ret == 0) {
284 : krb5_cc_close(context, id);
285 : return "API";
286 : }
287 :
288 : return NULL;
289 : }
290 : #endif /* _WIN32 */
291 :
292 : static const char *
293 35 : get_default_cc_type(krb5_context context, int simple)
294 : {
295 0 : const char *def_ccname;
296 0 : const char *def_cctype =
297 35 : krb5_config_get_string_default(context, NULL,
298 35 : secure_getenv("KRB5CCTYPE"),
299 : "libdefaults", "default_cc_type", NULL);
300 0 : const char *def_cccol =
301 35 : krb5_config_get_string(context, NULL, "libdefaults",
302 : "default_cc_collection", NULL);
303 0 : const krb5_cc_ops *ops;
304 :
305 35 : if (!simple && (def_ccname = krb5_cc_default_name(context))) {
306 0 : ops = cc_get_prefix_ops(context, def_ccname, NULL);
307 0 : if (ops)
308 0 : return ops->prefix;
309 : }
310 35 : if (!def_cctype && def_cccol) {
311 0 : ops = cc_get_prefix_ops(context, def_cccol, NULL);
312 0 : if (ops)
313 0 : return ops->prefix;
314 : }
315 : #ifdef _WIN32
316 : if (def_cctype == NULL)
317 : def_cctype = get_default_cc_type_win32(context);
318 : #endif
319 35 : if (def_cctype == NULL)
320 35 : def_cctype = KRB5_DEFAULT_CCTYPE->prefix;
321 35 : return def_cctype;
322 : }
323 :
324 : /**
325 : * Find and allocate a ccache in `id' for the subsidiary cache named by
326 : * `subsidiary' in the collection named by `collection'.
327 : *
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.
333 : *
334 : * @return Return 0 or an error code. In case of an error, id is set
335 : * to NULL, see krb5_get_error_message().
336 : *
337 : * @ingroup krb5_ccache
338 : */
339 :
340 :
341 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
342 0 : krb5_cc_resolve_sub(krb5_context context,
343 : const char *cctype,
344 : const char *collection,
345 : const char *subsidiary,
346 : krb5_ccache *id)
347 : {
348 0 : const krb5_cc_ops *ops = NULL;
349 :
350 0 : *id = NULL;
351 :
352 : /* Get the cctype from the collection, maybe */
353 0 : if (cctype == NULL && collection)
354 0 : ops = cc_get_prefix_ops(context, collection, &collection);
355 :
356 0 : if (ops == NULL)
357 0 : ops = cc_get_prefix_ops(context, get_default_cc_type(context, 0), NULL);
358 :
359 0 : if (ops == NULL) {
360 0 : krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
361 0 : N_("unknown ccache type %s", ""), cctype);
362 0 : return KRB5_CC_UNKNOWN_TYPE;
363 : }
364 :
365 0 : return allocate_ccache(context, ops, collection, subsidiary, id);
366 : }
367 :
368 :
369 : /**
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
374 : * file name.
375 : *
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.
380 : *
381 : * @return Return 0 or an error code. In case of an error, id is set
382 : * to NULL, see krb5_get_error_message().
383 : *
384 : * @ingroup krb5_ccache
385 : */
386 :
387 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
388 0 : krb5_cc_resolve_for(krb5_context context,
389 : const char *cctype,
390 : const char *name,
391 : krb5_const_principal principal,
392 : krb5_ccache *id)
393 : {
394 0 : krb5_error_code ret;
395 0 : char *p, *s;
396 :
397 0 : *id = NULL;
398 :
399 0 : ret = krb5_unparse_name(context, principal, &p);
400 0 : if (ret)
401 0 : return ret;
402 : /*
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.
407 : */
408 0 : for (s = p; *s; s++) {
409 0 : switch (s[0]) {
410 0 : case ':':
411 : case '+':
412 : case '/':
413 : case '\\':
414 0 : s[0] = '-';
415 0 : default: break;
416 : }
417 : }
418 0 : ret = krb5_cc_resolve_sub(context, cctype, name, p, id);
419 0 : free(p);
420 0 : return ret;
421 : }
422 :
423 : /**
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.
429 : *
430 : * @return Return an error code or 0, see krb5_get_error_message().
431 : *
432 : * @ingroup krb5_ccache
433 : */
434 :
435 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
436 23285 : krb5_cc_new_unique(krb5_context context, const char *type,
437 : const char *hint, krb5_ccache *id)
438 : {
439 0 : const krb5_cc_ops *ops;
440 0 : krb5_error_code ret;
441 :
442 23285 : if (type == NULL)
443 35 : type = get_default_cc_type(context, 1);
444 :
445 23285 : ops = krb5_cc_get_prefix_ops(context, type);
446 23285 : if (ops == NULL) {
447 0 : krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
448 : "Credential cache type %s is unknown", type);
449 0 : return KRB5_CC_UNKNOWN_TYPE;
450 : }
451 :
452 23285 : ret = _krb5_cc_allocate(context, ops, id);
453 23285 : if (ret)
454 0 : return ret;
455 23285 : ret = (*id)->ops->gen_new(context, id);
456 23285 : if (ret) {
457 0 : free(*id);
458 0 : *id = NULL;
459 : }
460 23285 : return ret;
461 : }
462 :
463 : /**
464 : * Return the name of the ccache `id'
465 : *
466 : * @ingroup krb5_ccache
467 : */
468 :
469 :
470 : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
471 102461 : krb5_cc_get_name(krb5_context context,
472 : krb5_ccache id)
473 : {
474 102461 : const char *name = NULL;
475 :
476 102461 : if (id->ops->version < KRB5_CC_OPS_VERSION_5
477 102461 : || id->ops->get_name_2 == NULL)
478 0 : return id->ops->get_name(context, id);
479 :
480 102461 : (void) id->ops->get_name_2(context, id, &name, NULL, NULL);
481 102461 : return name;
482 : }
483 :
484 : /**
485 : * Return the name of the ccache collection associated with `id'
486 : *
487 : * @ingroup krb5_ccache
488 : */
489 :
490 :
491 : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
492 0 : krb5_cc_get_collection(krb5_context context, krb5_ccache id)
493 : {
494 0 : const char *name = NULL;
495 :
496 0 : if (id->ops->version < KRB5_CC_OPS_VERSION_5
497 0 : || id->ops->get_name_2 == NULL)
498 0 : return NULL;
499 :
500 0 : (void) id->ops->get_name_2(context, id, NULL, &name, NULL);
501 0 : return name;
502 : }
503 :
504 : /**
505 : * Return the name of the subsidiary ccache of `id'
506 : *
507 : * @ingroup krb5_ccache
508 : */
509 :
510 :
511 : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
512 0 : krb5_cc_get_subsidiary(krb5_context context, krb5_ccache id)
513 : {
514 0 : const char *name = NULL;
515 :
516 0 : if (id->ops->version >= KRB5_CC_OPS_VERSION_5
517 0 : && id->ops->get_name_2 != NULL)
518 0 : (void) id->ops->get_name_2(context, id, NULL, NULL, &name);
519 0 : return name;
520 : }
521 :
522 : /**
523 : * Return the type of the ccache `id'.
524 : *
525 : * @ingroup krb5_ccache
526 : */
527 :
528 :
529 : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
530 188063 : krb5_cc_get_type(krb5_context context,
531 : krb5_ccache id)
532 : {
533 188063 : return id->ops->prefix;
534 : }
535 :
536 : /**
537 : * Return the complete resolvable name the cache
538 :
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()
542 : *
543 : * @return Returns 0 or an error (and then *str is set to NULL).
544 : *
545 : * @ingroup krb5_ccache
546 : */
547 :
548 :
549 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
550 102461 : krb5_cc_get_full_name(krb5_context context,
551 : krb5_ccache id,
552 : char **str)
553 : {
554 1466 : const char *type, *name;
555 :
556 102461 : *str = NULL;
557 :
558 102461 : type = krb5_cc_get_type(context, id);
559 102461 : if (type == NULL) {
560 0 : krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
561 : "cache has no name of type");
562 0 : return KRB5_CC_UNKNOWN_TYPE;
563 : }
564 :
565 102461 : name = krb5_cc_get_name(context, id);
566 102461 : if (name == NULL) {
567 0 : krb5_set_error_message(context, KRB5_CC_BADNAME,
568 : "cache of type %s has no name", type);
569 0 : return KRB5_CC_BADNAME;
570 : }
571 :
572 102461 : if (asprintf(str, "%s:%s", type, name) == -1) {
573 0 : *str = NULL;
574 0 : return krb5_enomem(context);
575 : }
576 100995 : return 0;
577 : }
578 :
579 : /**
580 : * Return krb5_cc_ops of a the ccache `id'.
581 : *
582 : * @ingroup krb5_ccache
583 : */
584 :
585 :
586 : KRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL
587 0 : krb5_cc_get_ops(krb5_context context, krb5_ccache id)
588 : {
589 0 : return id->ops;
590 : }
591 :
592 : /*
593 : * Expand variables in `str' into `res'
594 : */
595 :
596 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
597 0 : _krb5_expand_default_cc_name(krb5_context context, const char *str, char **res)
598 : {
599 0 : int filepath;
600 :
601 0 : filepath = (strncmp("FILE:", str, 5) == 0
602 0 : || strncmp("DIR:", str, 4) == 0
603 0 : || strncmp("SCC:", str, 4) == 0);
604 :
605 0 : return _krb5_expand_path_tokens(context, str, filepath, res);
606 : }
607 :
608 : /*
609 : * Return non-zero if envirnoment that will determine default krb5cc
610 : * name has changed.
611 : */
612 :
613 : static int
614 194 : environment_changed(krb5_context context)
615 : {
616 0 : const char *e;
617 :
618 : /* if the cc name was set, don't change it */
619 194 : if (context->default_cc_name_set)
620 0 : return 0;
621 :
622 : /* XXX performance: always ask KCM/API if default name has changed */
623 194 : if (context->default_cc_name &&
624 194 : (strncmp(context->default_cc_name, "KCM:", 4) == 0 ||
625 194 : strncmp(context->default_cc_name, "API:", 4) == 0))
626 0 : return 1;
627 :
628 194 : e = secure_getenv("KRB5CCNAME");
629 194 : if (e == NULL) {
630 0 : if (context->default_cc_name_env) {
631 0 : free(context->default_cc_name_env);
632 0 : context->default_cc_name_env = NULL;
633 0 : return 1;
634 : }
635 : } else {
636 194 : if (context->default_cc_name_env == NULL)
637 0 : return 1;
638 194 : if (strcmp(e, context->default_cc_name_env) != 0)
639 0 : return 1;
640 : }
641 194 : return 0;
642 : }
643 :
644 : /**
645 : * Switch the default default credential cache for a specific
646 : * credcache type (and name for some implementations).
647 : *
648 : * @return Return an error code or 0, see krb5_get_error_message().
649 : *
650 : * @ingroup krb5_ccache
651 : */
652 :
653 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
654 113 : krb5_cc_switch(krb5_context context, krb5_ccache id)
655 : {
656 : #ifdef _WIN32
657 : _krb5_set_default_cc_name_to_registry(context, id);
658 : #endif
659 :
660 113 : if (id->ops->version == KRB5_CC_OPS_VERSION_0
661 113 : || id->ops->set_default == NULL)
662 0 : return 0;
663 :
664 113 : return (*id->ops->set_default)(context, id);
665 : }
666 :
667 : /**
668 : * Return true if the default credential cache support switch
669 : *
670 : * @ingroup krb5_ccache
671 : */
672 :
673 : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
674 52 : krb5_cc_support_switch(krb5_context context, const char *type)
675 : {
676 0 : const krb5_cc_ops *ops;
677 :
678 52 : ops = krb5_cc_get_prefix_ops(context, type);
679 52 : if (ops && ops->version > KRB5_CC_OPS_VERSION_0 && ops->set_default)
680 52 : return 1;
681 0 : return FALSE;
682 : }
683 :
684 : /**
685 : * Set the default cc name for `context' to `name'.
686 : *
687 : * @ingroup krb5_ccache
688 : */
689 :
690 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
691 85395 : krb5_cc_set_default_name(krb5_context context, const char *name)
692 : {
693 85395 : krb5_error_code ret = 0;
694 85395 : char *p = NULL;
695 :
696 85395 : if (name == NULL) {
697 437 : const char *e;
698 :
699 85395 : if ((e = secure_getenv("KRB5CCNAME"))) {
700 85395 : if ((p = strdup(e)) == NULL)
701 0 : return krb5_enomem(context);
702 :
703 85395 : free(context->default_cc_name_env);
704 85395 : context->default_cc_name_env = p;
705 :
706 85395 : if ((p = strdup(e)) == NULL)
707 0 : return krb5_enomem(context);
708 :
709 : /*
710 : * We're resetting the default ccache name. Recall that we got
711 : * this from the environment, which might change.
712 : */
713 85395 : context->default_cc_name_set = 0;
714 0 : } else if ((e = krb5_cc_configured_default_name(context))) {
715 0 : if ((p = strdup(e)) == NULL)
716 0 : return krb5_enomem(context);
717 :
718 : /*
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.
723 : *
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!
727 : */
728 0 : context->default_cc_name_set = 1;
729 : }
730 : } else {
731 0 : int filepath = (strncmp("FILE:", name, 5) == 0 ||
732 0 : strncmp("DIR:", name, 4) == 0 ||
733 0 : strncmp("SCC:", name, 4) == 0);
734 :
735 0 : ret = _krb5_expand_path_tokens(context, name, filepath, &p);
736 0 : if (ret)
737 0 : return ret;
738 :
739 : /*
740 : * Since the default ccache name was set explicitly, we won't want
741 : * environment_changed() to return true until the default ccache name
742 : * is reset.
743 : */
744 0 : context->default_cc_name_set = 1;
745 : }
746 :
747 85395 : free(context->default_cc_name);
748 85395 : context->default_cc_name = p;
749 85395 : return 0;
750 : }
751 :
752 : /**
753 : * Return a pointer to a context static string containing the default
754 : * ccache name.
755 : *
756 : * @return String to the default credential cache name.
757 : *
758 : * @ingroup krb5_ccache
759 : */
760 :
761 :
762 : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
763 85589 : krb5_cc_default_name(krb5_context context)
764 : {
765 85589 : if (context->default_cc_name == NULL || environment_changed(context))
766 85395 : krb5_cc_set_default_name(context, NULL);
767 :
768 85589 : return context->default_cc_name;
769 : }
770 :
771 : KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL
772 0 : krb5_cc_configured_default_name(krb5_context context)
773 : {
774 0 : krb5_error_code ret = 0;
775 : #ifdef _WIN32
776 : krb5_ccache id;
777 : #endif
778 0 : const char *cfg;
779 0 : char *expanded;
780 0 : const krb5_cc_ops *ops;
781 :
782 0 : if (context->configured_default_cc_name)
783 0 : return context->configured_default_cc_name;
784 :
785 : #ifdef _WIN32
786 : if ((expanded = _krb5_get_default_cc_name_from_registry(context)))
787 : return context->configured_default_cc_name = expanded;
788 : #endif
789 :
790 : /* If there's a configured default, expand the tokens and use it */
791 0 : cfg = krb5_config_get_string(context, NULL, "libdefaults",
792 : "default_cc_name", NULL);
793 0 : if (cfg == NULL)
794 0 : cfg = krb5_config_get_string(context, NULL, "libdefaults",
795 : "default_ccache_name", NULL);
796 0 : if (cfg) {
797 0 : ret = _krb5_expand_default_cc_name(context, cfg, &expanded);
798 0 : if (ret) {
799 0 : krb5_set_error_message(context, ret,
800 : "token expansion failed for %s", cfg);
801 0 : return NULL;
802 : }
803 0 : return context->configured_default_cc_name = expanded;
804 : }
805 :
806 : /* Else try a configured default ccache type's default */
807 0 : cfg = get_default_cc_type(context, 1);
808 0 : if ((ops = krb5_cc_get_prefix_ops(context, cfg)) == NULL) {
809 0 : krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
810 : "unknown configured credential cache "
811 : "type %s", cfg);
812 0 : return NULL;
813 : }
814 :
815 : /* The get_default_name() method expands any tokens */
816 0 : ret = (*ops->get_default_name)(context, &expanded);
817 0 : if (ret) {
818 0 : krb5_set_error_message(context, ret, "failed to find a default "
819 : "ccache for default ccache type %s", cfg);
820 0 : return NULL;
821 : }
822 0 : return context->configured_default_cc_name = expanded;
823 : }
824 :
825 : KRB5_LIB_FUNCTION char * KRB5_LIB_CALL
826 0 : krb5_cccol_get_default_ccname(krb5_context context)
827 : {
828 0 : const char *cfg = get_default_cc_type(context, 1);
829 0 : char *cccol_default_ccname;
830 0 : const krb5_cc_ops *ops = krb5_cc_get_prefix_ops(context, cfg);
831 :
832 0 : (void) (*ops->get_default_name)(context, &cccol_default_ccname);
833 0 : return cccol_default_ccname;
834 : }
835 :
836 : /**
837 : * Open the default ccache in `id'.
838 : *
839 : * @return Return an error code or 0, see krb5_get_error_message().
840 : *
841 : * @ingroup krb5_ccache
842 : */
843 :
844 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
845 66291 : krb5_cc_default(krb5_context context,
846 : krb5_ccache *id)
847 : {
848 66291 : const char *p = krb5_cc_default_name(context);
849 :
850 66291 : *id = NULL;
851 66291 : if (p == NULL)
852 0 : return krb5_enomem(context);
853 66291 : return krb5_cc_resolve(context, p, id);
854 : }
855 :
856 : /**
857 : * Open the named subsidiary cache from the default ccache collection in `id'.
858 : *
859 : * @return Return an error code or 0, see krb5_get_error_message().
860 : *
861 : * @ingroup krb5_ccache
862 : */
863 :
864 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
865 0 : krb5_cc_default_sub(krb5_context context,
866 : const char *subsidiary,
867 : krb5_ccache *id)
868 : {
869 0 : return krb5_cc_resolve_sub(context, get_default_cc_type(context, 0), NULL,
870 : subsidiary, id);
871 : }
872 :
873 : /**
874 : * Open the default ccache in `id' that corresponds to the given principal.
875 : *
876 : * @return Return an error code or 0, see krb5_get_error_message().
877 : *
878 : * @ingroup krb5_ccache
879 : */
880 :
881 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
882 0 : krb5_cc_default_for(krb5_context context,
883 : krb5_const_principal principal,
884 : krb5_ccache *id)
885 : {
886 0 : return krb5_cc_resolve_for(context, get_default_cc_type(context, 0), NULL,
887 : principal, id);
888 : }
889 :
890 : /**
891 : * Create a new ccache in `id' for `primary_principal'.
892 : *
893 : * @return Return an error code or 0, see krb5_get_error_message().
894 : *
895 : * @ingroup krb5_ccache
896 : */
897 :
898 :
899 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
900 230248 : krb5_cc_initialize(krb5_context context,
901 : krb5_ccache id,
902 : krb5_principal primary_principal)
903 : {
904 3264 : krb5_error_code ret;
905 :
906 230248 : ret = (*id->ops->init)(context, id, primary_principal);
907 230248 : if (ret == 0) {
908 230248 : id->cc_kx509_done = 0;
909 230248 : id->cc_initialized = 1;
910 230248 : id->cc_need_start_realm = 1;
911 230248 : id->cc_start_tgt_stored = 0;
912 : }
913 230248 : return ret;
914 : }
915 :
916 :
917 : /**
918 : * Remove the ccache `id'.
919 : *
920 : * @return Return an error code or 0, see krb5_get_error_message().
921 : *
922 : * @ingroup krb5_ccache
923 : */
924 :
925 :
926 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
927 156039 : krb5_cc_destroy(krb5_context context,
928 : krb5_ccache id)
929 : {
930 156039 : krb5_error_code ret2 = 0;
931 2382 : krb5_error_code ret;
932 2382 : krb5_data d;
933 :
934 : /*
935 : * Destroy associated hx509 PKIX credential store created by krb5_kx509*().
936 : */
937 156039 : if (krb5_cc_get_config(context, id, NULL, "kx509store", &d) == 0) {
938 0 : char *name;
939 :
940 0 : if ((name = strndup(d.data, d.length)) == NULL) {
941 0 : ret2 = krb5_enomem(context);
942 : } else {
943 0 : hx509_certs certs;
944 0 : ret = hx509_certs_init(context->hx509ctx, name, 0, NULL, &certs);
945 0 : if (ret == 0)
946 0 : ret2 = hx509_certs_destroy(context->hx509ctx, &certs);
947 : else
948 0 : hx509_certs_free(&certs);
949 0 : free(name);
950 : }
951 : }
952 :
953 156039 : ret = (*id->ops->destroy)(context, id);
954 156039 : (void) krb5_cc_close(context, id);
955 156039 : return ret ? ret : ret2;
956 : }
957 :
958 : /**
959 : * Stop using the ccache `id' and free the related resources.
960 : *
961 : * @return Return an error code or 0, see krb5_get_error_message().
962 : *
963 : * @ingroup krb5_ccache
964 : */
965 :
966 :
967 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
968 337180 : krb5_cc_close(krb5_context context,
969 : krb5_ccache id)
970 : {
971 4275 : krb5_error_code ret;
972 :
973 337180 : if (!id)
974 0 : return 0;
975 :
976 : /*
977 : * We want to automatically acquire a PKIX credential using kx509.
978 : *
979 : * This can be slow if we're generating an RSA key. Plus it means talking
980 : * to the KDC.
981 : *
982 : * We only want to do this when:
983 : *
984 : * - krb5_cc_initialize() was called on this ccache handle,
985 : * - a start TGT was stored (actually, a cross-realm TGT would do),
986 : *
987 : * and
988 : *
989 : * - we aren't creating a gss_cred_id_t for a delegated credential.
990 : *
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.
993 : *
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.
996 : *
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.
1000 : */
1001 337180 : if (id->cc_initialized && id->cc_start_tgt_stored && !id->cc_kx509_done &&
1002 84625 : strcmp("MEMORY", krb5_cc_get_type(context, id)) != 0) {
1003 0 : krb5_boolean enabled;
1004 :
1005 284 : krb5_appdefault_boolean(context, NULL, NULL, "enable_kx509", FALSE,
1006 : &enabled);
1007 284 : if (enabled) {
1008 0 : _krb5_debug(context, 2, "attempting to fetch a certificate using "
1009 : "kx509");
1010 0 : ret = krb5_kx509(context, id, NULL);
1011 0 : if (ret)
1012 0 : _krb5_debug(context, 2, "failed to fetch a certificate");
1013 : else
1014 0 : _krb5_debug(context, 2, "fetched a certificate");
1015 : }
1016 : }
1017 :
1018 337180 : ret = (*id->ops->close)(context, id);
1019 337180 : free(id);
1020 337180 : return ret;
1021 : }
1022 :
1023 : /**
1024 : * Store `creds' in the ccache `id'.
1025 : *
1026 : * @return Return an error code or 0, see krb5_get_error_message().
1027 : *
1028 : * @ingroup krb5_ccache
1029 : */
1030 :
1031 :
1032 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1033 335583 : krb5_cc_store_cred(krb5_context context,
1034 : krb5_ccache id,
1035 : krb5_creds *creds)
1036 : {
1037 5425 : krb5_error_code ret;
1038 5425 : krb5_data realm;
1039 335583 : const char *cfg = "";
1040 :
1041 : /* Automatic cc_config-setting and other actions */
1042 669826 : if (krb5_principal_get_num_comp(context, creds->server) > 1 &&
1043 334243 : krb5_is_config_principal(context, creds->server))
1044 158610 : cfg = krb5_principal_get_comp_string(context, creds->server, 1);
1045 :
1046 335583 : if (id->cc_initialized && !id->cc_need_start_realm &&
1047 77690 : strcmp(cfg, "start_realm") == 0)
1048 135 : return 0;
1049 :
1050 335448 : ret = (*id->ops->store)(context, id, creds);
1051 335448 : if (ret)
1052 0 : return ret;
1053 :
1054 335448 : if (id->cc_initialized && !id->cc_start_tgt_stored &&
1055 158558 : id->cc_need_start_realm &&
1056 158558 : krb5_principal_is_root_krbtgt(context, creds->server)) {
1057 : /* Mark the first root TGT's realm as the start realm */
1058 86125 : id->cc_start_tgt_stored = 1;
1059 86125 : realm.length = strlen(creds->server->realm);
1060 86125 : realm.data = creds->server->realm;
1061 86125 : (void) krb5_cc_set_config(context, id, NULL, "start_realm", &realm);
1062 86125 : id->cc_need_start_realm = 0;
1063 249323 : } else if (id->cc_initialized && id->cc_start_tgt_stored &&
1064 91620 : !id->cc_kx509_done && strcmp(cfg, "kx509cert") == 0) {
1065 : /*
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).
1068 : */
1069 0 : id->cc_kx509_done = 1;
1070 249323 : } else if (id->cc_initialized && id->cc_start_tgt_stored &&
1071 91620 : !id->cc_kx509_done && strcmp(cfg, "kx509_service_status") == 0) {
1072 : /*
1073 : * Do not attempt kx509 at cc close time -- we're copying a ccache and
1074 : * we know the kx509 service is not available.
1075 : */
1076 0 : id->cc_kx509_done = 1;
1077 249323 : } else if (id->cc_initialized && strcmp(cfg, "start_realm") == 0) {
1078 : /*
1079 : * If the caller is storing a start_realm ccconfig, then stop looking
1080 : * for root TGTs to mark as the start_realm.
1081 : *
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.
1085 : */
1086 158185 : id->cc_need_start_realm = 0;
1087 : }
1088 330023 : return ret;
1089 : }
1090 :
1091 : /**
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.
1095 : *
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()
1102 : *
1103 : * @return Return an error code or 0, see krb5_get_error_message().
1104 : *
1105 : * @ingroup krb5_ccache
1106 : */
1107 :
1108 :
1109 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1110 501781 : krb5_cc_retrieve_cred(krb5_context context,
1111 : krb5_ccache id,
1112 : krb5_flags whichfields,
1113 : const krb5_creds *mcreds,
1114 : krb5_creds *creds)
1115 : {
1116 11779 : krb5_error_code ret;
1117 11779 : krb5_cc_cursor cursor;
1118 :
1119 501781 : if (id->ops->retrieve != NULL) {
1120 0 : return (*id->ops->retrieve)(context, id, whichfields,
1121 : mcreds, creds);
1122 : }
1123 :
1124 501781 : ret = krb5_cc_start_seq_get(context, id, &cursor);
1125 501781 : if (ret)
1126 0 : return ret;
1127 1380497 : while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){
1128 1130174 : if(krb5_compare_creds(context, whichfields, mcreds, creds)){
1129 244971 : ret = 0;
1130 244971 : break;
1131 : }
1132 878716 : krb5_free_cred_contents (context, creds);
1133 : }
1134 501781 : krb5_cc_end_seq_get(context, id, &cursor);
1135 501781 : return ret;
1136 : }
1137 :
1138 : /**
1139 : * Return the principal of `id' in `principal'.
1140 : *
1141 : * @return Return an error code or 0, see krb5_get_error_message().
1142 : *
1143 : * @ingroup krb5_ccache
1144 : */
1145 :
1146 :
1147 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1148 854027 : krb5_cc_get_principal(krb5_context context,
1149 : krb5_ccache id,
1150 : krb5_principal *principal)
1151 : {
1152 854027 : return (*id->ops->get_princ)(context, id, principal);
1153 : }
1154 :
1155 : /**
1156 : * Start iterating over `id', `cursor' is initialized to the
1157 : * beginning. Caller must free the cursor with krb5_cc_end_seq_get().
1158 : *
1159 : * @return Return an error code or 0, see krb5_get_error_message().
1160 : *
1161 : * @ingroup krb5_ccache
1162 : */
1163 :
1164 :
1165 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1166 713489 : krb5_cc_start_seq_get (krb5_context context,
1167 : const krb5_ccache id,
1168 : krb5_cc_cursor *cursor)
1169 : {
1170 713489 : return (*id->ops->get_first)(context, id, cursor);
1171 : }
1172 :
1173 : /**
1174 : * Retrieve the next cred pointed to by (`id', `cursor') in `creds'
1175 : * and advance `cursor'.
1176 : *
1177 : * @return Return an error code or 0, see krb5_get_error_message().
1178 : *
1179 : * @ingroup krb5_ccache
1180 : */
1181 :
1182 :
1183 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1184 1909473 : krb5_cc_next_cred (krb5_context context,
1185 : const krb5_ccache id,
1186 : krb5_cc_cursor *cursor,
1187 : krb5_creds *creds)
1188 : {
1189 1909473 : return (*id->ops->get_next)(context, id, cursor, creds);
1190 : }
1191 :
1192 : /**
1193 : * Destroy the cursor `cursor'.
1194 : *
1195 : * @ingroup krb5_ccache
1196 : */
1197 :
1198 :
1199 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1200 713489 : krb5_cc_end_seq_get (krb5_context context,
1201 : const krb5_ccache id,
1202 : krb5_cc_cursor *cursor)
1203 : {
1204 713489 : return (*id->ops->end_get)(context, id, cursor);
1205 : }
1206 :
1207 : /**
1208 : * Remove the credential identified by `cred', `which' from `id'.
1209 : *
1210 : * @ingroup krb5_ccache
1211 : */
1212 :
1213 :
1214 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1215 86273 : krb5_cc_remove_cred(krb5_context context,
1216 : krb5_ccache id,
1217 : krb5_flags which,
1218 : krb5_creds *cred)
1219 : {
1220 86273 : if(id->ops->remove_cred == NULL) {
1221 0 : krb5_set_error_message(context,
1222 : EACCES,
1223 : "ccache %s does not support remove_cred",
1224 0 : id->ops->prefix);
1225 0 : return EACCES; /* XXX */
1226 : }
1227 86273 : return (*id->ops->remove_cred)(context, id, which, cred);
1228 : }
1229 :
1230 : /**
1231 : * Set the flags of `id' to `flags'.
1232 : *
1233 : * @ingroup krb5_ccache
1234 : */
1235 :
1236 :
1237 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1238 0 : krb5_cc_set_flags(krb5_context context,
1239 : krb5_ccache id,
1240 : krb5_flags flags)
1241 : {
1242 0 : return (*id->ops->set_flags)(context, id, flags);
1243 : }
1244 :
1245 : /**
1246 : * Get the flags of `id', store them in `flags'.
1247 : *
1248 : * @ingroup krb5_ccache
1249 : */
1250 :
1251 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1252 0 : krb5_cc_get_flags(krb5_context context,
1253 : krb5_ccache id,
1254 : krb5_flags *flags)
1255 : {
1256 0 : *flags = 0;
1257 0 : return 0;
1258 : }
1259 :
1260 : /**
1261 : * Copy the contents of `from' to `to' if the given match function
1262 : * return true.
1263 : *
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.
1270 : *
1271 : * @return Return an error code or 0, see krb5_get_error_message().
1272 : *
1273 : * @ingroup krb5_ccache
1274 : */
1275 :
1276 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1277 72201 : krb5_cc_copy_match_f(krb5_context context,
1278 : const krb5_ccache from,
1279 : krb5_ccache to,
1280 : krb5_boolean (*match)(krb5_context, void *, const krb5_creds *),
1281 : void *matchctx,
1282 : unsigned int *matched)
1283 : {
1284 917 : krb5_error_code ret;
1285 917 : krb5_cc_cursor cursor;
1286 917 : krb5_creds cred;
1287 917 : krb5_principal princ;
1288 :
1289 72201 : if (matched)
1290 0 : *matched = 0;
1291 :
1292 72201 : ret = krb5_cc_get_principal(context, from, &princ);
1293 72201 : if (ret)
1294 0 : return ret;
1295 72201 : ret = krb5_cc_initialize(context, to, princ);
1296 72201 : if (ret) {
1297 0 : krb5_free_principal(context, princ);
1298 0 : return ret;
1299 : }
1300 72201 : ret = krb5_cc_start_seq_get(context, from, &cursor);
1301 72201 : if (ret) {
1302 0 : krb5_free_principal(context, princ);
1303 0 : return ret;
1304 : }
1305 :
1306 217007 : while ((ret = krb5_cc_next_cred(context, from, &cursor, &cred)) == 0) {
1307 144806 : if (match == NULL || (*match)(context, matchctx, &cred)) {
1308 144806 : if (matched)
1309 0 : (*matched)++;
1310 144806 : ret = krb5_cc_store_cred(context, to, &cred);
1311 144806 : if (ret)
1312 0 : break;
1313 : }
1314 144806 : krb5_free_cred_contents(context, &cred);
1315 : }
1316 72201 : krb5_cc_end_seq_get(context, from, &cursor);
1317 72201 : krb5_free_principal(context, princ);
1318 72201 : if (ret == KRB5_CC_END)
1319 72201 : ret = 0;
1320 71284 : return ret;
1321 : }
1322 :
1323 : /**
1324 : * Just like krb5_cc_copy_match_f(), but copy everything.
1325 : *
1326 : * @ingroup @krb5_ccache
1327 : */
1328 :
1329 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1330 335 : krb5_cc_copy_cache(krb5_context context,
1331 : const krb5_ccache from,
1332 : krb5_ccache to)
1333 : {
1334 335 : return krb5_cc_copy_match_f(context, from, to, NULL, NULL, NULL);
1335 : }
1336 :
1337 : /**
1338 : * Return the version of `id'.
1339 : *
1340 : * @ingroup krb5_ccache
1341 : */
1342 :
1343 :
1344 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1345 0 : krb5_cc_get_version(krb5_context context,
1346 : const krb5_ccache id)
1347 : {
1348 0 : if(id->ops->get_version)
1349 0 : return (*id->ops->get_version)(context, id);
1350 : else
1351 0 : return 0;
1352 : }
1353 :
1354 : /**
1355 : * Clear `mcreds' so it can be used with krb5_cc_retrieve_cred
1356 : *
1357 : * @ingroup krb5_ccache
1358 : */
1359 :
1360 :
1361 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
1362 32299 : krb5_cc_clear_mcred(krb5_creds *mcred)
1363 : {
1364 32299 : memset(mcred, 0, sizeof(*mcred));
1365 32299 : }
1366 :
1367 : /**
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.
1373 : *
1374 : * @return Returns NULL if ops not found.
1375 : *
1376 : * @ingroup krb5_ccache
1377 : */
1378 :
1379 :
1380 : KRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL
1381 23597 : krb5_cc_get_prefix_ops(krb5_context context, const char *prefix)
1382 : {
1383 23597 : return cc_get_prefix_ops(context, prefix, NULL);
1384 : }
1385 :
1386 : /**
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.
1392 : *
1393 : * If residual is non-NULL, it is set to the residual component of
1394 : * prefix (if present) or the prefix itself.
1395 : *
1396 : * @return Returns NULL if ops not found.
1397 : *
1398 : * @ingroup krb5_ccache
1399 : */
1400 :
1401 :
1402 : static const krb5_cc_ops *
1403 339114 : cc_get_prefix_ops(krb5_context context,
1404 : const char *prefix,
1405 : const char **residual)
1406 : {
1407 4286 : int i;
1408 :
1409 339114 : if (residual)
1410 315517 : *residual = prefix;
1411 :
1412 339114 : if (prefix == NULL)
1413 0 : return KRB5_DEFAULT_CCTYPE;
1414 :
1415 : /* Is absolute path? Or UNC path? */
1416 339114 : if (ISPATHSEP(prefix[0]))
1417 26146 : return &krb5_fcc_ops;
1418 :
1419 : #ifdef _WIN32
1420 : /* Is drive letter? */
1421 : if (isalpha((unsigned char)prefix[0]) && prefix[1] == ':')
1422 : return &krb5_fcc_ops;
1423 : #endif
1424 :
1425 1196560 : for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
1426 1195997 : size_t prefix_len = strlen(context->cc_ops[i]->prefix);
1427 :
1428 1195997 : if (strncmp(context->cc_ops[i]->prefix, prefix, prefix_len) == 0 &&
1429 312361 : (prefix[prefix_len] == ':' || prefix[prefix_len] == '\0')) {
1430 312361 : if (residual) {
1431 288764 : if (prefix[prefix_len] == ':' && prefix[prefix_len + 1] != '\0')
1432 288764 : *residual = &prefix[prefix_len + 1];
1433 : else
1434 0 : *residual = NULL;
1435 : }
1436 :
1437 312361 : return context->cc_ops[i];
1438 : }
1439 : }
1440 :
1441 563 : return NULL;
1442 : }
1443 :
1444 : struct krb5_cc_cache_cursor_data {
1445 : const krb5_cc_ops *ops;
1446 : krb5_cc_cursor cursor;
1447 : };
1448 :
1449 : /**
1450 : * Start iterating over all caches of specified type. See also
1451 : * krb5_cccol_cursor_new().
1452 :
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().
1456 : *
1457 : * @return Return an error code or 0, see krb5_get_error_message().
1458 : *
1459 : * @ingroup krb5_ccache
1460 : */
1461 :
1462 :
1463 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1464 260 : krb5_cc_cache_get_first (krb5_context context,
1465 : const char *type,
1466 : krb5_cc_cache_cursor *cursor)
1467 : {
1468 0 : const krb5_cc_ops *ops;
1469 0 : krb5_error_code ret;
1470 :
1471 260 : if (type == NULL)
1472 0 : type = krb5_cc_default_name(context);
1473 :
1474 260 : ops = krb5_cc_get_prefix_ops(context, type);
1475 260 : if (ops == NULL) {
1476 0 : krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
1477 : "Unknown type \"%s\" when iterating "
1478 : "trying to iterate the credential caches", type);
1479 0 : return KRB5_CC_UNKNOWN_TYPE;
1480 : }
1481 :
1482 260 : if (ops->get_cache_first == NULL) {
1483 0 : krb5_set_error_message(context, KRB5_CC_NOSUPP,
1484 0 : N_("Credential cache type %s doesn't support "
1485 : "iterations over caches", "type"),
1486 0 : ops->prefix);
1487 0 : return KRB5_CC_NOSUPP;
1488 : }
1489 :
1490 260 : *cursor = calloc(1, sizeof(**cursor));
1491 260 : if (*cursor == NULL)
1492 0 : return krb5_enomem(context);
1493 :
1494 260 : (*cursor)->ops = ops;
1495 :
1496 260 : ret = ops->get_cache_first(context, &(*cursor)->cursor);
1497 260 : if (ret) {
1498 104 : free(*cursor);
1499 104 : *cursor = NULL;
1500 : }
1501 260 : return ret;
1502 : }
1503 :
1504 : /**
1505 : * Retrieve the next cache pointed to by (`cursor') in `id'
1506 : * and advance `cursor'.
1507 : *
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
1511 : *
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().
1514 : *
1515 : * @ingroup krb5_ccache
1516 : */
1517 :
1518 :
1519 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1520 156 : krb5_cc_cache_next (krb5_context context,
1521 : krb5_cc_cache_cursor cursor,
1522 : krb5_ccache *id)
1523 : {
1524 156 : return cursor->ops->get_cache_next(context, cursor->cursor, id);
1525 : }
1526 :
1527 : /**
1528 : * Destroy the cursor `cursor'.
1529 : *
1530 : * @return Return an error code or 0, see krb5_get_error_message().
1531 : *
1532 : * @ingroup krb5_ccache
1533 : */
1534 :
1535 :
1536 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1537 156 : krb5_cc_cache_end_seq_get (krb5_context context,
1538 : krb5_cc_cache_cursor cursor)
1539 : {
1540 0 : krb5_error_code ret;
1541 156 : ret = cursor->ops->end_cache_get(context, cursor->cursor);
1542 156 : cursor->ops = NULL;
1543 156 : free(cursor);
1544 156 : return ret;
1545 : }
1546 :
1547 : /**
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().
1551 : *
1552 : * @param context A Kerberos 5 context
1553 : * @param client The principal to search for
1554 : * @param id the returned credential cache
1555 : *
1556 : * @return On failure, error code is returned and `id' is set to NULL.
1557 : *
1558 : * @ingroup krb5_ccache
1559 : */
1560 :
1561 :
1562 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1563 52 : krb5_cc_cache_match (krb5_context context,
1564 : krb5_principal client,
1565 : krb5_ccache *id)
1566 : {
1567 0 : krb5_cccol_cursor cursor;
1568 0 : krb5_error_code ret;
1569 52 : krb5_ccache cache = NULL;
1570 52 : krb5_ccache expired_match = NULL;
1571 :
1572 52 : *id = NULL;
1573 :
1574 52 : ret = krb5_cccol_cursor_new (context, &cursor);
1575 52 : if (ret)
1576 0 : return ret;
1577 :
1578 52 : while (krb5_cccol_cursor_next(context, cursor, &cache) == 0 && cache != NULL) {
1579 0 : krb5_principal principal;
1580 0 : krb5_boolean match;
1581 0 : time_t lifetime;
1582 :
1583 0 : ret = krb5_cc_get_principal(context, cache, &principal);
1584 0 : if (ret)
1585 0 : goto next;
1586 :
1587 0 : if (client->name.name_string.len == 0)
1588 0 : match = (strcmp(client->realm, principal->realm) == 0);
1589 : else
1590 0 : match = krb5_principal_compare(context, principal, client);
1591 0 : krb5_free_principal(context, principal);
1592 :
1593 0 : if (!match)
1594 0 : goto next;
1595 :
1596 0 : if (expired_match == NULL &&
1597 0 : (krb5_cc_get_lifetime(context, cache, &lifetime) != 0 || lifetime == 0)) {
1598 0 : expired_match = cache;
1599 0 : cache = NULL;
1600 0 : goto next;
1601 : }
1602 0 : break;
1603 :
1604 0 : next:
1605 0 : if (cache)
1606 0 : krb5_cc_close(context, cache);
1607 0 : cache = NULL;
1608 : }
1609 :
1610 52 : krb5_cccol_cursor_free(context, &cursor);
1611 :
1612 52 : if (cache == NULL && expired_match) {
1613 0 : cache = expired_match;
1614 0 : expired_match = NULL;
1615 52 : } else if (expired_match) {
1616 0 : krb5_cc_close(context, expired_match);
1617 52 : } else if (cache == NULL) {
1618 0 : char *str;
1619 :
1620 52 : (void) krb5_unparse_name(context, client, &str);
1621 52 : krb5_set_error_message(context, KRB5_CC_NOTFOUND,
1622 52 : N_("Principal %s not found in any "
1623 : "credential cache", ""),
1624 52 : str ? str : "<out of memory>");
1625 52 : if (str)
1626 52 : free(str);
1627 52 : return KRB5_CC_NOTFOUND;
1628 : }
1629 :
1630 0 : *id = cache;
1631 :
1632 0 : return 0;
1633 : }
1634 :
1635 : /**
1636 : * Move the content from one credential cache to another. The
1637 : * operation is an atomic switch.
1638 : *
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
1642 :
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().
1646 : *
1647 : * @ingroup krb5_ccache
1648 : */
1649 :
1650 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1651 137 : krb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
1652 : {
1653 137 : krb5_error_code ret = ENOTSUP;
1654 137 : krb5_principal princ = NULL;
1655 :
1656 137 : if (to->ops->move &&
1657 137 : strcmp(from->ops->prefix, to->ops->prefix) == 0) {
1658 : /*
1659 : * NOTE: to->ops->move() is expected to call
1660 : * krb5_cc_destroy(context, from) on success.
1661 : */
1662 137 : ret = (*to->ops->move)(context, from, to);
1663 137 : if (ret == 0)
1664 0 : return 0;
1665 137 : if (ret != EXDEV && ret != ENOTSUP && ret != KRB5_CC_NOSUPP &&
1666 0 : ret != KRB5_FCC_INTERNAL)
1667 0 : return ret;
1668 : /* Fallback to high-level copy */
1669 : } /* Else high-level copy */
1670 :
1671 : /*
1672 : * Initialize destination, copy the source's contents to the destination,
1673 : * then destroy the source on success.
1674 : *
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.
1677 : */
1678 137 : ret = krb5_cc_get_principal(context, from, &princ);
1679 137 : if (ret == 0)
1680 137 : ret = krb5_cc_initialize(context, to, princ);
1681 137 : krb5_free_principal(context, princ);
1682 137 : if (ret == 0)
1683 137 : ret = krb5_cc_copy_cache(context, from, to);
1684 137 : if (ret == 0)
1685 137 : krb5_cc_destroy(context, from);
1686 137 : return ret;
1687 : }
1688 :
1689 : #define KRB5_CONF_NAME "krb5_ccache_conf_data"
1690 : #define KRB5_REALM_NAME "X-CACHECONF:"
1691 :
1692 : static krb5_error_code
1693 453675 : build_conf_principals(krb5_context context, krb5_ccache id,
1694 : krb5_const_principal principal,
1695 : const char *name, krb5_creds *cred)
1696 : {
1697 8476 : krb5_principal client;
1698 8476 : krb5_error_code ret;
1699 453675 : char *pname = NULL;
1700 :
1701 453675 : memset(cred, 0, sizeof(*cred));
1702 :
1703 453675 : ret = krb5_cc_get_principal(context, id, &client);
1704 453675 : if (ret)
1705 1155 : return ret;
1706 :
1707 452520 : if (principal) {
1708 24373 : ret = krb5_unparse_name(context, principal, &pname);
1709 24373 : if (ret)
1710 0 : return ret;
1711 : }
1712 :
1713 452520 : ret = krb5_make_principal(context, &cred->server,
1714 : KRB5_REALM_NAME,
1715 : KRB5_CONF_NAME, name, pname, NULL);
1716 452520 : free(pname);
1717 452520 : if (ret) {
1718 0 : krb5_free_principal(context, client);
1719 0 : return ret;
1720 : }
1721 452520 : ret = krb5_copy_principal(context, client, &cred->client);
1722 452520 : krb5_free_principal(context, client);
1723 452520 : return ret;
1724 : }
1725 :
1726 : /**
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.
1730 : *
1731 : * @param context a Kerberos context
1732 : * @param principal principal to check if it a configuration principal
1733 : *
1734 : * @ingroup krb5_ccache
1735 : */
1736 :
1737 : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1738 506416 : krb5_is_config_principal(krb5_context context,
1739 : krb5_const_principal principal)
1740 : {
1741 506416 : if (strcmp(principal->realm, KRB5_REALM_NAME) != 0)
1742 206168 : return FALSE;
1743 :
1744 297206 : if (principal->name.name_string.len == 0 ||
1745 297206 : strcmp(principal->name.name_string.val[0], KRB5_CONF_NAME) != 0)
1746 0 : return FALSE;
1747 :
1748 292476 : return TRUE;
1749 : }
1750 :
1751 : /**
1752 : * Store some configuration for the credential cache in the cache.
1753 : * Existing configuration under the same name is over-written.
1754 : *
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.
1761 : *
1762 : * @ingroup krb5_ccache
1763 : */
1764 :
1765 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1766 86271 : krb5_cc_set_config(krb5_context context, krb5_ccache id,
1767 : krb5_const_principal principal,
1768 : const char *name, krb5_data *data)
1769 : {
1770 1466 : krb5_error_code ret;
1771 1466 : krb5_creds cred;
1772 :
1773 86271 : ret = build_conf_principals(context, id, principal, name, &cred);
1774 86271 : if (ret)
1775 0 : goto out;
1776 :
1777 : /* Remove old configuration */
1778 86271 : ret = krb5_cc_remove_cred(context, id, 0, &cred);
1779 86271 : if (ret && ret != KRB5_CC_NOTFOUND && ret != KRB5_CC_NOSUPP &&
1780 0 : ret != KRB5_FCC_INTERNAL)
1781 0 : goto out;
1782 :
1783 86271 : if (data) {
1784 : /* not that anyone care when this expire */
1785 86271 : cred.times.authtime = time(NULL);
1786 86271 : cred.times.endtime = cred.times.authtime + 3600 * 24 * 30;
1787 :
1788 86271 : ret = krb5_data_copy(&cred.ticket, data->data, data->length);
1789 86271 : if (ret)
1790 0 : goto out;
1791 :
1792 86271 : ret = krb5_cc_store_cred(context, id, &cred);
1793 : }
1794 :
1795 0 : out:
1796 86271 : krb5_free_cred_contents (context, &cred);
1797 86271 : return ret;
1798 : }
1799 :
1800 : /**
1801 : * Get some configuration for the credential cache in the cache.
1802 : *
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.
1811 : *
1812 : * @ingroup krb5_ccache
1813 : */
1814 :
1815 :
1816 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1817 367404 : krb5_cc_get_config(krb5_context context, krb5_ccache id,
1818 : krb5_const_principal principal,
1819 : const char *name, krb5_data *data)
1820 : {
1821 7010 : krb5_creds mcred, cred;
1822 7010 : krb5_error_code ret;
1823 :
1824 367404 : memset(&cred, 0, sizeof(cred));
1825 367404 : krb5_data_zero(data);
1826 :
1827 367404 : ret = build_conf_principals(context, id, principal, name, &mcred);
1828 367404 : if (ret)
1829 1155 : goto out;
1830 :
1831 366249 : ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred);
1832 366249 : if (ret)
1833 223978 : goto out;
1834 :
1835 142271 : ret = krb5_data_copy(data, cred.ticket.data, cred.ticket.length);
1836 :
1837 367404 : out:
1838 367404 : krb5_free_cred_contents (context, &cred);
1839 367404 : krb5_free_cred_contents (context, &mcred);
1840 367404 : return ret;
1841 : }
1842 :
1843 : /*
1844 : *
1845 : */
1846 :
1847 : struct krb5_cccol_cursor_data {
1848 : int idx;
1849 : krb5_cc_cache_cursor cursor;
1850 : };
1851 :
1852 : /**
1853 : * Get a new cache interation cursor that will interate over all
1854 : * credentials caches independent of type.
1855 : *
1856 : * @param context a Kerberos context
1857 : * @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free().
1858 : *
1859 : * @return Returns 0 or and error code, see krb5_get_error_message().
1860 : *
1861 : * @ingroup krb5_ccache
1862 : */
1863 :
1864 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1865 52 : krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor)
1866 : {
1867 52 : *cursor = calloc(1, sizeof(**cursor));
1868 52 : if (*cursor == NULL)
1869 0 : return krb5_enomem(context);
1870 52 : (*cursor)->idx = 0;
1871 52 : (*cursor)->cursor = NULL;
1872 :
1873 52 : return 0;
1874 : }
1875 :
1876 : /**
1877 : * Get next credential cache from the iteration.
1878 : *
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.
1886 : *
1887 : * @return Return 0 or and error, KRB5_CC_END is returned at the end
1888 : * of iteration. See krb5_get_error_message().
1889 : *
1890 : * @ingroup krb5_ccache
1891 : */
1892 :
1893 :
1894 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1895 52 : krb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor,
1896 : krb5_ccache *cache)
1897 : {
1898 52 : krb5_error_code ret = 0;
1899 :
1900 52 : *cache = NULL;
1901 :
1902 312 : while (cursor->idx < context->num_cc_ops) {
1903 :
1904 260 : if (cursor->cursor == NULL) {
1905 260 : ret = krb5_cc_cache_get_first (context,
1906 260 : context->cc_ops[cursor->idx]->prefix,
1907 : &cursor->cursor);
1908 260 : if (ret) {
1909 104 : cursor->idx++;
1910 104 : continue;
1911 : }
1912 : }
1913 156 : ret = krb5_cc_cache_next(context, cursor->cursor, cache);
1914 156 : if (ret == 0)
1915 0 : break;
1916 :
1917 156 : krb5_cc_cache_end_seq_get(context, cursor->cursor);
1918 156 : cursor->cursor = NULL;
1919 156 : if (ret != KRB5_CC_END)
1920 0 : break;
1921 :
1922 156 : cursor->idx++;
1923 : }
1924 52 : if (cursor->idx >= context->num_cc_ops) {
1925 52 : krb5_set_error_message(context, KRB5_CC_END,
1926 52 : N_("Reached end of credential caches", ""));
1927 52 : return KRB5_CC_END;
1928 : }
1929 :
1930 0 : return ret;
1931 : }
1932 :
1933 : /**
1934 : * End an iteration and free all resources, can be done before end is reached.
1935 : *
1936 : * @param context A Kerberos 5 context
1937 : * @param cursor the iteration cursor to be freed.
1938 : *
1939 : * @return Return 0 or and error, KRB5_CC_END is returned at the end
1940 : * of iteration. See krb5_get_error_message().
1941 : *
1942 : * @ingroup krb5_ccache
1943 : */
1944 :
1945 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1946 52 : krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor)
1947 : {
1948 52 : krb5_cccol_cursor c = *cursor;
1949 :
1950 52 : *cursor = NULL;
1951 52 : if (c) {
1952 52 : if (c->cursor)
1953 0 : krb5_cc_cache_end_seq_get(context, c->cursor);
1954 52 : free(c);
1955 : }
1956 52 : return 0;
1957 : }
1958 :
1959 : /**
1960 : * Return the last time the credential cache was modified.
1961 : *
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.
1965 :
1966 : * @return Return 0 or and error. See krb5_get_error_message().
1967 : *
1968 : * @ingroup krb5_ccache
1969 : */
1970 :
1971 :
1972 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1973 0 : krb5_cc_last_change_time(krb5_context context,
1974 : krb5_ccache id,
1975 : krb5_timestamp *mtime)
1976 : {
1977 0 : *mtime = 0;
1978 :
1979 0 : if (id->ops->version < KRB5_CC_OPS_VERSION_2
1980 0 : || id->ops->lastchange == NULL)
1981 0 : return KRB5_CC_NOSUPP;
1982 :
1983 0 : return (*id->ops->lastchange)(context, id, mtime);
1984 : }
1985 :
1986 : /**
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.
1990 : *
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.
1994 :
1995 : * @return Return 0 or and error. See krb5_get_error_message().
1996 : *
1997 : * @ingroup krb5_ccache
1998 : */
1999 :
2000 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2001 0 : krb5_cccol_last_change_time(krb5_context context,
2002 : const char *type,
2003 : krb5_timestamp *mtime)
2004 : {
2005 0 : krb5_cccol_cursor cursor;
2006 0 : krb5_error_code ret;
2007 0 : krb5_ccache id;
2008 0 : krb5_timestamp t = 0;
2009 :
2010 0 : *mtime = 0;
2011 :
2012 0 : ret = krb5_cccol_cursor_new (context, &cursor);
2013 0 : if (ret)
2014 0 : return ret;
2015 :
2016 0 : while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) {
2017 :
2018 0 : if (type && strcmp(krb5_cc_get_type(context, id), type) != 0)
2019 0 : continue;
2020 :
2021 0 : ret = krb5_cc_last_change_time(context, id, &t);
2022 0 : krb5_cc_close(context, id);
2023 0 : if (ret)
2024 0 : continue;
2025 0 : if (t > *mtime)
2026 0 : *mtime = t;
2027 : }
2028 :
2029 0 : krb5_cccol_cursor_free(context, &cursor);
2030 :
2031 0 : return 0;
2032 : }
2033 : /**
2034 : * Return a friendly name on credential cache. Free the result with krb5_xfree().
2035 : *
2036 : * @return Return an error code or 0, see krb5_get_error_message().
2037 : *
2038 : * @ingroup krb5_ccache
2039 : */
2040 :
2041 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2042 0 : krb5_cc_get_friendly_name(krb5_context context,
2043 : krb5_ccache id,
2044 : char **name)
2045 : {
2046 0 : krb5_error_code ret;
2047 0 : krb5_data data;
2048 :
2049 0 : ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data);
2050 0 : if (ret) {
2051 0 : krb5_principal principal;
2052 0 : ret = krb5_cc_get_principal(context, id, &principal);
2053 0 : if (ret)
2054 0 : return ret;
2055 0 : ret = krb5_unparse_name(context, principal, name);
2056 0 : krb5_free_principal(context, principal);
2057 : } else {
2058 0 : ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data);
2059 0 : krb5_data_free(&data);
2060 0 : if (ret <= 0)
2061 0 : ret = krb5_enomem(context);
2062 : else
2063 0 : ret = 0;
2064 : }
2065 :
2066 0 : return ret;
2067 : }
2068 :
2069 : /**
2070 : * Set the friendly name on credential cache.
2071 : *
2072 : * @return Return an error code or 0, see krb5_get_error_message().
2073 : *
2074 : * @ingroup krb5_ccache
2075 : */
2076 :
2077 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2078 0 : krb5_cc_set_friendly_name(krb5_context context,
2079 : krb5_ccache id,
2080 : const char *name)
2081 : {
2082 0 : krb5_data data;
2083 :
2084 0 : data.data = rk_UNCONST(name);
2085 0 : data.length = strlen(name);
2086 :
2087 0 : return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data);
2088 : }
2089 :
2090 : /**
2091 : * Get the lifetime of the initial ticket in the cache
2092 : *
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.
2095 : *
2096 : * @param context A Kerberos 5 context.
2097 : * @param id a credential cache
2098 : * @param t the relative lifetime of the initial ticket
2099 : *
2100 : * @return Return an error code or 0, see krb5_get_error_message().
2101 : *
2102 : * @ingroup krb5_ccache
2103 : */
2104 :
2105 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2106 139051 : krb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t)
2107 : {
2108 2347 : krb5_data config_start_realm;
2109 2347 : char *start_realm;
2110 2347 : krb5_cc_cursor cursor;
2111 2347 : krb5_error_code ret;
2112 2347 : krb5_creds cred;
2113 139051 : time_t now, endtime = 0;
2114 :
2115 139051 : *t = 0;
2116 139051 : krb5_timeofday(context, &now);
2117 :
2118 139051 : ret = krb5_cc_get_config(context, id, NULL, "start_realm", &config_start_realm);
2119 139051 : if (ret == 0) {
2120 138927 : start_realm = strndup(config_start_realm.data, config_start_realm.length);
2121 138927 : krb5_data_free(&config_start_realm);
2122 : } else {
2123 0 : krb5_principal client;
2124 :
2125 124 : ret = krb5_cc_get_principal(context, id, &client);
2126 124 : if (ret)
2127 0 : return ret;
2128 124 : start_realm = strdup(krb5_principal_get_realm(context, client));
2129 124 : krb5_free_principal(context, client);
2130 : }
2131 139051 : if (start_realm == NULL)
2132 0 : return krb5_enomem(context);
2133 :
2134 139051 : ret = krb5_cc_start_seq_get(context, id, &cursor);
2135 139051 : if (ret) {
2136 0 : free(start_realm);
2137 0 : return ret;
2138 : }
2139 :
2140 310897 : while ((ret = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) {
2141 : /**
2142 : * If we find the start krbtgt in the cache, use that as the lifespan.
2143 : */
2144 310821 : if (krb5_principal_is_root_krbtgt(context, cred.server) &&
2145 138975 : strcmp(cred.server->realm, start_realm) == 0) {
2146 138975 : if (now < cred.times.endtime)
2147 138975 : endtime = cred.times.endtime;
2148 138975 : krb5_free_cred_contents(context, &cred);
2149 138975 : break;
2150 : }
2151 : /*
2152 : * Skip config entries
2153 : */
2154 171846 : if (krb5_is_config_principal(context, cred.server)) {
2155 138596 : krb5_free_cred_contents(context, &cred);
2156 138596 : continue;
2157 : }
2158 : /**
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.
2162 : */
2163 33250 : if ((endtime == 0 || cred.times.endtime < endtime) && now < cred.times.endtime)
2164 5721 : endtime = cred.times.endtime;
2165 33250 : krb5_free_cred_contents(context, &cred);
2166 : }
2167 139051 : free(start_realm);
2168 :
2169 : /* if we found an endtime use that */
2170 139051 : if (endtime) {
2171 139051 : *t = endtime - now;
2172 139051 : ret = 0;
2173 : }
2174 :
2175 139051 : krb5_cc_end_seq_get(context, id, &cursor);
2176 :
2177 139051 : return ret;
2178 : }
2179 :
2180 : /**
2181 : * Set the time offset betwen the client and the KDC
2182 : *
2183 : * If the backend doesn't support KDC offset, use the context global setting.
2184 : *
2185 : * @param context A Kerberos 5 context.
2186 : * @param id a credential cache
2187 : * @param offset the offset in seconds
2188 : *
2189 : * @return Return an error code or 0, see krb5_get_error_message().
2190 : *
2191 : * @ingroup krb5_ccache
2192 : */
2193 :
2194 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2195 0 : krb5_cc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat offset)
2196 : {
2197 0 : if (id->ops->version < KRB5_CC_OPS_VERSION_3
2198 0 : || id->ops->set_kdc_offset == NULL) {
2199 0 : context->kdc_sec_offset = offset;
2200 0 : context->kdc_usec_offset = 0;
2201 0 : return 0;
2202 : }
2203 0 : return (*id->ops->set_kdc_offset)(context, id, offset);
2204 : }
2205 :
2206 : /**
2207 : * Get the time offset betwen the client and the KDC
2208 : *
2209 : * If the backend doesn't support KDC offset, use the context global setting.
2210 : *
2211 : * @param context A Kerberos 5 context.
2212 : * @param id a credential cache
2213 : * @param offset the offset in seconds
2214 : *
2215 : * @return Return an error code or 0, see krb5_get_error_message().
2216 : *
2217 : * @ingroup krb5_ccache
2218 : */
2219 :
2220 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2221 21789 : krb5_cc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *offset)
2222 : {
2223 21789 : if (id->ops->version < KRB5_CC_OPS_VERSION_3
2224 21789 : || id->ops->get_kdc_offset == NULL) {
2225 0 : *offset = context->kdc_sec_offset;
2226 0 : return 0;
2227 : }
2228 21789 : return (*id->ops->get_kdc_offset)(context, id, offset);
2229 : }
2230 :
2231 : #ifdef _WIN32
2232 : #define REGPATH_MIT_KRB5 "SOFTWARE\\MIT\\Kerberos5"
2233 :
2234 : static char *
2235 : _get_default_cc_name_from_registry(krb5_context context, HKEY hkBase)
2236 : {
2237 : HKEY hk_k5 = 0;
2238 : LONG code;
2239 : char *ccname = NULL;
2240 :
2241 : code = RegOpenKeyEx(hkBase,
2242 : REGPATH_MIT_KRB5,
2243 : 0, KEY_READ, &hk_k5);
2244 :
2245 : if (code != ERROR_SUCCESS)
2246 : return NULL;
2247 :
2248 : ccname = heim_parse_reg_value_as_string(context->hcontext, hk_k5, "ccname",
2249 : REG_NONE, 0);
2250 :
2251 : RegCloseKey(hk_k5);
2252 :
2253 : return ccname;
2254 : }
2255 :
2256 : KRB5_LIB_FUNCTION char * KRB5_LIB_CALL
2257 : _krb5_get_default_cc_name_from_registry(krb5_context context)
2258 : {
2259 : char *ccname;
2260 :
2261 : ccname = _get_default_cc_name_from_registry(context, HKEY_CURRENT_USER);
2262 : if (ccname == NULL)
2263 : ccname = _get_default_cc_name_from_registry(context,
2264 : HKEY_LOCAL_MACHINE);
2265 :
2266 : return ccname;
2267 : }
2268 :
2269 : KRB5_LIB_FUNCTION int KRB5_LIB_CALL
2270 : _krb5_set_default_cc_name_to_registry(krb5_context context, krb5_ccache id)
2271 : {
2272 : HKEY hk_k5 = 0;
2273 : LONG code;
2274 : int ret = -1;
2275 : char * ccname = NULL;
2276 :
2277 : code = RegOpenKeyEx(HKEY_CURRENT_USER,
2278 : REGPATH_MIT_KRB5,
2279 : 0, KEY_READ|KEY_WRITE, &hk_k5);
2280 :
2281 : if (code != ERROR_SUCCESS)
2282 : return -1;
2283 :
2284 : ret = asprintf(&ccname, "%s:%s", krb5_cc_get_type(context, id), krb5_cc_get_name(context, id));
2285 : if (ret < 0)
2286 : goto cleanup;
2287 :
2288 : ret = heim_store_string_to_reg_value(context->hcontext, hk_k5, "ccname",
2289 : REG_SZ, ccname, -1, 0);
2290 :
2291 : cleanup:
2292 :
2293 : if (ccname)
2294 : free(ccname);
2295 :
2296 : RegCloseKey(hk_k5);
2297 :
2298 : return ret;
2299 : }
2300 : #endif
|