Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/krb5/cache.c
34878 views
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
/**
104
* Add a new ccache type with operations `ops', overwriting any
105
* existing one if `override'.
106
*
107
* @param context a Keberos context
108
* @param ops type of plugin symbol
109
* @param override flag to select if the registration is to overide
110
* an existing ops with the same name.
111
*
112
* @return Return an error code or 0, see krb5_get_error_message().
113
*
114
* @ingroup krb5_ccache
115
*/
116
117
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
118
krb5_cc_register(krb5_context context,
119
const krb5_cc_ops *ops,
120
krb5_boolean override)
121
{
122
int i;
123
124
for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
125
if(strcmp(context->cc_ops[i]->prefix, ops->prefix) == 0) {
126
if(!override) {
127
krb5_set_error_message(context,
128
KRB5_CC_TYPE_EXISTS,
129
N_("cache type %s already exists", "type"),
130
ops->prefix);
131
return KRB5_CC_TYPE_EXISTS;
132
}
133
break;
134
}
135
}
136
if(i == context->num_cc_ops) {
137
const krb5_cc_ops **o = realloc(rk_UNCONST(context->cc_ops),
138
(context->num_cc_ops + 1) *
139
sizeof(context->cc_ops[0]));
140
if(o == NULL) {
141
krb5_set_error_message(context, KRB5_CC_NOMEM,
142
N_("malloc: out of memory", ""));
143
return KRB5_CC_NOMEM;
144
}
145
context->cc_ops = o;
146
context->cc_ops[context->num_cc_ops] = NULL;
147
context->num_cc_ops++;
148
}
149
context->cc_ops[i] = ops;
150
return 0;
151
}
152
153
/*
154
* Allocate the memory for a `id' and the that function table to
155
* `ops'. Returns 0 or and error code.
156
*/
157
158
krb5_error_code
159
_krb5_cc_allocate(krb5_context context,
160
const krb5_cc_ops *ops,
161
krb5_ccache *id)
162
{
163
krb5_ccache p;
164
165
p = malloc (sizeof(*p));
166
if(p == NULL) {
167
krb5_set_error_message(context, KRB5_CC_NOMEM,
168
N_("malloc: out of memory", ""));
169
return KRB5_CC_NOMEM;
170
}
171
p->ops = ops;
172
*id = p;
173
174
return 0;
175
}
176
177
/*
178
* Allocate memory for a new ccache in `id' with operations `ops'
179
* and name `residual'. Return 0 or an error code.
180
*/
181
182
static krb5_error_code
183
allocate_ccache (krb5_context context,
184
const krb5_cc_ops *ops,
185
const char *residual,
186
krb5_ccache *id)
187
{
188
krb5_error_code ret;
189
#ifdef KRB5_USE_PATH_TOKENS
190
char * exp_residual = NULL;
191
192
ret = _krb5_expand_path_tokens(context, residual, &exp_residual);
193
if (ret)
194
return ret;
195
196
residual = exp_residual;
197
#endif
198
199
ret = _krb5_cc_allocate(context, ops, id);
200
if (ret) {
201
#ifdef KRB5_USE_PATH_TOKENS
202
if (exp_residual)
203
free(exp_residual);
204
#endif
205
return ret;
206
}
207
208
ret = (*id)->ops->resolve(context, id, residual);
209
if(ret) {
210
free(*id);
211
*id = NULL;
212
}
213
214
#ifdef KRB5_USE_PATH_TOKENS
215
if (exp_residual)
216
free(exp_residual);
217
#endif
218
219
return ret;
220
}
221
222
static int
223
is_possible_path_name(const char * name)
224
{
225
const char * colon;
226
227
if ((colon = strchr(name, ':')) == NULL)
228
return TRUE;
229
230
#ifdef _WIN32
231
/* <drive letter>:\path\to\cache ? */
232
233
if (colon == name + 1 &&
234
strchr(colon + 1, ':') == NULL)
235
return TRUE;
236
#endif
237
238
return FALSE;
239
}
240
241
/**
242
* Find and allocate a ccache in `id' from the specification in `residual'.
243
* If the ccache name doesn't contain any colon, interpret it as a file name.
244
*
245
* @param context a Keberos context.
246
* @param name string name of a credential cache.
247
* @param id return pointer to a found credential cache.
248
*
249
* @return Return 0 or an error code. In case of an error, id is set
250
* to NULL, see krb5_get_error_message().
251
*
252
* @ingroup krb5_ccache
253
*/
254
255
256
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
257
krb5_cc_resolve(krb5_context context,
258
const char *name,
259
krb5_ccache *id)
260
{
261
int i;
262
263
*id = NULL;
264
265
for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
266
size_t prefix_len = strlen(context->cc_ops[i]->prefix);
267
268
if(strncmp(context->cc_ops[i]->prefix, name, prefix_len) == 0
269
&& name[prefix_len] == ':') {
270
return allocate_ccache (context, context->cc_ops[i],
271
name + prefix_len + 1,
272
id);
273
}
274
}
275
if (is_possible_path_name(name))
276
return allocate_ccache (context, &krb5_fcc_ops, name, id);
277
else {
278
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
279
N_("unknown ccache type %s", "name"), name);
280
return KRB5_CC_UNKNOWN_TYPE;
281
}
282
}
283
284
/**
285
* Generates a new unique ccache of `type` in `id'. If `type' is NULL,
286
* the library chooses the default credential cache type. The supplied
287
* `hint' (that can be NULL) is a string that the credential cache
288
* type can use to base the name of the credential on, this is to make
289
* it easier for the user to differentiate the credentials.
290
*
291
* @return Return an error code or 0, see krb5_get_error_message().
292
*
293
* @ingroup krb5_ccache
294
*/
295
296
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
297
krb5_cc_new_unique(krb5_context context, const char *type,
298
const char *hint, krb5_ccache *id)
299
{
300
const krb5_cc_ops *ops;
301
krb5_error_code ret;
302
303
ops = krb5_cc_get_prefix_ops(context, type);
304
if (ops == NULL) {
305
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
306
"Credential cache type %s is unknown", type);
307
return KRB5_CC_UNKNOWN_TYPE;
308
}
309
310
ret = _krb5_cc_allocate(context, ops, id);
311
if (ret)
312
return ret;
313
ret = (*id)->ops->gen_new(context, id);
314
if (ret) {
315
free(*id);
316
*id = NULL;
317
}
318
return ret;
319
}
320
321
/**
322
* Return the name of the ccache `id'
323
*
324
* @ingroup krb5_ccache
325
*/
326
327
328
KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
329
krb5_cc_get_name(krb5_context context,
330
krb5_ccache id)
331
{
332
return id->ops->get_name(context, id);
333
}
334
335
/**
336
* Return the type of the ccache `id'.
337
*
338
* @ingroup krb5_ccache
339
*/
340
341
342
KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
343
krb5_cc_get_type(krb5_context context,
344
krb5_ccache id)
345
{
346
return id->ops->prefix;
347
}
348
349
/**
350
* Return the complete resolvable name the cache
351
352
* @param context a Keberos context
353
* @param id return pointer to a found credential cache
354
* @param str the returned name of a credential cache, free with krb5_xfree()
355
*
356
* @return Returns 0 or an error (and then *str is set to NULL).
357
*
358
* @ingroup krb5_ccache
359
*/
360
361
362
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
363
krb5_cc_get_full_name(krb5_context context,
364
krb5_ccache id,
365
char **str)
366
{
367
const char *type, *name;
368
369
*str = NULL;
370
371
type = krb5_cc_get_type(context, id);
372
if (type == NULL) {
373
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
374
"cache have no name of type");
375
return KRB5_CC_UNKNOWN_TYPE;
376
}
377
378
name = krb5_cc_get_name(context, id);
379
if (name == NULL) {
380
krb5_set_error_message(context, KRB5_CC_BADNAME,
381
"cache of type %s have no name", type);
382
return KRB5_CC_BADNAME;
383
}
384
385
if (asprintf(str, "%s:%s", type, name) == -1) {
386
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
387
*str = NULL;
388
return ENOMEM;
389
}
390
return 0;
391
}
392
393
/**
394
* Return krb5_cc_ops of a the ccache `id'.
395
*
396
* @ingroup krb5_ccache
397
*/
398
399
400
KRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL
401
krb5_cc_get_ops(krb5_context context, krb5_ccache id)
402
{
403
return id->ops;
404
}
405
406
/*
407
* Expand variables in `str' into `res'
408
*/
409
410
krb5_error_code
411
_krb5_expand_default_cc_name(krb5_context context, const char *str, char **res)
412
{
413
return _krb5_expand_path_tokens(context, str, res);
414
}
415
416
/*
417
* Return non-zero if envirnoment that will determine default krb5cc
418
* name has changed.
419
*/
420
421
static int
422
environment_changed(krb5_context context)
423
{
424
const char *e;
425
426
/* if the cc name was set, don't change it */
427
if (context->default_cc_name_set)
428
return 0;
429
430
/* XXX performance: always ask KCM/API if default name has changed */
431
if (context->default_cc_name &&
432
(strncmp(context->default_cc_name, "KCM:", 4) == 0 ||
433
strncmp(context->default_cc_name, "API:", 4) == 0))
434
return 1;
435
436
if(issuid())
437
return 0;
438
439
e = getenv("KRB5CCNAME");
440
if (e == NULL) {
441
if (context->default_cc_name_env) {
442
free(context->default_cc_name_env);
443
context->default_cc_name_env = NULL;
444
return 1;
445
}
446
} else {
447
if (context->default_cc_name_env == NULL)
448
return 1;
449
if (strcmp(e, context->default_cc_name_env) != 0)
450
return 1;
451
}
452
return 0;
453
}
454
455
/**
456
* Switch the default default credential cache for a specific
457
* credcache type (and name for some implementations).
458
*
459
* @return Return an error code or 0, see krb5_get_error_message().
460
*
461
* @ingroup krb5_ccache
462
*/
463
464
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
465
krb5_cc_switch(krb5_context context, krb5_ccache id)
466
{
467
#ifdef _WIN32
468
_krb5_set_default_cc_name_to_registry(context, id);
469
#endif
470
471
if (id->ops->set_default == NULL)
472
return 0;
473
474
return (*id->ops->set_default)(context, id);
475
}
476
477
/**
478
* Return true if the default credential cache support switch
479
*
480
* @ingroup krb5_ccache
481
*/
482
483
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
484
krb5_cc_support_switch(krb5_context context, const char *type)
485
{
486
const krb5_cc_ops *ops;
487
488
ops = krb5_cc_get_prefix_ops(context, type);
489
if (ops && ops->set_default)
490
return 1;
491
return FALSE;
492
}
493
494
/**
495
* Set the default cc name for `context' to `name'.
496
*
497
* @ingroup krb5_ccache
498
*/
499
500
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
501
krb5_cc_set_default_name(krb5_context context, const char *name)
502
{
503
krb5_error_code ret = 0;
504
char *p = NULL, *exp_p = NULL;
505
506
if (name == NULL) {
507
const char *e = NULL;
508
509
if(!issuid()) {
510
e = getenv("KRB5CCNAME");
511
if (e) {
512
p = strdup(e);
513
if (context->default_cc_name_env)
514
free(context->default_cc_name_env);
515
context->default_cc_name_env = strdup(e);
516
}
517
}
518
519
#ifdef _WIN32
520
if (e == NULL) {
521
e = p = _krb5_get_default_cc_name_from_registry(context);
522
}
523
#endif
524
if (e == NULL) {
525
e = krb5_config_get_string(context, NULL, "libdefaults",
526
"default_cc_name", NULL);
527
if (e) {
528
ret = _krb5_expand_default_cc_name(context, e, &p);
529
if (ret)
530
return ret;
531
}
532
if (e == NULL) {
533
const krb5_cc_ops *ops = KRB5_DEFAULT_CCTYPE;
534
e = krb5_config_get_string(context, NULL, "libdefaults",
535
"default_cc_type", NULL);
536
if (e) {
537
ops = krb5_cc_get_prefix_ops(context, e);
538
if (ops == NULL) {
539
krb5_set_error_message(context,
540
KRB5_CC_UNKNOWN_TYPE,
541
"Credential cache type %s "
542
"is unknown", e);
543
return KRB5_CC_UNKNOWN_TYPE;
544
}
545
}
546
ret = (*ops->get_default_name)(context, &p);
547
if (ret)
548
return ret;
549
}
550
}
551
context->default_cc_name_set = 0;
552
} else {
553
p = strdup(name);
554
context->default_cc_name_set = 1;
555
}
556
557
if (p == NULL) {
558
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
559
return ENOMEM;
560
}
561
562
ret = _krb5_expand_path_tokens(context, p, &exp_p);
563
free(p);
564
if (ret)
565
return ret;
566
567
if (context->default_cc_name)
568
free(context->default_cc_name);
569
570
context->default_cc_name = exp_p;
571
572
return 0;
573
}
574
575
/**
576
* Return a pointer to a context static string containing the default
577
* ccache name.
578
*
579
* @return String to the default credential cache name.
580
*
581
* @ingroup krb5_ccache
582
*/
583
584
585
KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
586
krb5_cc_default_name(krb5_context context)
587
{
588
if (context->default_cc_name == NULL || environment_changed(context))
589
krb5_cc_set_default_name(context, NULL);
590
591
return context->default_cc_name;
592
}
593
594
/**
595
* Open the default ccache in `id'.
596
*
597
* @return Return an error code or 0, see krb5_get_error_message().
598
*
599
* @ingroup krb5_ccache
600
*/
601
602
603
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
604
krb5_cc_default(krb5_context context,
605
krb5_ccache *id)
606
{
607
const char *p = krb5_cc_default_name(context);
608
609
if (p == NULL) {
610
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
611
return ENOMEM;
612
}
613
return krb5_cc_resolve(context, p, id);
614
}
615
616
/**
617
* Create a new ccache in `id' for `primary_principal'.
618
*
619
* @return Return an error code or 0, see krb5_get_error_message().
620
*
621
* @ingroup krb5_ccache
622
*/
623
624
625
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
626
krb5_cc_initialize(krb5_context context,
627
krb5_ccache id,
628
krb5_principal primary_principal)
629
{
630
return (*id->ops->init)(context, id, primary_principal);
631
}
632
633
634
/**
635
* Remove the ccache `id'.
636
*
637
* @return Return an error code or 0, see krb5_get_error_message().
638
*
639
* @ingroup krb5_ccache
640
*/
641
642
643
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
644
krb5_cc_destroy(krb5_context context,
645
krb5_ccache id)
646
{
647
krb5_error_code ret;
648
649
ret = (*id->ops->destroy)(context, id);
650
krb5_cc_close (context, id);
651
return ret;
652
}
653
654
/**
655
* Stop using the ccache `id' and free the related resources.
656
*
657
* @return Return an error code or 0, see krb5_get_error_message().
658
*
659
* @ingroup krb5_ccache
660
*/
661
662
663
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
664
krb5_cc_close(krb5_context context,
665
krb5_ccache id)
666
{
667
krb5_error_code ret;
668
ret = (*id->ops->close)(context, id);
669
free(id);
670
return ret;
671
}
672
673
/**
674
* Store `creds' in the ccache `id'.
675
*
676
* @return Return an error code or 0, see krb5_get_error_message().
677
*
678
* @ingroup krb5_ccache
679
*/
680
681
682
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
683
krb5_cc_store_cred(krb5_context context,
684
krb5_ccache id,
685
krb5_creds *creds)
686
{
687
return (*id->ops->store)(context, id, creds);
688
}
689
690
/**
691
* Retrieve the credential identified by `mcreds' (and `whichfields')
692
* from `id' in `creds'. 'creds' must be free by the caller using
693
* krb5_free_cred_contents.
694
*
695
* @param context A Kerberos 5 context
696
* @param id a Kerberos 5 credential cache
697
* @param whichfields what fields to use for matching credentials, same
698
* flags as whichfields in krb5_compare_creds()
699
* @param mcreds template credential to use for comparing
700
* @param creds returned credential, free with krb5_free_cred_contents()
701
*
702
* @return Return an error code or 0, see krb5_get_error_message().
703
*
704
* @ingroup krb5_ccache
705
*/
706
707
708
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
709
krb5_cc_retrieve_cred(krb5_context context,
710
krb5_ccache id,
711
krb5_flags whichfields,
712
const krb5_creds *mcreds,
713
krb5_creds *creds)
714
{
715
krb5_error_code ret;
716
krb5_cc_cursor cursor;
717
718
if (id->ops->retrieve != NULL) {
719
return (*id->ops->retrieve)(context, id, whichfields,
720
mcreds, creds);
721
}
722
723
ret = krb5_cc_start_seq_get(context, id, &cursor);
724
if (ret)
725
return ret;
726
while((ret = krb5_cc_next_cred(context, id, &cursor, creds)) == 0){
727
if(krb5_compare_creds(context, whichfields, mcreds, creds)){
728
ret = 0;
729
break;
730
}
731
krb5_free_cred_contents (context, creds);
732
}
733
krb5_cc_end_seq_get(context, id, &cursor);
734
return ret;
735
}
736
737
/**
738
* Return the principal of `id' in `principal'.
739
*
740
* @return Return an error code or 0, see krb5_get_error_message().
741
*
742
* @ingroup krb5_ccache
743
*/
744
745
746
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
747
krb5_cc_get_principal(krb5_context context,
748
krb5_ccache id,
749
krb5_principal *principal)
750
{
751
return (*id->ops->get_princ)(context, id, principal);
752
}
753
754
/**
755
* Start iterating over `id', `cursor' is initialized to the
756
* beginning. Caller must free the cursor with krb5_cc_end_seq_get().
757
*
758
* @return Return an error code or 0, see krb5_get_error_message().
759
*
760
* @ingroup krb5_ccache
761
*/
762
763
764
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
765
krb5_cc_start_seq_get (krb5_context context,
766
const krb5_ccache id,
767
krb5_cc_cursor *cursor)
768
{
769
return (*id->ops->get_first)(context, id, cursor);
770
}
771
772
/**
773
* Retrieve the next cred pointed to by (`id', `cursor') in `creds'
774
* and advance `cursor'.
775
*
776
* @return Return an error code or 0, see krb5_get_error_message().
777
*
778
* @ingroup krb5_ccache
779
*/
780
781
782
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
783
krb5_cc_next_cred (krb5_context context,
784
const krb5_ccache id,
785
krb5_cc_cursor *cursor,
786
krb5_creds *creds)
787
{
788
return (*id->ops->get_next)(context, id, cursor, creds);
789
}
790
791
/**
792
* Destroy the cursor `cursor'.
793
*
794
* @ingroup krb5_ccache
795
*/
796
797
798
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
799
krb5_cc_end_seq_get (krb5_context context,
800
const krb5_ccache id,
801
krb5_cc_cursor *cursor)
802
{
803
return (*id->ops->end_get)(context, id, cursor);
804
}
805
806
/**
807
* Remove the credential identified by `cred', `which' from `id'.
808
*
809
* @ingroup krb5_ccache
810
*/
811
812
813
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
814
krb5_cc_remove_cred(krb5_context context,
815
krb5_ccache id,
816
krb5_flags which,
817
krb5_creds *cred)
818
{
819
if(id->ops->remove_cred == NULL) {
820
krb5_set_error_message(context,
821
EACCES,
822
"ccache %s does not support remove_cred",
823
id->ops->prefix);
824
return EACCES; /* XXX */
825
}
826
return (*id->ops->remove_cred)(context, id, which, cred);
827
}
828
829
/**
830
* Set the flags of `id' to `flags'.
831
*
832
* @ingroup krb5_ccache
833
*/
834
835
836
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
837
krb5_cc_set_flags(krb5_context context,
838
krb5_ccache id,
839
krb5_flags flags)
840
{
841
return (*id->ops->set_flags)(context, id, flags);
842
}
843
844
/**
845
* Get the flags of `id', store them in `flags'.
846
*
847
* @ingroup krb5_ccache
848
*/
849
850
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
851
krb5_cc_get_flags(krb5_context context,
852
krb5_ccache id,
853
krb5_flags *flags)
854
{
855
*flags = 0;
856
return 0;
857
}
858
859
/**
860
* Copy the contents of `from' to `to' if the given match function
861
* return true.
862
*
863
* @param context A Kerberos 5 context.
864
* @param from the cache to copy data from.
865
* @param to the cache to copy data to.
866
* @param match a match function that should return TRUE if cred argument should be copied, if NULL, all credentials are copied.
867
* @param matchctx context passed to match function.
868
* @param matched set to true if there was a credential that matched, may be NULL.
869
*
870
* @return Return an error code or 0, see krb5_get_error_message().
871
*
872
* @ingroup krb5_ccache
873
*/
874
875
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
876
krb5_cc_copy_match_f(krb5_context context,
877
const krb5_ccache from,
878
krb5_ccache to,
879
krb5_boolean (*match)(krb5_context, void *, const krb5_creds *),
880
void *matchctx,
881
unsigned int *matched)
882
{
883
krb5_error_code ret;
884
krb5_cc_cursor cursor;
885
krb5_creds cred;
886
krb5_principal princ;
887
888
if (matched)
889
*matched = 0;
890
891
ret = krb5_cc_get_principal(context, from, &princ);
892
if (ret)
893
return ret;
894
ret = krb5_cc_initialize(context, to, princ);
895
if (ret) {
896
krb5_free_principal(context, princ);
897
return ret;
898
}
899
ret = krb5_cc_start_seq_get(context, from, &cursor);
900
if (ret) {
901
krb5_free_principal(context, princ);
902
return ret;
903
}
904
905
while ((ret = krb5_cc_next_cred(context, from, &cursor, &cred)) == 0) {
906
if (match == NULL || (*match)(context, matchctx, &cred) == 0) {
907
if (matched)
908
(*matched)++;
909
ret = krb5_cc_store_cred(context, to, &cred);
910
if (ret)
911
break;
912
}
913
krb5_free_cred_contents(context, &cred);
914
}
915
krb5_cc_end_seq_get(context, from, &cursor);
916
krb5_free_principal(context, princ);
917
if (ret == KRB5_CC_END)
918
ret = 0;
919
return ret;
920
}
921
922
/**
923
* Just like krb5_cc_copy_match_f(), but copy everything.
924
*
925
* @ingroup @krb5_ccache
926
*/
927
928
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
929
krb5_cc_copy_cache(krb5_context context,
930
const krb5_ccache from,
931
krb5_ccache to)
932
{
933
return krb5_cc_copy_match_f(context, from, to, NULL, NULL, NULL);
934
}
935
936
/**
937
* Return the version of `id'.
938
*
939
* @ingroup krb5_ccache
940
*/
941
942
943
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
944
krb5_cc_get_version(krb5_context context,
945
const krb5_ccache id)
946
{
947
if(id->ops->get_version)
948
return (*id->ops->get_version)(context, id);
949
else
950
return 0;
951
}
952
953
/**
954
* Clear `mcreds' so it can be used with krb5_cc_retrieve_cred
955
*
956
* @ingroup krb5_ccache
957
*/
958
959
960
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
961
krb5_cc_clear_mcred(krb5_creds *mcred)
962
{
963
memset(mcred, 0, sizeof(*mcred));
964
}
965
966
/**
967
* Get the cc ops that is registered in `context' to handle the
968
* prefix. prefix can be a complete credential cache name or a
969
* prefix, the function will only use part up to the first colon (:)
970
* if there is one. If prefix the argument is NULL, the default ccache
971
* implemtation is returned.
972
*
973
* @return Returns NULL if ops not found.
974
*
975
* @ingroup krb5_ccache
976
*/
977
978
979
KRB5_LIB_FUNCTION const krb5_cc_ops * KRB5_LIB_CALL
980
krb5_cc_get_prefix_ops(krb5_context context, const char *prefix)
981
{
982
char *p, *p1;
983
int i;
984
985
if (prefix == NULL)
986
return KRB5_DEFAULT_CCTYPE;
987
if (prefix[0] == '/')
988
return &krb5_fcc_ops;
989
990
p = strdup(prefix);
991
if (p == NULL) {
992
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
993
return NULL;
994
}
995
p1 = strchr(p, ':');
996
if (p1)
997
*p1 = '\0';
998
999
for(i = 0; i < context->num_cc_ops && context->cc_ops[i]->prefix; i++) {
1000
if(strcmp(context->cc_ops[i]->prefix, p) == 0) {
1001
free(p);
1002
return context->cc_ops[i];
1003
}
1004
}
1005
free(p);
1006
return NULL;
1007
}
1008
1009
struct krb5_cc_cache_cursor_data {
1010
const krb5_cc_ops *ops;
1011
krb5_cc_cursor cursor;
1012
};
1013
1014
/**
1015
* Start iterating over all caches of specified type. See also
1016
* krb5_cccol_cursor_new().
1017
1018
* @param context A Kerberos 5 context
1019
* @param type optional type to iterate over, if NULL, the default cache is used.
1020
* @param cursor cursor should be freed with krb5_cc_cache_end_seq_get().
1021
*
1022
* @return Return an error code or 0, see krb5_get_error_message().
1023
*
1024
* @ingroup krb5_ccache
1025
*/
1026
1027
1028
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1029
krb5_cc_cache_get_first (krb5_context context,
1030
const char *type,
1031
krb5_cc_cache_cursor *cursor)
1032
{
1033
const krb5_cc_ops *ops;
1034
krb5_error_code ret;
1035
1036
if (type == NULL)
1037
type = krb5_cc_default_name(context);
1038
1039
ops = krb5_cc_get_prefix_ops(context, type);
1040
if (ops == NULL) {
1041
krb5_set_error_message(context, KRB5_CC_UNKNOWN_TYPE,
1042
"Unknown type \"%s\" when iterating "
1043
"trying to iterate the credential caches", type);
1044
return KRB5_CC_UNKNOWN_TYPE;
1045
}
1046
1047
if (ops->get_cache_first == NULL) {
1048
krb5_set_error_message(context, KRB5_CC_NOSUPP,
1049
N_("Credential cache type %s doesn't support "
1050
"iterations over caches", "type"),
1051
ops->prefix);
1052
return KRB5_CC_NOSUPP;
1053
}
1054
1055
*cursor = calloc(1, sizeof(**cursor));
1056
if (*cursor == NULL) {
1057
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1058
return ENOMEM;
1059
}
1060
1061
(*cursor)->ops = ops;
1062
1063
ret = ops->get_cache_first(context, &(*cursor)->cursor);
1064
if (ret) {
1065
free(*cursor);
1066
*cursor = NULL;
1067
}
1068
return ret;
1069
}
1070
1071
/**
1072
* Retrieve the next cache pointed to by (`cursor') in `id'
1073
* and advance `cursor'.
1074
*
1075
* @param context A Kerberos 5 context
1076
* @param cursor the iterator cursor, returned by krb5_cc_cache_get_first()
1077
* @param id next ccache
1078
*
1079
* @return Return 0 or an error code. Returns KRB5_CC_END when the end
1080
* of caches is reached, see krb5_get_error_message().
1081
*
1082
* @ingroup krb5_ccache
1083
*/
1084
1085
1086
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1087
krb5_cc_cache_next (krb5_context context,
1088
krb5_cc_cache_cursor cursor,
1089
krb5_ccache *id)
1090
{
1091
return cursor->ops->get_cache_next(context, cursor->cursor, id);
1092
}
1093
1094
/**
1095
* Destroy the cursor `cursor'.
1096
*
1097
* @return Return an error code or 0, see krb5_get_error_message().
1098
*
1099
* @ingroup krb5_ccache
1100
*/
1101
1102
1103
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1104
krb5_cc_cache_end_seq_get (krb5_context context,
1105
krb5_cc_cache_cursor cursor)
1106
{
1107
krb5_error_code ret;
1108
ret = cursor->ops->end_cache_get(context, cursor->cursor);
1109
cursor->ops = NULL;
1110
free(cursor);
1111
return ret;
1112
}
1113
1114
/**
1115
* Search for a matching credential cache that have the
1116
* `principal' as the default principal. On success, `id' needs to be
1117
* freed with krb5_cc_close() or krb5_cc_destroy().
1118
*
1119
* @param context A Kerberos 5 context
1120
* @param client The principal to search for
1121
* @param id the returned credential cache
1122
*
1123
* @return On failure, error code is returned and `id' is set to NULL.
1124
*
1125
* @ingroup krb5_ccache
1126
*/
1127
1128
1129
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1130
krb5_cc_cache_match (krb5_context context,
1131
krb5_principal client,
1132
krb5_ccache *id)
1133
{
1134
krb5_cccol_cursor cursor;
1135
krb5_error_code ret;
1136
krb5_ccache cache = NULL;
1137
1138
*id = NULL;
1139
1140
ret = krb5_cccol_cursor_new (context, &cursor);
1141
if (ret)
1142
return ret;
1143
1144
while (krb5_cccol_cursor_next (context, cursor, &cache) == 0 && cache != NULL) {
1145
krb5_principal principal;
1146
1147
ret = krb5_cc_get_principal(context, cache, &principal);
1148
if (ret == 0) {
1149
krb5_boolean match;
1150
1151
match = krb5_principal_compare(context, principal, client);
1152
krb5_free_principal(context, principal);
1153
if (match)
1154
break;
1155
}
1156
1157
krb5_cc_close(context, cache);
1158
cache = NULL;
1159
}
1160
1161
krb5_cccol_cursor_free(context, &cursor);
1162
1163
if (cache == NULL) {
1164
char *str;
1165
1166
krb5_unparse_name(context, client, &str);
1167
1168
krb5_set_error_message(context, KRB5_CC_NOTFOUND,
1169
N_("Principal %s not found in any "
1170
"credential cache", ""),
1171
str ? str : "<out of memory>");
1172
if (str)
1173
free(str);
1174
return KRB5_CC_NOTFOUND;
1175
}
1176
*id = cache;
1177
1178
return 0;
1179
}
1180
1181
/**
1182
* Move the content from one credential cache to another. The
1183
* operation is an atomic switch.
1184
*
1185
* @param context a Keberos context
1186
* @param from the credential cache to move the content from
1187
* @param to the credential cache to move the content to
1188
1189
* @return On sucess, from is freed. On failure, error code is
1190
* returned and from and to are both still allocated, see krb5_get_error_message().
1191
*
1192
* @ingroup krb5_ccache
1193
*/
1194
1195
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1196
krb5_cc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
1197
{
1198
krb5_error_code ret;
1199
1200
if (strcmp(from->ops->prefix, to->ops->prefix) != 0) {
1201
krb5_set_error_message(context, KRB5_CC_NOSUPP,
1202
N_("Moving credentials between diffrent "
1203
"types not yet supported", ""));
1204
return KRB5_CC_NOSUPP;
1205
}
1206
1207
ret = (*to->ops->move)(context, from, to);
1208
if (ret == 0) {
1209
memset(from, 0, sizeof(*from));
1210
free(from);
1211
}
1212
return ret;
1213
}
1214
1215
#define KRB5_CONF_NAME "krb5_ccache_conf_data"
1216
#define KRB5_REALM_NAME "X-CACHECONF:"
1217
1218
static krb5_error_code
1219
build_conf_principals(krb5_context context, krb5_ccache id,
1220
krb5_const_principal principal,
1221
const char *name, krb5_creds *cred)
1222
{
1223
krb5_principal client;
1224
krb5_error_code ret;
1225
char *pname = NULL;
1226
1227
memset(cred, 0, sizeof(*cred));
1228
1229
ret = krb5_cc_get_principal(context, id, &client);
1230
if (ret)
1231
return ret;
1232
1233
if (principal) {
1234
ret = krb5_unparse_name(context, principal, &pname);
1235
if (ret)
1236
return ret;
1237
}
1238
1239
ret = krb5_make_principal(context, &cred->server,
1240
KRB5_REALM_NAME,
1241
KRB5_CONF_NAME, name, pname, NULL);
1242
free(pname);
1243
if (ret) {
1244
krb5_free_principal(context, client);
1245
return ret;
1246
}
1247
ret = krb5_copy_principal(context, client, &cred->client);
1248
krb5_free_principal(context, client);
1249
return ret;
1250
}
1251
1252
/**
1253
* Return TRUE (non zero) if the principal is a configuration
1254
* principal (generated part of krb5_cc_set_config()). Returns FALSE
1255
* (zero) if not a configuration principal.
1256
*
1257
* @param context a Keberos context
1258
* @param principal principal to check if it a configuration principal
1259
*
1260
* @ingroup krb5_ccache
1261
*/
1262
1263
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1264
krb5_is_config_principal(krb5_context context,
1265
krb5_const_principal principal)
1266
{
1267
if (strcmp(principal->realm, KRB5_REALM_NAME) != 0)
1268
return FALSE;
1269
1270
if (principal->name.name_string.len == 0 ||
1271
strcmp(principal->name.name_string.val[0], KRB5_CONF_NAME) != 0)
1272
return FALSE;
1273
1274
return TRUE;
1275
}
1276
1277
/**
1278
* Store some configuration for the credential cache in the cache.
1279
* Existing configuration under the same name is over-written.
1280
*
1281
* @param context a Keberos context
1282
* @param id the credential cache to store the data for
1283
* @param principal configuration for a specific principal, if
1284
* NULL, global for the whole cache.
1285
* @param name name under which the configuraion is stored.
1286
* @param data data to store, if NULL, configure is removed.
1287
*
1288
* @ingroup krb5_ccache
1289
*/
1290
1291
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1292
krb5_cc_set_config(krb5_context context, krb5_ccache id,
1293
krb5_const_principal principal,
1294
const char *name, krb5_data *data)
1295
{
1296
krb5_error_code ret;
1297
krb5_creds cred;
1298
1299
ret = build_conf_principals(context, id, principal, name, &cred);
1300
if (ret)
1301
goto out;
1302
1303
/* Remove old configuration */
1304
ret = krb5_cc_remove_cred(context, id, 0, &cred);
1305
if (ret && ret != KRB5_CC_NOTFOUND)
1306
goto out;
1307
1308
if (data) {
1309
/* not that anyone care when this expire */
1310
cred.times.authtime = time(NULL);
1311
cred.times.endtime = cred.times.authtime + 3600 * 24 * 30;
1312
1313
ret = krb5_data_copy(&cred.ticket, data->data, data->length);
1314
if (ret)
1315
goto out;
1316
1317
ret = krb5_cc_store_cred(context, id, &cred);
1318
}
1319
1320
out:
1321
krb5_free_cred_contents (context, &cred);
1322
return ret;
1323
}
1324
1325
/**
1326
* Get some configuration for the credential cache in the cache.
1327
*
1328
* @param context a Keberos context
1329
* @param id the credential cache to store the data for
1330
* @param principal configuration for a specific principal, if
1331
* NULL, global for the whole cache.
1332
* @param name name under which the configuraion is stored.
1333
* @param data data to fetched, free with krb5_data_free()
1334
*
1335
* @ingroup krb5_ccache
1336
*/
1337
1338
1339
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1340
krb5_cc_get_config(krb5_context context, krb5_ccache id,
1341
krb5_const_principal principal,
1342
const char *name, krb5_data *data)
1343
{
1344
krb5_creds mcred, cred;
1345
krb5_error_code ret;
1346
1347
memset(&cred, 0, sizeof(cred));
1348
krb5_data_zero(data);
1349
1350
ret = build_conf_principals(context, id, principal, name, &mcred);
1351
if (ret)
1352
goto out;
1353
1354
ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred);
1355
if (ret)
1356
goto out;
1357
1358
ret = krb5_data_copy(data, cred.ticket.data, cred.ticket.length);
1359
1360
out:
1361
krb5_free_cred_contents (context, &cred);
1362
krb5_free_cred_contents (context, &mcred);
1363
return ret;
1364
}
1365
1366
/*
1367
*
1368
*/
1369
1370
struct krb5_cccol_cursor_data {
1371
int idx;
1372
krb5_cc_cache_cursor cursor;
1373
};
1374
1375
/**
1376
* Get a new cache interation cursor that will interate over all
1377
* credentials caches independent of type.
1378
*
1379
* @param context a Keberos context
1380
* @param cursor passed into krb5_cccol_cursor_next() and free with krb5_cccol_cursor_free().
1381
*
1382
* @return Returns 0 or and error code, see krb5_get_error_message().
1383
*
1384
* @ingroup krb5_ccache
1385
*/
1386
1387
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1388
krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor)
1389
{
1390
*cursor = calloc(1, sizeof(**cursor));
1391
if (*cursor == NULL) {
1392
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1393
return ENOMEM;
1394
}
1395
(*cursor)->idx = 0;
1396
(*cursor)->cursor = NULL;
1397
1398
return 0;
1399
}
1400
1401
/**
1402
* Get next credential cache from the iteration.
1403
*
1404
* @param context A Kerberos 5 context
1405
* @param cursor the iteration cursor
1406
* @param cache the returned cursor, pointer is set to NULL on failure
1407
* and a cache on success. The returned cache needs to be freed
1408
* with krb5_cc_close() or destroyed with krb5_cc_destroy().
1409
* MIT Kerberos behavies slightly diffrent and sets cache to NULL
1410
* when all caches are iterated over and return 0.
1411
*
1412
* @return Return 0 or and error, KRB5_CC_END is returned at the end
1413
* of iteration. See krb5_get_error_message().
1414
*
1415
* @ingroup krb5_ccache
1416
*/
1417
1418
1419
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1420
krb5_cccol_cursor_next(krb5_context context, krb5_cccol_cursor cursor,
1421
krb5_ccache *cache)
1422
{
1423
krb5_error_code ret;
1424
1425
*cache = NULL;
1426
1427
while (cursor->idx < context->num_cc_ops) {
1428
1429
if (cursor->cursor == NULL) {
1430
ret = krb5_cc_cache_get_first (context,
1431
context->cc_ops[cursor->idx]->prefix,
1432
&cursor->cursor);
1433
if (ret) {
1434
cursor->idx++;
1435
continue;
1436
}
1437
}
1438
ret = krb5_cc_cache_next(context, cursor->cursor, cache);
1439
if (ret == 0)
1440
break;
1441
1442
krb5_cc_cache_end_seq_get(context, cursor->cursor);
1443
cursor->cursor = NULL;
1444
if (ret != KRB5_CC_END)
1445
break;
1446
1447
cursor->idx++;
1448
}
1449
if (cursor->idx >= context->num_cc_ops) {
1450
krb5_set_error_message(context, KRB5_CC_END,
1451
N_("Reached end of credential caches", ""));
1452
return KRB5_CC_END;
1453
}
1454
1455
return 0;
1456
}
1457
1458
/**
1459
* End an iteration and free all resources, can be done before end is reached.
1460
*
1461
* @param context A Kerberos 5 context
1462
* @param cursor the iteration cursor to be freed.
1463
*
1464
* @return Return 0 or and error, KRB5_CC_END is returned at the end
1465
* of iteration. See krb5_get_error_message().
1466
*
1467
* @ingroup krb5_ccache
1468
*/
1469
1470
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1471
krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor)
1472
{
1473
krb5_cccol_cursor c = *cursor;
1474
1475
*cursor = NULL;
1476
if (c) {
1477
if (c->cursor)
1478
krb5_cc_cache_end_seq_get(context, c->cursor);
1479
free(c);
1480
}
1481
return 0;
1482
}
1483
1484
/**
1485
* Return the last time the credential cache was modified.
1486
*
1487
* @param context A Kerberos 5 context
1488
* @param id The credential cache to probe
1489
* @param mtime the last modification time, set to 0 on error.
1490
1491
* @return Return 0 or and error. See krb5_get_error_message().
1492
*
1493
* @ingroup krb5_ccache
1494
*/
1495
1496
1497
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1498
krb5_cc_last_change_time(krb5_context context,
1499
krb5_ccache id,
1500
krb5_timestamp *mtime)
1501
{
1502
*mtime = 0;
1503
return (*id->ops->lastchange)(context, id, mtime);
1504
}
1505
1506
/**
1507
* Return the last modfication time for a cache collection. The query
1508
* can be limited to a specific cache type. If the function return 0
1509
* and mtime is 0, there was no credentials in the caches.
1510
*
1511
* @param context A Kerberos 5 context
1512
* @param type The credential cache to probe, if NULL, all type are traversed.
1513
* @param mtime the last modification time, set to 0 on error.
1514
1515
* @return Return 0 or and error. See krb5_get_error_message().
1516
*
1517
* @ingroup krb5_ccache
1518
*/
1519
1520
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1521
krb5_cccol_last_change_time(krb5_context context,
1522
const char *type,
1523
krb5_timestamp *mtime)
1524
{
1525
krb5_cccol_cursor cursor;
1526
krb5_error_code ret;
1527
krb5_ccache id;
1528
krb5_timestamp t = 0;
1529
1530
*mtime = 0;
1531
1532
ret = krb5_cccol_cursor_new (context, &cursor);
1533
if (ret)
1534
return ret;
1535
1536
while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) {
1537
1538
if (type && strcmp(krb5_cc_get_type(context, id), type) != 0)
1539
continue;
1540
1541
ret = krb5_cc_last_change_time(context, id, &t);
1542
krb5_cc_close(context, id);
1543
if (ret)
1544
continue;
1545
if (t > *mtime)
1546
*mtime = t;
1547
}
1548
1549
krb5_cccol_cursor_free(context, &cursor);
1550
1551
return 0;
1552
}
1553
/**
1554
* Return a friendly name on credential cache. Free the result with krb5_xfree().
1555
*
1556
* @return Return an error code or 0, see krb5_get_error_message().
1557
*
1558
* @ingroup krb5_ccache
1559
*/
1560
1561
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1562
krb5_cc_get_friendly_name(krb5_context context,
1563
krb5_ccache id,
1564
char **name)
1565
{
1566
krb5_error_code ret;
1567
krb5_data data;
1568
1569
ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data);
1570
if (ret) {
1571
krb5_principal principal;
1572
ret = krb5_cc_get_principal(context, id, &principal);
1573
if (ret)
1574
return ret;
1575
ret = krb5_unparse_name(context, principal, name);
1576
krb5_free_principal(context, principal);
1577
} else {
1578
ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data);
1579
krb5_data_free(&data);
1580
if (ret <= 0) {
1581
ret = ENOMEM;
1582
krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1583
} else
1584
ret = 0;
1585
}
1586
1587
return ret;
1588
}
1589
1590
/**
1591
* Set the friendly name on credential cache.
1592
*
1593
* @return Return an error code or 0, see krb5_get_error_message().
1594
*
1595
* @ingroup krb5_ccache
1596
*/
1597
1598
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1599
krb5_cc_set_friendly_name(krb5_context context,
1600
krb5_ccache id,
1601
const char *name)
1602
{
1603
krb5_data data;
1604
1605
data.data = rk_UNCONST(name);
1606
data.length = strlen(name);
1607
1608
return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data);
1609
}
1610
1611
/**
1612
* Get the lifetime of the initial ticket in the cache
1613
*
1614
* Get the lifetime of the initial ticket in the cache, if the initial
1615
* ticket was not found, the error code KRB5_CC_END is returned.
1616
*
1617
* @param context A Kerberos 5 context.
1618
* @param id a credential cache
1619
* @param t the relative lifetime of the initial ticket
1620
*
1621
* @return Return an error code or 0, see krb5_get_error_message().
1622
*
1623
* @ingroup krb5_ccache
1624
*/
1625
1626
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1627
krb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t)
1628
{
1629
krb5_cc_cursor cursor;
1630
krb5_error_code ret;
1631
krb5_creds cred;
1632
time_t now;
1633
1634
*t = 0;
1635
now = time(NULL);
1636
1637
ret = krb5_cc_start_seq_get(context, id, &cursor);
1638
if (ret)
1639
return ret;
1640
1641
while ((ret = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) {
1642
if (cred.flags.b.initial) {
1643
if (now < cred.times.endtime)
1644
*t = cred.times.endtime - now;
1645
krb5_free_cred_contents(context, &cred);
1646
break;
1647
}
1648
krb5_free_cred_contents(context, &cred);
1649
}
1650
1651
krb5_cc_end_seq_get(context, id, &cursor);
1652
1653
return ret;
1654
}
1655
1656
/**
1657
* Set the time offset betwen the client and the KDC
1658
*
1659
* If the backend doesn't support KDC offset, use the context global setting.
1660
*
1661
* @param context A Kerberos 5 context.
1662
* @param id a credential cache
1663
* @param offset the offset in seconds
1664
*
1665
* @return Return an error code or 0, see krb5_get_error_message().
1666
*
1667
* @ingroup krb5_ccache
1668
*/
1669
1670
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1671
krb5_cc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat offset)
1672
{
1673
if (id->ops->set_kdc_offset == NULL) {
1674
context->kdc_sec_offset = offset;
1675
context->kdc_usec_offset = 0;
1676
return 0;
1677
}
1678
return (*id->ops->set_kdc_offset)(context, id, offset);
1679
}
1680
1681
/**
1682
* Get the time offset betwen the client and the KDC
1683
*
1684
* If the backend doesn't support KDC offset, use the context global setting.
1685
*
1686
* @param context A Kerberos 5 context.
1687
* @param id a credential cache
1688
* @param offset the offset in seconds
1689
*
1690
* @return Return an error code or 0, see krb5_get_error_message().
1691
*
1692
* @ingroup krb5_ccache
1693
*/
1694
1695
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1696
krb5_cc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *offset)
1697
{
1698
if (id->ops->get_kdc_offset == NULL) {
1699
*offset = context->kdc_sec_offset;
1700
return 0;
1701
}
1702
return (*id->ops->get_kdc_offset)(context, id, offset);
1703
}
1704
1705
1706
#ifdef _WIN32
1707
1708
#define REGPATH_MIT_KRB5 "SOFTWARE\\MIT\\Kerberos5"
1709
char *
1710
_krb5_get_default_cc_name_from_registry(krb5_context context)
1711
{
1712
HKEY hk_k5 = 0;
1713
LONG code;
1714
char * ccname = NULL;
1715
1716
code = RegOpenKeyEx(HKEY_CURRENT_USER,
1717
REGPATH_MIT_KRB5,
1718
0, KEY_READ, &hk_k5);
1719
1720
if (code != ERROR_SUCCESS)
1721
return NULL;
1722
1723
ccname = _krb5_parse_reg_value_as_string(context, hk_k5, "ccname",
1724
REG_NONE, 0);
1725
1726
RegCloseKey(hk_k5);
1727
1728
return ccname;
1729
}
1730
1731
int
1732
_krb5_set_default_cc_name_to_registry(krb5_context context, krb5_ccache id)
1733
{
1734
HKEY hk_k5 = 0;
1735
LONG code;
1736
int ret = -1;
1737
char * ccname = NULL;
1738
1739
code = RegOpenKeyEx(HKEY_CURRENT_USER,
1740
REGPATH_MIT_KRB5,
1741
0, KEY_READ|KEY_WRITE, &hk_k5);
1742
1743
if (code != ERROR_SUCCESS)
1744
return -1;
1745
1746
ret = asprintf(&ccname, "%s:%s", krb5_cc_get_type(context, id), krb5_cc_get_name(context, id));
1747
if (ret < 0)
1748
goto cleanup;
1749
1750
ret = _krb5_store_string_to_reg_value(context, hk_k5, "ccname",
1751
REG_SZ, ccname, -1, 0);
1752
1753
cleanup:
1754
1755
if (ccname)
1756
free(ccname);
1757
1758
RegCloseKey(hk_k5);
1759
1760
return ret;
1761
}
1762
1763
#endif
1764
1765