1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/ccache/ccapi/stdcc.c - ccache API support functions */
3 /*
4 * Copyright 1998, 1999, 2006, 2008 by the Massachusetts Institute of
5 * Technology. All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 /*
28 * Written by Frank Dabek July 1998
29 * Updated by Jeffrey Altman June 2006
30 */
31
32 #if defined(_WIN32) || defined(USE_CCAPI)
33
34 #include "k5-int.h"
35 #include "../cc-int.h"
36 #include "stdcc.h"
37 #include "stdcc_util.h"
38 #include "string.h"
39 #include <stdio.h>
40
41 #if defined(_WIN32)
42 #include "winccld.h"
43 #endif
44
45 #ifndef CC_API_VER2
46 #define CC_API_VER2
47 #endif
48
49 #ifdef DEBUG
50 #if defined(_WIN32)
51 #include <io.h>
52 #define SHOW_DEBUG(buf) MessageBox((HWND)NULL, (buf), "ccapi debug", MB_OK)
53 #endif
54 /* XXX need macintosh debugging statement if we want to debug */
55 /* on the mac */
56 #else
57 #define SHOW_DEBUG(buf)
58 #endif
59
60 #ifdef USE_CCAPI_V3
61 cc_context_t gCntrlBlock = NULL;
62 cc_int32 gCCVersion = 0;
63 #else
64 apiCB *gCntrlBlock = NULL;
65 #endif
66
67 /*
68 * declare our global object wanna-be
69 * must be installed in ccdefops.c
70 */
71
72 krb5_cc_ops krb5_cc_stdcc_ops = {
73 0,
74 "API",
75 #ifdef USE_CCAPI_V3
76 krb5_stdccv3_get_name,
77 krb5_stdccv3_resolve,
78 krb5_stdccv3_generate_new,
79 krb5_stdccv3_initialize,
80 krb5_stdccv3_destroy,
81 krb5_stdccv3_close,
82 krb5_stdccv3_store,
83 krb5_stdccv3_retrieve,
84 krb5_stdccv3_get_principal,
85 krb5_stdccv3_start_seq_get,
86 krb5_stdccv3_next_cred,
87 krb5_stdccv3_end_seq_get,
88 krb5_stdccv3_remove,
89 krb5_stdccv3_set_flags,
90 krb5_stdccv3_get_flags,
91 krb5_stdccv3_ptcursor_new,
92 krb5_stdccv3_ptcursor_next,
93 krb5_stdccv3_ptcursor_free,
94 NULL, /* move */
95 NULL, /* wasdefault */
96 krb5_stdccv3_lock,
97 krb5_stdccv3_unlock,
98 krb5_stdccv3_switch_to,
99 #else
100 krb5_stdcc_get_name,
101 krb5_stdcc_resolve,
102 krb5_stdcc_generate_new,
103 krb5_stdcc_initialize,
104 krb5_stdcc_destroy,
105 krb5_stdcc_close,
106 krb5_stdcc_store,
107 krb5_stdcc_retrieve,
108 krb5_stdcc_get_principal,
109 krb5_stdcc_start_seq_get,
110 krb5_stdcc_next_cred,
111 krb5_stdcc_end_seq_get,
112 krb5_stdcc_remove,
113 krb5_stdcc_set_flags,
114 krb5_stdcc_get_flags,
115 NULL,
116 NULL,
117 NULL,
118 NULL,
119 NULL,
120 #endif
121 };
122
123 #if defined(_WIN32)
124 /*
125 * cache_changed be called after the cache changes.
126 * A notification message is is posted out to all top level
127 * windows so that they may recheck the cache based on the
128 * changes made. We register a unique message type with which
129 * we'll communicate to all other processes.
130 */
cache_changed()131 static void cache_changed()
132 {
133 static unsigned int message = 0;
134
135 if (message == 0)
136 message = RegisterWindowMessage(WM_KERBEROS5_CHANGED);
137
138 PostMessage(HWND_BROADCAST, message, 0, 0);
139 }
140 #else /* _WIN32 */
141
cache_changed()142 static void cache_changed()
143 {
144 return;
145 }
146 #endif /* _WIN32 */
147
148 struct err_xlate
149 {
150 int cc_err;
151 krb5_error_code krb5_err;
152 };
153
154 static const struct err_xlate err_xlate_table[] =
155 {
156 #ifdef USE_CCAPI_V3
157 { ccIteratorEnd, KRB5_CC_END },
158 { ccErrBadParam, KRB5_FCC_INTERNAL },
159 { ccErrNoMem, KRB5_CC_NOMEM },
160 { ccErrInvalidContext, KRB5_FCC_NOFILE },
161 { ccErrInvalidCCache, KRB5_FCC_NOFILE },
162 { ccErrInvalidString, KRB5_FCC_INTERNAL },
163 { ccErrInvalidCredentials, KRB5_FCC_INTERNAL },
164 { ccErrInvalidCCacheIterator, KRB5_FCC_INTERNAL },
165 { ccErrInvalidCredentialsIterator, KRB5_FCC_INTERNAL },
166 { ccErrInvalidLock, KRB5_FCC_INTERNAL },
167 { ccErrBadName, KRB5_CC_BADNAME },
168 { ccErrBadCredentialsVersion, KRB5_FCC_INTERNAL },
169 { ccErrBadAPIVersion, KRB5_FCC_INTERNAL },
170 { ccErrContextLocked, KRB5_FCC_INTERNAL },
171 { ccErrContextUnlocked, KRB5_FCC_INTERNAL },
172 { ccErrCCacheLocked, KRB5_FCC_INTERNAL },
173 { ccErrCCacheUnlocked, KRB5_FCC_INTERNAL },
174 { ccErrBadLockType, KRB5_FCC_INTERNAL },
175 { ccErrNeverDefault, KRB5_FCC_INTERNAL },
176 { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND },
177 { ccErrCCacheNotFound, KRB5_FCC_NOFILE },
178 { ccErrContextNotFound, KRB5_FCC_NOFILE },
179 { ccErrServerUnavailable, KRB5_CC_IO },
180 { ccErrServerInsecure, KRB5_CC_IO },
181 { ccErrServerCantBecomeUID, KRB5_CC_IO },
182 { ccErrTimeOffsetNotSet, KRB5_FCC_INTERNAL },
183 { ccErrBadInternalMessage, KRB5_FCC_INTERNAL },
184 { ccErrNotImplemented, KRB5_FCC_INTERNAL },
185 #else
186 { CC_BADNAME, KRB5_CC_BADNAME },
187 { CC_NOTFOUND, KRB5_CC_NOTFOUND },
188 { CC_END, KRB5_CC_END },
189 { CC_IO, KRB5_CC_IO },
190 { CC_WRITE, KRB5_CC_WRITE },
191 { CC_NOMEM, KRB5_CC_NOMEM },
192 { CC_FORMAT, KRB5_CC_FORMAT },
193 { CC_WRITE, KRB5_CC_WRITE },
194 { CC_LOCKED, KRB5_FCC_INTERNAL /* XXX */ },
195 { CC_BAD_API_VERSION, KRB5_FCC_INTERNAL /* XXX */ },
196 { CC_NO_EXIST, KRB5_FCC_NOFILE },
197 { CC_NOT_SUPP, KRB5_FCC_INTERNAL /* XXX */ },
198 { CC_BAD_PARM, KRB5_FCC_INTERNAL /* XXX */ },
199 { CC_ERR_CACHE_ATTACH, KRB5_FCC_INTERNAL /* XXX */ },
200 { CC_ERR_CACHE_RELEASE, KRB5_FCC_INTERNAL /* XXX */ },
201 { CC_ERR_CACHE_FULL, KRB5_FCC_INTERNAL /* XXX */ },
202 { CC_ERR_CRED_VERSION, KRB5_FCC_INTERNAL /* XXX */ },
203 #endif
204 { 0, 0 }
205 };
206
207 /* Note: cc_err_xlate is NOT idempotent. Don't call it multiple times. */
cc_err_xlate(int err)208 static krb5_error_code cc_err_xlate(int err)
209 {
210 const struct err_xlate *p;
211
212 #ifdef USE_CCAPI_V3
213 if (err == ccNoError)
214 return 0;
215 #else
216 if (err == CC_NOERROR)
217 return 0;
218 #endif
219
220 for (p = err_xlate_table; p->cc_err; p++) {
221 if (err == p->cc_err)
222 return p->krb5_err;
223 }
224
225 return KRB5_FCC_INTERNAL;
226 }
227
228
229 #ifdef USE_CCAPI_V3
230
stdccv3_get_timeoffset(krb5_context in_context,cc_ccache_t in_ccache)231 static krb5_error_code stdccv3_get_timeoffset (krb5_context in_context,
232 cc_ccache_t in_ccache)
233 {
234 krb5_error_code err = 0;
235
236 if (gCCVersion >= ccapi_version_5) {
237 krb5_os_context os_ctx = (krb5_os_context) &in_context->os_context;
238 cc_time_t time_offset = 0;
239
240 err = cc_ccache_get_kdc_time_offset (in_ccache, cc_credentials_v5,
241 &time_offset);
242
243 if (!err) {
244 os_ctx->time_offset = time_offset;
245 os_ctx->usec_offset = 0;
246 os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
247 KRB5_OS_TOFFSET_VALID);
248 }
249
250 if (err == ccErrTimeOffsetNotSet) {
251 err = 0; /* okay if there is no time offset */
252 }
253 }
254
255 return err; /* Don't translate. Callers will translate for us */
256 }
257
stdccv3_set_timeoffset(krb5_context in_context,cc_ccache_t in_ccache)258 static krb5_error_code stdccv3_set_timeoffset (krb5_context in_context,
259 cc_ccache_t in_ccache)
260 {
261 krb5_error_code err = 0;
262
263 if (gCCVersion >= ccapi_version_5) {
264 krb5_os_context os_ctx = (krb5_os_context) &in_context->os_context;
265
266 if (!err && os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
267 err = cc_ccache_set_kdc_time_offset (in_ccache,
268 cc_credentials_v5,
269 os_ctx->time_offset);
270 }
271 }
272
273 return err; /* Don't translate. Callers will translate for us */
274 }
275
stdccv3_setup(krb5_context context,stdccCacheDataPtr ccapi_data)276 static krb5_error_code stdccv3_setup (krb5_context context,
277 stdccCacheDataPtr ccapi_data)
278 {
279 krb5_error_code err = 0;
280
281 if (!err && !gCntrlBlock) {
282 err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
283 }
284
285 if (!err && ccapi_data && !ccapi_data->NamedCache) {
286 /* ccache has not been opened yet. open it. */
287 err = cc_context_open_ccache (gCntrlBlock, ccapi_data->cache_name,
288 &ccapi_data->NamedCache);
289 }
290
291 if (!err && ccapi_data && ccapi_data->NamedCache) {
292 err = stdccv3_get_timeoffset (context, ccapi_data->NamedCache);
293 }
294
295 return err; /* Don't translate. Callers will translate for us */
296 }
297
298 /* krb5_stdcc_shutdown is exported; use the old name */
krb5_stdcc_shutdown()299 void krb5_stdcc_shutdown()
300 {
301 if (gCntrlBlock) { cc_context_release(gCntrlBlock); }
302 gCntrlBlock = NULL;
303 gCCVersion = 0;
304 }
305
306 /*
307 * -- generate_new --------------------------------
308 *
309 * create a new cache with a unique name, corresponds to creating a
310 * named cache initialize the API here if we have to.
311 */
312 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_generate_new(krb5_context context,krb5_ccache * id)313 krb5_stdccv3_generate_new (krb5_context context, krb5_ccache *id )
314 {
315 krb5_error_code err = 0;
316 krb5_ccache newCache = NULL;
317 stdccCacheDataPtr ccapi_data = NULL;
318 cc_ccache_t ccache = NULL;
319 cc_string_t ccstring = NULL;
320 char *name = NULL;
321
322 if (!err) {
323 err = stdccv3_setup(context, NULL);
324 }
325
326 if (!err) {
327 newCache = (krb5_ccache) malloc (sizeof (*newCache));
328 if (!newCache) { err = KRB5_CC_NOMEM; }
329 }
330
331 if (!err) {
332 ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
333 if (!ccapi_data) { err = KRB5_CC_NOMEM; }
334 }
335
336 if (!err) {
337 err = cc_context_create_new_ccache (gCntrlBlock, cc_credentials_v5, "",
338 &ccache);
339 }
340
341 if (!err) {
342 err = stdccv3_set_timeoffset (context, ccache);
343 }
344
345 if (!err) {
346 err = cc_ccache_get_name (ccache, &ccstring);
347 }
348
349 if (!err) {
350 name = strdup (ccstring->data);
351 if (!name) { err = KRB5_CC_NOMEM; }
352 }
353
354 if (!err) {
355 ccapi_data->cache_name = name;
356 name = NULL; /* take ownership */
357
358 ccapi_data->NamedCache = ccache;
359 ccache = NULL; /* take ownership */
360
361 newCache->ops = &krb5_cc_stdcc_ops;
362 newCache->data = ccapi_data;
363 ccapi_data = NULL; /* take ownership */
364
365 /* return a pointer to the new cache */
366 *id = newCache;
367 newCache = NULL;
368 }
369
370 if (ccstring) { cc_string_release (ccstring); }
371 if (name) { free (name); }
372 if (ccache) { cc_ccache_release (ccache); }
373 if (ccapi_data) { free (ccapi_data); }
374 if (newCache) { free (newCache); }
375
376 return cc_err_xlate (err);
377 }
378
379 /*
380 * resolve
381 *
382 * create a new cache with the name stored in residual
383 */
384 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_resolve(krb5_context context,krb5_ccache * id,const char * residual)385 krb5_stdccv3_resolve (krb5_context context, krb5_ccache *id , const char *residual )
386 {
387 krb5_error_code err = 0;
388 stdccCacheDataPtr ccapi_data = NULL;
389 krb5_ccache ccache = NULL;
390 char *name = NULL;
391 cc_string_t defname = NULL;
392
393 if (id == NULL) { err = KRB5_CC_NOMEM; }
394
395 if (!err) {
396 err = stdccv3_setup (context, NULL);
397 }
398
399 if (!err) {
400 ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
401 if (!ccapi_data) { err = KRB5_CC_NOMEM; }
402 }
403
404 if (!err) {
405 ccache = (krb5_ccache ) malloc (sizeof (*ccache));
406 if (!ccache) { err = KRB5_CC_NOMEM; }
407 }
408
409 if (!err) {
410 if ((residual == NULL) || (strlen(residual) == 0)) {
411 err = cc_context_get_default_ccache_name(gCntrlBlock, &defname);
412 if (defname)
413 residual = defname->data;
414 }
415 }
416
417 if (!err) {
418 name = strdup (residual);
419 if (!name) { err = KRB5_CC_NOMEM; }
420 }
421
422 if (!err) {
423 err = cc_context_open_ccache (gCntrlBlock, residual,
424 &ccapi_data->NamedCache);
425 if (err == ccErrCCacheNotFound) {
426 ccapi_data->NamedCache = NULL;
427 err = 0; /* ccache just doesn't exist yet */
428 }
429 }
430
431 if (!err) {
432 ccapi_data->cache_name = name;
433 name = NULL; /* take ownership */
434
435 ccache->ops = &krb5_cc_stdcc_ops;
436 ccache->data = ccapi_data;
437 ccapi_data = NULL; /* take ownership */
438
439 *id = ccache;
440 ccache = NULL; /* take ownership */
441 }
442
443 if (ccache) { free (ccache); }
444 if (ccapi_data) { free (ccapi_data); }
445 if (name) { free (name); }
446 if (defname) { cc_string_release(defname); }
447
448 return cc_err_xlate (err);
449 }
450
451 /*
452 * initialize
453 *
454 * initialize the cache, check to see if one already exists for this
455 * principal if not set our principal to this principal. This
456 * searching enables ticket sharing
457 */
458 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_initialize(krb5_context context,krb5_ccache id,krb5_principal princ)459 krb5_stdccv3_initialize (krb5_context context,
460 krb5_ccache id,
461 krb5_principal princ)
462 {
463 krb5_error_code err = 0;
464 stdccCacheDataPtr ccapi_data = id->data;
465 char *name = NULL;
466 cc_ccache_t ccache = NULL;
467
468 if (id == NULL) { err = KRB5_CC_NOMEM; }
469
470 if (!err) {
471 err = stdccv3_setup (context, NULL);
472 }
473
474 if (!err) {
475 err = krb5_unparse_name(context, princ, &name);
476 }
477
478 if (!err) {
479 err = cc_context_create_ccache (gCntrlBlock, ccapi_data->cache_name,
480 cc_credentials_v5, name,
481 &ccache);
482 }
483
484 if (!err) {
485 err = stdccv3_set_timeoffset (context, ccache);
486 }
487
488 if (!err) {
489 if (ccapi_data->NamedCache) {
490 err = cc_ccache_release (ccapi_data->NamedCache);
491 }
492 ccapi_data->NamedCache = ccache;
493 ccache = NULL; /* take ownership */
494 cache_changed ();
495 }
496
497 if (ccache) { cc_ccache_release (ccache); }
498 if (name ) { krb5_free_unparsed_name(context, name); }
499
500 return cc_err_xlate(err);
501 }
502
503 /*
504 * store
505 *
506 * store some credentials in our cache
507 */
508 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_store(krb5_context context,krb5_ccache id,krb5_creds * creds)509 krb5_stdccv3_store (krb5_context context, krb5_ccache id, krb5_creds *creds )
510 {
511 krb5_error_code err = 0;
512 stdccCacheDataPtr ccapi_data = id->data;
513 cc_credentials_union *cred_union = NULL;
514
515 if (!err) {
516 err = stdccv3_setup (context, ccapi_data);
517 }
518
519 if (!err) {
520 /* copy the fields from the almost identical structures */
521 err = copy_krb5_creds_to_cc_cred_union (context, creds, &cred_union);
522 }
523
524 if (!err) {
525 err = cc_ccache_store_credentials (ccapi_data->NamedCache, cred_union);
526 }
527
528 if (!err) {
529 cache_changed();
530 }
531
532 if (cred_union) { cred_union_release (cred_union); }
533
534 return cc_err_xlate (err);
535 }
536
537 /*
538 * start_seq_get
539 *
540 * begin an iterator call to get all of the credentials in the cache
541 */
542 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_start_seq_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)543 krb5_stdccv3_start_seq_get (krb5_context context,
544 krb5_ccache id,
545 krb5_cc_cursor *cursor )
546 {
547 krb5_error_code err = 0;
548 stdccCacheDataPtr ccapi_data = id->data;
549 cc_credentials_iterator_t iterator = NULL;
550
551 if (!err) {
552 err = stdccv3_setup (context, ccapi_data);
553 }
554
555 if (!err) {
556 err = cc_ccache_new_credentials_iterator(ccapi_data->NamedCache,
557 &iterator);
558 }
559
560 if (!err) {
561 *cursor = iterator;
562 }
563
564 return cc_err_xlate (err);
565 }
566
567 /*
568 * next cred
569 *
570 * - get the next credential in the cache as part of an iterator call
571 * - this maps to call to cc_seq_fetch_creds
572 */
573 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_next_cred(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)574 krb5_stdccv3_next_cred (krb5_context context,
575 krb5_ccache id,
576 krb5_cc_cursor *cursor,
577 krb5_creds *creds)
578 {
579 krb5_error_code err = 0;
580 stdccCacheDataPtr ccapi_data = id->data;
581 cc_credentials_t credentials = NULL;
582 cc_credentials_iterator_t iterator = *cursor;
583
584 if (!iterator) { err = KRB5_CC_END; }
585
586 if (!err) {
587 err = stdccv3_setup (context, ccapi_data);
588 }
589
590 while (!err) {
591 err = cc_credentials_iterator_next (iterator, &credentials);
592
593 if (!err && (credentials->data->version == cc_credentials_v5)) {
594 copy_cc_cred_union_to_krb5_creds(context, credentials->data, creds);
595 break;
596 }
597 }
598
599 if (credentials) { cc_credentials_release (credentials); }
600 if (err == ccIteratorEnd) {
601 cc_credentials_iterator_release (iterator);
602 *cursor = 0;
603 }
604
605 return cc_err_xlate (err);
606 }
607
608
609 /*
610 * retrieve
611 *
612 * - try to find a matching credential in the cache
613 */
614 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_retrieve(krb5_context context,krb5_ccache id,krb5_flags whichfields,krb5_creds * mcreds,krb5_creds * creds)615 krb5_stdccv3_retrieve (krb5_context context,
616 krb5_ccache id,
617 krb5_flags whichfields,
618 krb5_creds *mcreds,
619 krb5_creds *creds)
620 {
621 return k5_cc_retrieve_cred_default(context, id, whichfields, mcreds,
622 creds);
623 }
624
625 /*
626 * end seq
627 *
628 * just free up the storage associated with the cursor (if we can)
629 */
630 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_end_seq_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)631 krb5_stdccv3_end_seq_get (krb5_context context,
632 krb5_ccache id,
633 krb5_cc_cursor *cursor)
634 {
635 krb5_error_code err = 0;
636 stdccCacheDataPtr ccapi_data = id->data;
637 cc_credentials_iterator_t iterator = *cursor;
638
639 if (!iterator) { return 0; }
640
641 if (!err) {
642 err = stdccv3_setup (context, ccapi_data);
643 }
644
645 if (!err) {
646 err = cc_credentials_iterator_release(iterator);
647 }
648
649 return cc_err_xlate(err);
650 }
651
652 /*
653 * close
654 *
655 * - free our pointers to the NC
656 */
657 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_close(krb5_context context,krb5_ccache id)658 krb5_stdccv3_close(krb5_context context,
659 krb5_ccache id)
660 {
661 krb5_error_code err = 0;
662 stdccCacheDataPtr ccapi_data = id->data;
663
664 if (!err) {
665 err = stdccv3_setup (context, NULL);
666 }
667
668 if (!err) {
669 if (ccapi_data) {
670 if (ccapi_data->cache_name) {
671 free (ccapi_data->cache_name);
672 }
673 if (ccapi_data->NamedCache) {
674 err = cc_ccache_release (ccapi_data->NamedCache);
675 }
676 free (ccapi_data);
677 id->data = NULL;
678 }
679 free (id);
680 }
681
682 return cc_err_xlate(err);
683 }
684
685 /*
686 * destroy
687 *
688 * - free our storage and the cache
689 */
690 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_destroy(krb5_context context,krb5_ccache id)691 krb5_stdccv3_destroy (krb5_context context,
692 krb5_ccache id)
693 {
694 krb5_error_code err = 0;
695 stdccCacheDataPtr ccapi_data = id->data;
696
697 if (!err) {
698 err = stdccv3_setup(context, ccapi_data);
699 }
700
701 if (!err) {
702 if (ccapi_data) {
703 if (ccapi_data->cache_name) {
704 free(ccapi_data->cache_name);
705 }
706 if (ccapi_data->NamedCache) {
707 /* destroy the named cache */
708 err = cc_ccache_destroy(ccapi_data->NamedCache);
709 if (err == ccErrCCacheNotFound) {
710 err = 0; /* ccache maybe already destroyed */
711 }
712 cache_changed();
713 }
714 free(ccapi_data);
715 id->data = NULL;
716 }
717 free(id);
718 }
719
720 return cc_err_xlate(err);
721 }
722
723 /*
724 * getname
725 *
726 * - return the name of the named cache
727 */
728 const char * KRB5_CALLCONV
krb5_stdccv3_get_name(krb5_context context,krb5_ccache id)729 krb5_stdccv3_get_name (krb5_context context,
730 krb5_ccache id )
731 {
732 stdccCacheDataPtr ccapi_data = id->data;
733
734 if (!ccapi_data) {
735 return NULL;
736 } else {
737 return (ccapi_data->cache_name);
738 }
739 }
740
741
742 /* get_principal
743 *
744 * - return the principal associated with the named cache
745 */
746 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_get_principal(krb5_context context,krb5_ccache id,krb5_principal * princ)747 krb5_stdccv3_get_principal (krb5_context context,
748 krb5_ccache id ,
749 krb5_principal *princ)
750 {
751 krb5_error_code err = 0;
752 stdccCacheDataPtr ccapi_data = id->data;
753 cc_string_t name = NULL;
754
755 if (!err) {
756 err = stdccv3_setup(context, ccapi_data);
757 }
758
759 if (!err) {
760 err = cc_ccache_get_principal (ccapi_data->NamedCache, cc_credentials_v5, &name);
761 }
762
763 if (!err) {
764 err = krb5_parse_name (context, name->data, princ);
765 } else {
766 err = cc_err_xlate (err);
767 }
768
769 if (name) { cc_string_release (name); }
770
771 return err;
772 }
773
774 /*
775 * set_flags
776 *
777 * - currently a NOP since we don't store any flags in the NC
778 */
779 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)780 krb5_stdccv3_set_flags (krb5_context context,
781 krb5_ccache id,
782 krb5_flags flags)
783 {
784 krb5_error_code err = 0;
785 stdccCacheDataPtr ccapi_data = id->data;
786
787 err = stdccv3_setup (context, ccapi_data);
788
789 return cc_err_xlate (err);
790 }
791
792 /*
793 * get_flags
794 *
795 * - currently a NOP since we don't store any flags in the NC
796 */
797 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_get_flags(krb5_context context,krb5_ccache id,krb5_flags * flags)798 krb5_stdccv3_get_flags (krb5_context context,
799 krb5_ccache id,
800 krb5_flags *flags)
801 {
802 krb5_error_code err = 0;
803 stdccCacheDataPtr ccapi_data = id->data;
804
805 err = stdccv3_setup (context, ccapi_data);
806
807 return cc_err_xlate (err);
808 }
809
810 /*
811 * remove
812 *
813 * - remove the specified credentials from the NC
814 */
815 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_remove(krb5_context context,krb5_ccache id,krb5_flags whichfields,krb5_creds * in_creds)816 krb5_stdccv3_remove (krb5_context context,
817 krb5_ccache id,
818 krb5_flags whichfields,
819 krb5_creds *in_creds)
820 {
821 krb5_error_code err = 0;
822 stdccCacheDataPtr ccapi_data = id->data;
823 cc_credentials_iterator_t iterator = NULL;
824 int found = 0;
825
826 if (!err) {
827 err = stdccv3_setup(context, ccapi_data);
828 }
829
830
831 if (!err) {
832 err = cc_ccache_new_credentials_iterator(ccapi_data->NamedCache,
833 &iterator);
834 }
835
836 while (!err && !found) {
837 cc_credentials_t credentials = NULL;
838
839 err = cc_credentials_iterator_next (iterator, &credentials);
840
841 if (!err && (credentials->data->version == cc_credentials_v5)) {
842 krb5_creds creds;
843
844 err = copy_cc_cred_union_to_krb5_creds(context,
845 credentials->data, &creds);
846
847 if (!err) {
848 found = krb5int_cc_creds_match_request(context,
849 whichfields,
850 in_creds,
851 &creds);
852 krb5_free_cred_contents (context, &creds);
853 }
854
855 if (!err && found) {
856 err = cc_ccache_remove_credentials (ccapi_data->NamedCache, credentials);
857 }
858 }
859
860 if (credentials) { cc_credentials_release (credentials); }
861 }
862 if (err == ccIteratorEnd) { err = ccErrCredentialsNotFound; }
863
864 if (iterator) {
865 err = cc_credentials_iterator_release(iterator);
866 }
867
868 if (!err) {
869 cache_changed ();
870 }
871
872 return cc_err_xlate (err);
873 }
874
875 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_new(krb5_context context,krb5_cc_ptcursor * cursor)876 krb5_stdccv3_ptcursor_new(krb5_context context,
877 krb5_cc_ptcursor *cursor)
878 {
879 krb5_error_code err = 0;
880 krb5_cc_ptcursor ptcursor = NULL;
881 cc_ccache_iterator_t iterator = NULL;
882
883 ptcursor = malloc(sizeof(*ptcursor));
884 if (ptcursor == NULL) {
885 err = ccErrNoMem;
886 }
887 else {
888 memset(ptcursor, 0, sizeof(*ptcursor));
889 }
890
891 if (!err) {
892 err = stdccv3_setup(context, NULL);
893 }
894 if (!err) {
895 ptcursor->ops = &krb5_cc_stdcc_ops;
896 err = cc_context_new_ccache_iterator(gCntrlBlock, &iterator);
897 }
898
899 if (!err) {
900 ptcursor->data = iterator;
901 }
902
903 if (err) {
904 if (ptcursor) { krb5_stdccv3_ptcursor_free(context, &ptcursor); }
905 // krb5_stdccv3_ptcursor_free sets ptcursor to NULL for us
906 }
907
908 *cursor = ptcursor;
909
910 return cc_err_xlate(err);
911 }
912
913 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_next(krb5_context context,krb5_cc_ptcursor cursor,krb5_ccache * ccache)914 krb5_stdccv3_ptcursor_next(
915 krb5_context context,
916 krb5_cc_ptcursor cursor,
917 krb5_ccache *ccache)
918 {
919 krb5_error_code err = 0;
920 cc_ccache_iterator_t iterator = NULL;
921
922 krb5_ccache newCache = NULL;
923 stdccCacheDataPtr ccapi_data = NULL;
924 cc_ccache_t ccCache = NULL;
925 cc_string_t ccstring = NULL;
926 char *name = NULL;
927
928 if (!cursor || !cursor->data) {
929 err = ccErrInvalidContext;
930 }
931
932 *ccache = NULL;
933
934 if (!err) {
935 newCache = (krb5_ccache) malloc (sizeof (*newCache));
936 if (!newCache) { err = ccErrNoMem; }
937 }
938
939 if (!err) {
940 ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
941 if (!ccapi_data) { err = ccErrNoMem; }
942 }
943
944 if (!err) {
945 iterator = cursor->data;
946 err = cc_ccache_iterator_next(iterator, &ccCache);
947 }
948
949 if (!err) {
950 err = cc_ccache_get_name (ccCache, &ccstring);
951 }
952
953 if (!err) {
954 name = strdup (ccstring->data);
955 if (!name) { err = ccErrNoMem; }
956 }
957
958 if (!err) {
959 ccapi_data->cache_name = name;
960 name = NULL; /* take ownership */
961
962 ccapi_data->NamedCache = ccCache;
963 ccCache = NULL; /* take ownership */
964
965 newCache->ops = &krb5_cc_stdcc_ops;
966 newCache->data = ccapi_data;
967 ccapi_data = NULL; /* take ownership */
968
969 /* return a pointer to the new cache */
970 *ccache = newCache;
971 newCache = NULL;
972 }
973
974 if (name) { free (name); }
975 if (ccstring) { cc_string_release (ccstring); }
976 if (ccCache) { cc_ccache_release (ccCache); }
977 if (ccapi_data) { free (ccapi_data); }
978 if (newCache) { free (newCache); }
979
980 if (err == ccIteratorEnd) {
981 err = ccNoError;
982 }
983
984 return cc_err_xlate(err);
985 }
986
987 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_free(krb5_context context,krb5_cc_ptcursor * cursor)988 krb5_stdccv3_ptcursor_free(
989 krb5_context context,
990 krb5_cc_ptcursor *cursor)
991 {
992 if (*cursor != NULL) {
993 if ((*cursor)->data != NULL) {
994 cc_ccache_iterator_release((cc_ccache_iterator_t)((*cursor)->data));
995 }
996 free(*cursor);
997 *cursor = NULL;
998 }
999 return 0;
1000 }
1001
krb5_stdccv3_lock(krb5_context context,krb5_ccache id)1002 krb5_error_code KRB5_CALLCONV krb5_stdccv3_lock
1003 (krb5_context context, krb5_ccache id)
1004 {
1005 krb5_error_code err = 0;
1006 stdccCacheDataPtr ccapi_data = id->data;
1007
1008 if (!err) {
1009 err = stdccv3_setup(context, ccapi_data);
1010 }
1011 if (!err) {
1012 err = cc_ccache_lock(ccapi_data->NamedCache, cc_lock_write, cc_lock_block);
1013 }
1014 return cc_err_xlate(err);
1015 }
1016
krb5_stdccv3_unlock(krb5_context context,krb5_ccache id)1017 krb5_error_code KRB5_CALLCONV krb5_stdccv3_unlock
1018 (krb5_context context, krb5_ccache id)
1019 {
1020 krb5_error_code err = 0;
1021 stdccCacheDataPtr ccapi_data = id->data;
1022
1023 if (!err) {
1024 err = stdccv3_setup(context, ccapi_data);
1025 }
1026 if (!err) {
1027 err = cc_ccache_unlock(ccapi_data->NamedCache);
1028 }
1029 return cc_err_xlate(err);
1030 }
1031
krb5_stdccv3_context_lock(krb5_context context)1032 krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_lock
1033 (krb5_context context)
1034 {
1035 krb5_error_code err = 0;
1036
1037 if (!err && !gCntrlBlock) {
1038 err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
1039 }
1040 if (!err) {
1041 err = cc_context_lock(gCntrlBlock, cc_lock_write, cc_lock_block);
1042 }
1043 return cc_err_xlate(err);
1044 }
1045
krb5_stdccv3_context_unlock(krb5_context context)1046 krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_unlock
1047 (krb5_context context)
1048 {
1049 krb5_error_code err = 0;
1050
1051 if (!err && !gCntrlBlock) {
1052 err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
1053 }
1054 if (!err) {
1055 err = cc_context_unlock(gCntrlBlock);
1056 }
1057 return cc_err_xlate(err);
1058 }
1059
krb5_stdccv3_switch_to(krb5_context context,krb5_ccache id)1060 krb5_error_code KRB5_CALLCONV krb5_stdccv3_switch_to
1061 (krb5_context context, krb5_ccache id)
1062 {
1063 krb5_error_code retval;
1064 stdccCacheDataPtr ccapi_data = id->data;
1065 int err;
1066
1067 retval = stdccv3_setup(context, ccapi_data);
1068 if (retval)
1069 return cc_err_xlate(retval);
1070
1071 err = cc_ccache_set_default(ccapi_data->NamedCache);
1072 return cc_err_xlate(err);
1073 }
1074
1075 #else /* !USE_CCAPI_V3 */
1076
stdcc_setup(krb5_context context,stdccCacheDataPtr ccapi_data)1077 static krb5_error_code stdcc_setup(krb5_context context,
1078 stdccCacheDataPtr ccapi_data)
1079 {
1080 int err;
1081
1082 /* make sure the API has been initialized */
1083 if (gCntrlBlock == NULL) {
1084 #ifdef CC_API_VER2
1085 err = cc_initialize(&gCntrlBlock, CC_API_VER_2, NULL, NULL);
1086 #else
1087 err = cc_initialize(&gCntrlBlock, CC_API_VER_1, NULL, NULL);
1088 #endif
1089 if (err != CC_NOERROR)
1090 return cc_err_xlate(err);
1091 }
1092
1093 /*
1094 * No ccapi_data structure, so we don't need to make sure the
1095 * ccache exists.
1096 */
1097 if (!ccapi_data)
1098 return 0;
1099
1100 /*
1101 * The ccache already exists
1102 */
1103 if (ccapi_data->NamedCache)
1104 return 0;
1105
1106 err = cc_open(gCntrlBlock, ccapi_data->cache_name,
1107 CC_CRED_V5, 0L, &ccapi_data->NamedCache);
1108 if (err == CC_NOTFOUND)
1109 err = CC_NO_EXIST;
1110 if (err == CC_NOERROR)
1111 return 0;
1112
1113 ccapi_data->NamedCache = NULL;
1114 return cc_err_xlate(err);
1115 }
1116
krb5_stdcc_shutdown()1117 void krb5_stdcc_shutdown()
1118 {
1119 if (gCntrlBlock)
1120 cc_shutdown(&gCntrlBlock);
1121 gCntrlBlock = NULL;
1122 }
1123
1124 /*
1125 * -- generate_new --------------------------------
1126 *
1127 * create a new cache with a unique name, corresponds to creating a
1128 * named cache iniitialize the API here if we have to.
1129 */
krb5_stdcc_generate_new(krb5_context context,krb5_ccache * id)1130 krb5_error_code KRB5_CALLCONV krb5_stdcc_generate_new
1131 (krb5_context context, krb5_ccache *id )
1132 {
1133 krb5_ccache newCache = NULL;
1134 krb5_error_code retval;
1135 stdccCacheDataPtr ccapi_data = NULL;
1136 char *name = NULL;
1137 cc_time_t change_time;
1138 int err;
1139
1140 if ((retval = stdcc_setup(context, NULL)))
1141 return retval;
1142
1143 retval = KRB5_CC_NOMEM;
1144 if (!(newCache = (krb5_ccache) malloc(sizeof(struct _krb5_ccache))))
1145 goto errout;
1146 if (!(ccapi_data = (stdccCacheDataPtr)malloc(sizeof(stdccCacheData))))
1147 goto errout;
1148 if (!(name = malloc(256)))
1149 goto errout;
1150
1151 /* create a unique name */
1152 cc_get_change_time(gCntrlBlock, &change_time);
1153 snprintf(name, 256, "gen_new_cache%d", change_time);
1154
1155 /* create the new cache */
1156 err = cc_create(gCntrlBlock, name, name, CC_CRED_V5, 0L,
1157 &ccapi_data->NamedCache);
1158 if (err != CC_NOERROR) {
1159 retval = cc_err_xlate(err);
1160 goto errout;
1161 }
1162
1163 /* setup some fields */
1164 newCache->ops = &krb5_cc_stdcc_ops;
1165 newCache->data = ccapi_data;
1166 ccapi_data->cache_name = name;
1167
1168 /* return a pointer to the new cache */
1169 *id = newCache;
1170
1171 return 0;
1172
1173 errout:
1174 if (newCache)
1175 free(newCache);
1176 if (ccapi_data)
1177 free(ccapi_data);
1178 if (name)
1179 free(name);
1180 return retval;
1181 }
1182
1183 /*
1184 * resolve
1185 *
1186 * create a new cache with the name stored in residual
1187 */
krb5_stdcc_resolve(krb5_context context,krb5_ccache * id,const char * residual)1188 krb5_error_code KRB5_CALLCONV krb5_stdcc_resolve
1189 (krb5_context context, krb5_ccache *id , const char *residual )
1190 {
1191 krb5_ccache newCache = NULL;
1192 stdccCacheDataPtr ccapi_data = NULL;
1193 int err;
1194 krb5_error_code retval;
1195 char *cName = NULL;
1196
1197 if ((retval = stdcc_setup(context, NULL)))
1198 return retval;
1199
1200 retval = KRB5_CC_NOMEM;
1201 if (!(newCache = (krb5_ccache) malloc(sizeof(struct _krb5_ccache))))
1202 goto errout;
1203
1204 if (!(ccapi_data = (stdccCacheDataPtr)malloc(sizeof(stdccCacheData))))
1205 goto errout;
1206
1207 if (!(cName = strdup(residual)))
1208 goto errout;
1209
1210 newCache->ops = &krb5_cc_stdcc_ops;
1211 newCache->data = ccapi_data;
1212 ccapi_data->cache_name = cName;
1213
1214 err = cc_open(gCntrlBlock, cName, CC_CRED_V5, 0L,
1215 &ccapi_data->NamedCache);
1216 if (err != CC_NOERROR) {
1217 ccapi_data->NamedCache = NULL;
1218 if (err != CC_NO_EXIST) {
1219 retval = cc_err_xlate(err);
1220 goto errout;
1221 }
1222 }
1223
1224 /* return new cache structure */
1225 *id = newCache;
1226
1227 return 0;
1228
1229 errout:
1230 if (newCache)
1231 free(newCache);
1232 if (ccapi_data)
1233 free(ccapi_data);
1234 if (cName)
1235 free(cName);
1236 return retval;
1237 }
1238
1239 /*
1240 * initialize
1241 *
1242 * initialize the cache, check to see if one already exists for this
1243 * principal if not set our principal to this principal. This
1244 * searching enables ticket sharing
1245 */
krb5_stdcc_initialize(krb5_context context,krb5_ccache id,krb5_principal princ)1246 krb5_error_code KRB5_CALLCONV krb5_stdcc_initialize
1247 (krb5_context context, krb5_ccache id, krb5_principal princ)
1248 {
1249 stdccCacheDataPtr ccapi_data = NULL;
1250 int err;
1251 char *cName = NULL;
1252 krb5_error_code retval;
1253
1254 if ((retval = stdcc_setup(context, NULL)))
1255 return retval;
1256
1257 /* test id for null */
1258 if (id == NULL) return KRB5_CC_NOMEM;
1259
1260 if ((retval = krb5_unparse_name(context, princ, &cName)))
1261 return retval;
1262
1263 ccapi_data = id->data;
1264
1265
1266 if (ccapi_data->NamedCache)
1267 cc_close(gCntrlBlock, &ccapi_data->NamedCache);
1268
1269 err = cc_create(gCntrlBlock, ccapi_data->cache_name, cName,
1270 CC_CRED_V5, 0L, &ccapi_data->NamedCache);
1271 if (err != CC_NOERROR) {
1272 krb5_free_unparsed_name(context, cName);
1273 return cc_err_xlate(err);
1274 }
1275
1276 krb5_free_unparsed_name(context, cName);
1277 cache_changed();
1278
1279 return cc_err_xlate(err);
1280 }
1281
1282 /*
1283 * store
1284 *
1285 * store some credentials in our cache
1286 */
krb5_stdcc_store(krb5_context context,krb5_ccache id,krb5_creds * creds)1287 krb5_error_code KRB5_CALLCONV krb5_stdcc_store
1288 (krb5_context context, krb5_ccache id, krb5_creds *creds )
1289 {
1290 krb5_error_code retval;
1291 stdccCacheDataPtr ccapi_data = id->data;
1292 cred_union *cu = NULL;
1293 int err;
1294
1295 if ((retval = stdcc_setup(context, ccapi_data)))
1296 return retval;
1297
1298 /* copy the fields from the almost identical structures */
1299 dupK5toCC(context, creds, &cu);
1300
1301 /*
1302 * finally store the credential
1303 * store will copy (that is duplicate) everything
1304 */
1305 err = cc_store(gCntrlBlock,
1306 ((stdccCacheDataPtr)(id->data))->NamedCache, *cu);
1307 if (err != CC_NOERROR)
1308 return cc_err_xlate(err);
1309
1310 /* free the cred union using our local version of cc_free_creds()
1311 since we allocated it locally */
1312 err = krb5int_free_cc_cred_union(&cu);
1313
1314 cache_changed();
1315 return err;
1316 }
1317
1318 /*
1319 * start_seq_get
1320 *
1321 * begin an iterator call to get all of the credentials in the cache
1322 */
krb5_stdcc_start_seq_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)1323 krb5_error_code KRB5_CALLCONV krb5_stdcc_start_seq_get
1324 (krb5_context context, krb5_ccache id , krb5_cc_cursor *cursor )
1325 {
1326 stdccCacheDataPtr ccapi_data = id->data;
1327 krb5_error_code retval;
1328 int err;
1329 ccache_cit *iterator;
1330
1331 if ((retval = stdcc_setup(context, ccapi_data)))
1332 return retval;
1333
1334 #ifdef CC_API_VER2
1335 err = cc_seq_fetch_creds_begin(gCntrlBlock, ccapi_data->NamedCache,
1336 &iterator);
1337 if (err != CC_NOERROR)
1338 return cc_err_xlate(err);
1339 *cursor = iterator;
1340 #else
1341 /* all we have to do is initialize the cursor */
1342 *cursor = NULL;
1343 #endif
1344 return 0;
1345 }
1346
1347 /*
1348 * next cred
1349 *
1350 * - get the next credential in the cache as part of an iterator call
1351 * - this maps to call to cc_seq_fetch_creds
1352 */
krb5_stdcc_next_cred(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)1353 krb5_error_code KRB5_CALLCONV krb5_stdcc_next_cred
1354 (krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
1355 krb5_creds *creds)
1356 {
1357 krb5_error_code retval;
1358 stdccCacheDataPtr ccapi_data = id->data;
1359 int err;
1360 cred_union *credU = NULL;
1361 ccache_cit *iterator;
1362
1363 if ((retval = stdcc_setup(context, ccapi_data)))
1364 return retval;
1365
1366 #ifdef CC_API_VER2
1367 iterator = *cursor;
1368 if (iterator == 0)
1369 return KRB5_CC_END;
1370 err = cc_seq_fetch_creds_next(gCntrlBlock, &credU, iterator);
1371
1372 if (err == CC_END) {
1373 cc_seq_fetch_creds_end(gCntrlBlock, &iterator);
1374 *cursor = 0;
1375 }
1376 #else
1377 err = cc_seq_fetch_creds(gCntrlBlock, ccapi_data->NamedCache,
1378 &credU, (ccache_cit **)cursor);
1379 #endif
1380
1381 if (err != CC_NOERROR)
1382 return cc_err_xlate(err);
1383
1384 /* copy data (with translation) */
1385 dupCCtoK5(context, credU->cred.pV5Cred, creds);
1386
1387 /* free our version of the cred - okay to use cc_free_creds() here
1388 because we got it from the CCache library */
1389 cc_free_creds(gCntrlBlock, &credU);
1390
1391 return 0;
1392 }
1393
1394
1395 /*
1396 * retrieve
1397 *
1398 * - try to find a matching credential in the cache
1399 */
1400 krb5_error_code KRB5_CALLCONV
krb5_stdcc_retrieve(context,id,whichfields,mcreds,creds)1401 krb5_stdcc_retrieve(context, id, whichfields, mcreds, creds)
1402 krb5_context context;
1403 krb5_ccache id;
1404 krb5_flags whichfields;
1405 krb5_creds *mcreds;
1406 krb5_creds *creds;
1407 {
1408 return k5_cc_retrieve_cred_default(context, id, whichfields, mcreds,
1409 creds);
1410 }
1411
1412 /*
1413 * end seq
1414 *
1415 * just free up the storage associated with the cursor (if we could)
1416 */
krb5_stdcc_end_seq_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)1417 krb5_error_code KRB5_CALLCONV krb5_stdcc_end_seq_get
1418 (krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
1419 {
1420 krb5_error_code retval;
1421 stdccCacheDataPtr ccapi_data = NULL;
1422 int err;
1423 #ifndef CC_API_VER2
1424 cred_union *credU = NULL;
1425 #endif
1426
1427 ccapi_data = id->data;
1428
1429 if ((retval = stdcc_setup(context, ccapi_data)))
1430 return retval;
1431
1432 if (*cursor == NULL)
1433 return 0;
1434
1435 #ifdef CC_API_VER2
1436 err = cc_seq_fetch_creds_end(gCntrlBlock, (ccache_cit **)cursor);
1437 if (err != CC_NOERROR)
1438 return cc_err_xlate(err);
1439 #else
1440 /*
1441 * Finish calling cc_seq_fetch_creds to clear out the cursor
1442 */
1443 while (*cursor) {
1444 err = cc_seq_fetch_creds(gCntrlBlock, ccapi_data->NamedCache,
1445 &credU, (ccache_cit **)cursor);
1446 if (err)
1447 break;
1448
1449 /* okay to call cc_free_creds() here because we got credU from CCache lib */
1450 cc_free_creds(gCntrlBlock, &credU);
1451 }
1452 #endif
1453
1454 return(0);
1455 }
1456
1457 /*
1458 * close
1459 *
1460 * - free our pointers to the NC
1461 */
1462 krb5_error_code KRB5_CALLCONV
krb5_stdcc_close(krb5_context context,krb5_ccache id)1463 krb5_stdcc_close(krb5_context context, krb5_ccache id)
1464 {
1465 krb5_error_code retval;
1466 stdccCacheDataPtr ccapi_data = id->data;
1467
1468 if ((retval = stdcc_setup(context, NULL)))
1469 return retval;
1470
1471 /* free it */
1472
1473 if (ccapi_data) {
1474 if (ccapi_data->cache_name)
1475 free(ccapi_data->cache_name);
1476 if (ccapi_data->NamedCache)
1477 cc_close(gCntrlBlock, &ccapi_data->NamedCache);
1478 free(ccapi_data);
1479 id->data = NULL;
1480 }
1481 free(id);
1482
1483 return 0;
1484 }
1485
1486 /*
1487 * destroy
1488 *
1489 * - free our storage and the cache
1490 */
1491 krb5_error_code KRB5_CALLCONV
krb5_stdcc_destroy(krb5_context context,krb5_ccache id)1492 krb5_stdcc_destroy (krb5_context context, krb5_ccache id)
1493 {
1494 int err;
1495 krb5_error_code retval;
1496 stdccCacheDataPtr ccapi_data = id->data;
1497
1498 if ((retval = stdcc_setup(context, ccapi_data))) {
1499 return retval;
1500 }
1501
1502 /* free memory associated with the krb5_ccache */
1503 if (ccapi_data) {
1504 if (ccapi_data->cache_name)
1505 free(ccapi_data->cache_name);
1506 if (ccapi_data->NamedCache) {
1507 /* destroy the named cache */
1508 err = cc_destroy(gCntrlBlock, &ccapi_data->NamedCache);
1509 retval = cc_err_xlate(err);
1510 cache_changed();
1511 }
1512 free(ccapi_data);
1513 id->data = NULL;
1514 }
1515 free(id);
1516
1517 /* If the cache does not exist when we tried to destroy it,
1518 that's fine. That means someone else destroyed it since
1519 we resolved it. */
1520 if (retval == KRB5_FCC_NOFILE)
1521 return 0;
1522 return retval;
1523 }
1524
1525 /*
1526 * getname
1527 *
1528 * - return the name of the named cache
1529 */
krb5_stdcc_get_name(krb5_context context,krb5_ccache id)1530 const char * KRB5_CALLCONV krb5_stdcc_get_name
1531 (krb5_context context, krb5_ccache id )
1532 {
1533 stdccCacheDataPtr ccapi_data = id->data;
1534
1535 if (!ccapi_data)
1536 return 0;
1537
1538 return (ccapi_data->cache_name);
1539 }
1540
1541
1542 /* get_principal
1543 *
1544 * - return the principal associated with the named cache
1545 */
krb5_stdcc_get_principal(krb5_context context,krb5_ccache id,krb5_principal * princ)1546 krb5_error_code KRB5_CALLCONV krb5_stdcc_get_principal
1547 (krb5_context context, krb5_ccache id , krb5_principal *princ)
1548 {
1549 int err;
1550 char *name = NULL;
1551 stdccCacheDataPtr ccapi_data = id->data;
1552 krb5_error_code retval;
1553
1554 if ((retval = stdcc_setup(context, ccapi_data)))
1555 return retval;
1556
1557 /* another wrapper */
1558 err = cc_get_principal(gCntrlBlock, ccapi_data->NamedCache,
1559 &name);
1560
1561 if (err != CC_NOERROR)
1562 return cc_err_xlate(err);
1563
1564 /* turn it into a krb principal */
1565 err = krb5_parse_name(context, name, princ);
1566
1567 cc_free_principal(gCntrlBlock, &name);
1568
1569 return err;
1570 }
1571
1572 /*
1573 * set_flags
1574 *
1575 * - currently a NOP since we don't store any flags in the NC
1576 */
krb5_stdcc_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)1577 krb5_error_code KRB5_CALLCONV krb5_stdcc_set_flags
1578 (krb5_context context, krb5_ccache id , krb5_flags flags)
1579 {
1580 stdccCacheDataPtr ccapi_data = id->data;
1581 krb5_error_code retval;
1582
1583 if ((retval = stdcc_setup(context, ccapi_data)))
1584 return retval;
1585
1586 return 0;
1587 }
1588
1589 /*
1590 * get_flags
1591 *
1592 * - currently a NOP since we don't store any flags in the NC
1593 */
krb5_stdcc_get_flags(krb5_context context,krb5_ccache id,krb5_flags * flags)1594 krb5_error_code KRB5_CALLCONV krb5_stdcc_get_flags
1595 (krb5_context context, krb5_ccache id , krb5_flags *flags)
1596 {
1597 stdccCacheDataPtr ccapi_data = id->data;
1598 krb5_error_code retval;
1599
1600 if ((retval = stdcc_setup(context, ccapi_data)))
1601 return retval;
1602
1603 return 0;
1604 }
1605
1606 /*
1607 * remove
1608 *
1609 * - remove the specified credentials from the NC
1610 */
krb5_stdcc_remove(krb5_context context,krb5_ccache id,krb5_flags flags,krb5_creds * creds)1611 krb5_error_code KRB5_CALLCONV krb5_stdcc_remove
1612 (krb5_context context, krb5_ccache id,
1613 krb5_flags flags, krb5_creds *creds)
1614 {
1615 cred_union *cu = NULL;
1616 int err;
1617 stdccCacheDataPtr ccapi_data = id->data;
1618 krb5_error_code retval;
1619
1620 if ((retval = stdcc_setup(context, ccapi_data))) {
1621 if (retval == KRB5_FCC_NOFILE)
1622 return 0;
1623 return retval;
1624 }
1625
1626 /* convert to a cred union */
1627 dupK5toCC(context, creds, &cu);
1628
1629 /* remove it */
1630 err = cc_remove_cred(gCntrlBlock, ccapi_data->NamedCache, *cu);
1631 if (err != CC_NOERROR)
1632 return cc_err_xlate(err);
1633
1634 /* free the cred union using our local version of cc_free_creds()
1635 since we allocated it locally */
1636 err = krb5int_free_cc_cred_union(&cu);
1637 cache_changed();
1638 if (err != CC_NOERROR)
1639 return cc_err_xlate(err);
1640
1641 return 0;
1642 }
1643 #endif /* !USE_CCAPI_V3 */
1644
1645 #endif /* defined(_WIN32) || defined(USE_CCAPI) */
1646