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 "../ccapi_util.h"
37 #include "stdcc.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 cc_context_t gCntrlBlock = NULL;
61 cc_int32 gCCVersion = 0;
62
63 /*
64 * declare our global object wanna-be
65 * must be installed in ccdefops.c
66 */
67
68 krb5_cc_ops krb5_cc_stdcc_ops = {
69 0,
70 "API",
71 krb5_stdccv3_get_name,
72 krb5_stdccv3_resolve,
73 krb5_stdccv3_generate_new,
74 krb5_stdccv3_initialize,
75 krb5_stdccv3_destroy,
76 krb5_stdccv3_close,
77 krb5_stdccv3_store,
78 krb5_stdccv3_retrieve,
79 krb5_stdccv3_get_principal,
80 krb5_stdccv3_start_seq_get,
81 krb5_stdccv3_next_cred,
82 krb5_stdccv3_end_seq_get,
83 krb5_stdccv3_remove,
84 krb5_stdccv3_set_flags,
85 krb5_stdccv3_get_flags,
86 krb5_stdccv3_ptcursor_new,
87 krb5_stdccv3_ptcursor_next,
88 krb5_stdccv3_ptcursor_free,
89 NULL, /* move */
90 NULL, /* wasdefault */
91 krb5_stdccv3_lock,
92 krb5_stdccv3_unlock,
93 krb5_stdccv3_switch_to,
94 };
95
96 #if defined(_WIN32)
97 /*
98 * cache_changed be called after the cache changes.
99 * A notification message is is posted out to all top level
100 * windows so that they may recheck the cache based on the
101 * changes made. We register a unique message type with which
102 * we'll communicate to all other processes.
103 */
cache_changed(void)104 static void cache_changed(void)
105 {
106 static unsigned int message = 0;
107
108 if (message == 0)
109 message = RegisterWindowMessage(WM_KERBEROS5_CHANGED);
110
111 PostMessage(HWND_BROADCAST, message, 0, 0);
112 }
113 #else /* _WIN32 */
114
cache_changed(void)115 static void cache_changed(void)
116 {
117 return;
118 }
119 #endif /* _WIN32 */
120
121 struct err_xlate
122 {
123 int cc_err;
124 krb5_error_code krb5_err;
125 };
126
127 static const struct err_xlate err_xlate_table[] =
128 {
129 { ccIteratorEnd, KRB5_CC_END },
130 { ccErrBadParam, KRB5_FCC_INTERNAL },
131 { ccErrNoMem, KRB5_CC_NOMEM },
132 { ccErrInvalidContext, KRB5_FCC_NOFILE },
133 { ccErrInvalidCCache, KRB5_FCC_NOFILE },
134 { ccErrInvalidString, KRB5_FCC_INTERNAL },
135 { ccErrInvalidCredentials, KRB5_FCC_INTERNAL },
136 { ccErrInvalidCCacheIterator, KRB5_FCC_INTERNAL },
137 { ccErrInvalidCredentialsIterator, KRB5_FCC_INTERNAL },
138 { ccErrInvalidLock, KRB5_FCC_INTERNAL },
139 { ccErrBadName, KRB5_CC_BADNAME },
140 { ccErrBadCredentialsVersion, KRB5_FCC_INTERNAL },
141 { ccErrBadAPIVersion, KRB5_FCC_INTERNAL },
142 { ccErrContextLocked, KRB5_FCC_INTERNAL },
143 { ccErrContextUnlocked, KRB5_FCC_INTERNAL },
144 { ccErrCCacheLocked, KRB5_FCC_INTERNAL },
145 { ccErrCCacheUnlocked, KRB5_FCC_INTERNAL },
146 { ccErrBadLockType, KRB5_FCC_INTERNAL },
147 { ccErrNeverDefault, KRB5_FCC_INTERNAL },
148 { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND },
149 { ccErrCCacheNotFound, KRB5_FCC_NOFILE },
150 { ccErrContextNotFound, KRB5_FCC_NOFILE },
151 { ccErrServerUnavailable, KRB5_CC_IO },
152 { ccErrServerInsecure, KRB5_CC_IO },
153 { ccErrServerCantBecomeUID, KRB5_CC_IO },
154 { ccErrTimeOffsetNotSet, KRB5_FCC_INTERNAL },
155 { ccErrBadInternalMessage, KRB5_FCC_INTERNAL },
156 { ccErrNotImplemented, KRB5_FCC_INTERNAL },
157 { 0, 0 }
158 };
159
160 /* Note: cc_err_xlate is NOT idempotent. Don't call it multiple times. */
cc_err_xlate(int err)161 static krb5_error_code cc_err_xlate(int err)
162 {
163 const struct err_xlate *p;
164
165 if (err == ccNoError)
166 return 0;
167
168 for (p = err_xlate_table; p->cc_err; p++) {
169 if (err == p->cc_err)
170 return p->krb5_err;
171 }
172
173 return KRB5_FCC_INTERNAL;
174 }
175
176
stdccv3_get_timeoffset(krb5_context in_context,cc_ccache_t in_ccache)177 static krb5_error_code stdccv3_get_timeoffset (krb5_context in_context,
178 cc_ccache_t in_ccache)
179 {
180 krb5_error_code err = 0;
181
182 if (gCCVersion >= ccapi_version_5) {
183 krb5_os_context os_ctx = (krb5_os_context) &in_context->os_context;
184 cc_time_t time_offset = 0;
185
186 err = cc_ccache_get_kdc_time_offset (in_ccache, cc_credentials_v5,
187 &time_offset);
188
189 if (!err) {
190 os_ctx->time_offset = time_offset;
191 os_ctx->usec_offset = 0;
192 os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
193 KRB5_OS_TOFFSET_VALID);
194 }
195
196 if (err == ccErrTimeOffsetNotSet) {
197 err = 0; /* okay if there is no time offset */
198 }
199 }
200
201 return err; /* Don't translate. Callers will translate for us */
202 }
203
stdccv3_set_timeoffset(krb5_context in_context,cc_ccache_t in_ccache)204 static krb5_error_code stdccv3_set_timeoffset (krb5_context in_context,
205 cc_ccache_t in_ccache)
206 {
207 krb5_error_code err = 0;
208
209 if (gCCVersion >= ccapi_version_5) {
210 krb5_os_context os_ctx = (krb5_os_context) &in_context->os_context;
211
212 if (!err && os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
213 err = cc_ccache_set_kdc_time_offset (in_ccache,
214 cc_credentials_v5,
215 os_ctx->time_offset);
216 }
217 }
218
219 return err; /* Don't translate. Callers will translate for us */
220 }
221
stdccv3_setup(krb5_context context,stdccCacheDataPtr ccapi_data)222 static krb5_error_code stdccv3_setup (krb5_context context,
223 stdccCacheDataPtr ccapi_data)
224 {
225 krb5_error_code err = 0;
226
227 if (!err && !gCntrlBlock) {
228 err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
229 }
230
231 if (!err && ccapi_data && !ccapi_data->NamedCache) {
232 /* ccache has not been opened yet. open it. */
233 err = cc_context_open_ccache (gCntrlBlock, ccapi_data->cache_name,
234 &ccapi_data->NamedCache);
235 }
236
237 if (!err && ccapi_data && ccapi_data->NamedCache) {
238 err = stdccv3_get_timeoffset (context, ccapi_data->NamedCache);
239 }
240
241 return err; /* Don't translate. Callers will translate for us */
242 }
243
244 /* krb5_stdcc_shutdown is exported; use the old name */
krb5_stdcc_shutdown(void)245 void krb5_stdcc_shutdown(void)
246 {
247 if (gCntrlBlock) { cc_context_release(gCntrlBlock); }
248 gCntrlBlock = NULL;
249 gCCVersion = 0;
250 }
251
252 /*
253 * -- generate_new --------------------------------
254 *
255 * create a new cache with a unique name, corresponds to creating a
256 * named cache initialize the API here if we have to.
257 */
258 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_generate_new(krb5_context context,krb5_ccache * id)259 krb5_stdccv3_generate_new (krb5_context context, krb5_ccache *id )
260 {
261 krb5_error_code err = 0;
262 krb5_ccache newCache = NULL;
263 stdccCacheDataPtr ccapi_data = NULL;
264 cc_ccache_t ccache = NULL;
265 cc_string_t ccstring = NULL;
266 char *name = NULL;
267
268 if (!err) {
269 err = stdccv3_setup(context, NULL);
270 }
271
272 if (!err) {
273 newCache = (krb5_ccache) malloc (sizeof (*newCache));
274 if (!newCache) { err = KRB5_CC_NOMEM; }
275 }
276
277 if (!err) {
278 ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
279 if (!ccapi_data) { err = KRB5_CC_NOMEM; }
280 }
281
282 if (!err) {
283 err = cc_context_create_new_ccache (gCntrlBlock, cc_credentials_v5, "",
284 &ccache);
285 }
286
287 if (!err) {
288 err = stdccv3_set_timeoffset (context, ccache);
289 }
290
291 if (!err) {
292 err = cc_ccache_get_name (ccache, &ccstring);
293 }
294
295 if (!err) {
296 name = strdup (ccstring->data);
297 if (!name) { err = KRB5_CC_NOMEM; }
298 }
299
300 if (!err) {
301 ccapi_data->cache_name = name;
302 name = NULL; /* take ownership */
303
304 ccapi_data->NamedCache = ccache;
305 ccache = NULL; /* take ownership */
306
307 newCache->ops = &krb5_cc_stdcc_ops;
308 newCache->data = ccapi_data;
309 ccapi_data = NULL; /* take ownership */
310
311 /* return a pointer to the new cache */
312 *id = newCache;
313 newCache = NULL;
314 }
315
316 if (ccstring) { cc_string_release (ccstring); }
317 if (name) { free (name); }
318 if (ccache) { cc_ccache_release (ccache); }
319 if (ccapi_data) { free (ccapi_data); }
320 if (newCache) { free (newCache); }
321
322 return cc_err_xlate (err);
323 }
324
325 /*
326 * resolve
327 *
328 * create a new cache with the name stored in residual
329 */
330 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_resolve(krb5_context context,krb5_ccache * id,const char * residual)331 krb5_stdccv3_resolve (krb5_context context, krb5_ccache *id , const char *residual )
332 {
333 krb5_error_code err = 0;
334 stdccCacheDataPtr ccapi_data = NULL;
335 krb5_ccache ccache = NULL;
336 char *name = NULL;
337 cc_string_t defname = NULL;
338
339 if (id == NULL) { err = KRB5_CC_NOMEM; }
340
341 if (!err) {
342 err = stdccv3_setup (context, NULL);
343 }
344
345 if (!err) {
346 ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
347 if (!ccapi_data) { err = KRB5_CC_NOMEM; }
348 }
349
350 if (!err) {
351 ccache = (krb5_ccache ) malloc (sizeof (*ccache));
352 if (!ccache) { err = KRB5_CC_NOMEM; }
353 }
354
355 if (!err) {
356 if ((residual == NULL) || (strlen(residual) == 0)) {
357 err = cc_context_get_default_ccache_name(gCntrlBlock, &defname);
358 if (defname)
359 residual = defname->data;
360 }
361 }
362
363 if (!err) {
364 name = strdup (residual);
365 if (!name) { err = KRB5_CC_NOMEM; }
366 }
367
368 if (!err) {
369 err = cc_context_open_ccache (gCntrlBlock, residual,
370 &ccapi_data->NamedCache);
371 if (err == ccErrCCacheNotFound) {
372 ccapi_data->NamedCache = NULL;
373 err = 0; /* ccache just doesn't exist yet */
374 }
375 }
376
377 if (!err) {
378 ccapi_data->cache_name = name;
379 name = NULL; /* take ownership */
380
381 ccache->ops = &krb5_cc_stdcc_ops;
382 ccache->data = ccapi_data;
383 ccapi_data = NULL; /* take ownership */
384
385 *id = ccache;
386 ccache = NULL; /* take ownership */
387 }
388
389 if (ccache) { free (ccache); }
390 if (ccapi_data) { free (ccapi_data); }
391 if (name) { free (name); }
392 if (defname) { cc_string_release(defname); }
393
394 return cc_err_xlate (err);
395 }
396
397 /*
398 * initialize
399 *
400 * initialize the cache, check to see if one already exists for this
401 * principal if not set our principal to this principal. This
402 * searching enables ticket sharing
403 */
404 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_initialize(krb5_context context,krb5_ccache id,krb5_principal princ)405 krb5_stdccv3_initialize (krb5_context context,
406 krb5_ccache id,
407 krb5_principal princ)
408 {
409 krb5_error_code err = 0;
410 stdccCacheDataPtr ccapi_data = id->data;
411 char *name = NULL;
412 cc_ccache_t ccache = NULL;
413
414 if (id == NULL) { err = KRB5_CC_NOMEM; }
415
416 if (!err) {
417 err = stdccv3_setup (context, NULL);
418 }
419
420 if (!err) {
421 err = krb5_unparse_name(context, princ, &name);
422 }
423
424 if (!err) {
425 err = cc_context_create_ccache (gCntrlBlock, ccapi_data->cache_name,
426 cc_credentials_v5, name,
427 &ccache);
428 }
429
430 if (!err) {
431 err = stdccv3_set_timeoffset (context, ccache);
432 }
433
434 if (!err) {
435 if (ccapi_data->NamedCache) {
436 err = cc_ccache_release (ccapi_data->NamedCache);
437 }
438 ccapi_data->NamedCache = ccache;
439 ccache = NULL; /* take ownership */
440 cache_changed ();
441 }
442
443 if (ccache) { cc_ccache_release (ccache); }
444 if (name ) { krb5_free_unparsed_name(context, name); }
445
446 return cc_err_xlate(err);
447 }
448
449 /*
450 * store
451 *
452 * store some credentials in our cache
453 */
454 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_store(krb5_context context,krb5_ccache id,krb5_creds * creds)455 krb5_stdccv3_store (krb5_context context, krb5_ccache id, krb5_creds *creds )
456 {
457 krb5_error_code err = 0;
458 stdccCacheDataPtr ccapi_data = id->data;
459 cc_credentials_union *cred_union = NULL;
460
461 if (!err) {
462 err = stdccv3_setup (context, ccapi_data);
463 }
464
465 if (!err) {
466 /* copy the fields from the almost identical structures */
467 err = k5_krb5_to_ccapi_creds (context, creds, &cred_union);
468 }
469
470 if (!err) {
471 err = cc_ccache_store_credentials (ccapi_data->NamedCache, cred_union);
472 }
473
474 if (!err) {
475 cache_changed();
476 }
477
478 if (cred_union) { k5_release_ccapi_cred (cred_union); }
479
480 return cc_err_xlate (err);
481 }
482
483 /*
484 * start_seq_get
485 *
486 * begin an iterator call to get all of the credentials in the cache
487 */
488 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_start_seq_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)489 krb5_stdccv3_start_seq_get (krb5_context context,
490 krb5_ccache id,
491 krb5_cc_cursor *cursor )
492 {
493 krb5_error_code err = 0;
494 stdccCacheDataPtr ccapi_data = id->data;
495 cc_credentials_iterator_t iterator = NULL;
496
497 if (!err) {
498 err = stdccv3_setup (context, ccapi_data);
499 }
500
501 if (!err) {
502 err = cc_ccache_new_credentials_iterator(ccapi_data->NamedCache,
503 &iterator);
504 }
505
506 if (!err) {
507 *cursor = iterator;
508 }
509
510 return cc_err_xlate (err);
511 }
512
513 /*
514 * next cred
515 *
516 * - get the next credential in the cache as part of an iterator call
517 * - this maps to call to cc_seq_fetch_creds
518 */
519 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_next_cred(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)520 krb5_stdccv3_next_cred (krb5_context context,
521 krb5_ccache id,
522 krb5_cc_cursor *cursor,
523 krb5_creds *creds)
524 {
525 krb5_error_code err = 0;
526 stdccCacheDataPtr ccapi_data = id->data;
527 cc_credentials_t credentials = NULL;
528 cc_credentials_iterator_t iterator = *cursor;
529
530 if (!iterator) { err = KRB5_CC_END; }
531
532 if (!err) {
533 err = stdccv3_setup (context, ccapi_data);
534 }
535
536 while (!err) {
537 err = cc_credentials_iterator_next (iterator, &credentials);
538
539 if (!err && (credentials->data->version == cc_credentials_v5)) {
540 err = k5_ccapi_to_krb5_creds (context, credentials->data, creds);
541 break;
542 }
543 }
544
545 if (credentials) { cc_credentials_release (credentials); }
546 if (err == ccIteratorEnd) {
547 cc_credentials_iterator_release (iterator);
548 *cursor = 0;
549 }
550
551 return cc_err_xlate (err);
552 }
553
554
555 /*
556 * retrieve
557 *
558 * - try to find a matching credential in the cache
559 */
560 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_retrieve(krb5_context context,krb5_ccache id,krb5_flags whichfields,krb5_creds * mcreds,krb5_creds * creds)561 krb5_stdccv3_retrieve (krb5_context context,
562 krb5_ccache id,
563 krb5_flags whichfields,
564 krb5_creds *mcreds,
565 krb5_creds *creds)
566 {
567 return k5_cc_retrieve_cred_default(context, id, whichfields, mcreds,
568 creds);
569 }
570
571 /*
572 * end seq
573 *
574 * just free up the storage associated with the cursor (if we can)
575 */
576 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_end_seq_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)577 krb5_stdccv3_end_seq_get (krb5_context context,
578 krb5_ccache id,
579 krb5_cc_cursor *cursor)
580 {
581 krb5_error_code err = 0;
582 stdccCacheDataPtr ccapi_data = id->data;
583 cc_credentials_iterator_t iterator = *cursor;
584
585 if (!iterator) { return 0; }
586
587 if (!err) {
588 err = stdccv3_setup (context, ccapi_data);
589 }
590
591 if (!err) {
592 err = cc_credentials_iterator_release(iterator);
593 }
594
595 return cc_err_xlate(err);
596 }
597
598 /*
599 * close
600 *
601 * - free our pointers to the NC
602 */
603 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_close(krb5_context context,krb5_ccache id)604 krb5_stdccv3_close(krb5_context context,
605 krb5_ccache id)
606 {
607 krb5_error_code err = 0;
608 stdccCacheDataPtr ccapi_data = id->data;
609
610 if (!err) {
611 err = stdccv3_setup (context, NULL);
612 }
613
614 if (!err) {
615 if (ccapi_data) {
616 if (ccapi_data->cache_name) {
617 free (ccapi_data->cache_name);
618 }
619 if (ccapi_data->NamedCache) {
620 err = cc_ccache_release (ccapi_data->NamedCache);
621 }
622 free (ccapi_data);
623 id->data = NULL;
624 }
625 free (id);
626 }
627
628 return cc_err_xlate(err);
629 }
630
631 /*
632 * destroy
633 *
634 * - free our storage and the cache
635 */
636 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_destroy(krb5_context context,krb5_ccache id)637 krb5_stdccv3_destroy (krb5_context context,
638 krb5_ccache id)
639 {
640 krb5_error_code err = 0;
641 stdccCacheDataPtr ccapi_data = id->data;
642
643 if (!err) {
644 err = stdccv3_setup(context, ccapi_data);
645 }
646
647 if (!err) {
648 if (ccapi_data) {
649 if (ccapi_data->cache_name) {
650 free(ccapi_data->cache_name);
651 }
652 if (ccapi_data->NamedCache) {
653 /* destroy the named cache */
654 err = cc_ccache_destroy(ccapi_data->NamedCache);
655 if (err == ccErrCCacheNotFound) {
656 err = 0; /* ccache maybe already destroyed */
657 }
658 cache_changed();
659 }
660 free(ccapi_data);
661 id->data = NULL;
662 }
663 free(id);
664 }
665
666 return cc_err_xlate(err);
667 }
668
669 /*
670 * getname
671 *
672 * - return the name of the named cache
673 */
674 const char * KRB5_CALLCONV
krb5_stdccv3_get_name(krb5_context context,krb5_ccache id)675 krb5_stdccv3_get_name (krb5_context context,
676 krb5_ccache id )
677 {
678 stdccCacheDataPtr ccapi_data = id->data;
679
680 if (!ccapi_data) {
681 return NULL;
682 } else {
683 return (ccapi_data->cache_name);
684 }
685 }
686
687
688 /* get_principal
689 *
690 * - return the principal associated with the named cache
691 */
692 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_get_principal(krb5_context context,krb5_ccache id,krb5_principal * princ)693 krb5_stdccv3_get_principal (krb5_context context,
694 krb5_ccache id ,
695 krb5_principal *princ)
696 {
697 krb5_error_code err = 0;
698 stdccCacheDataPtr ccapi_data = id->data;
699 cc_string_t name = NULL;
700
701 if (!err) {
702 err = stdccv3_setup(context, ccapi_data);
703 }
704
705 if (!err) {
706 err = cc_ccache_get_principal (ccapi_data->NamedCache, cc_credentials_v5, &name);
707 }
708
709 if (!err) {
710 err = krb5_parse_name (context, name->data, princ);
711 } else {
712 err = cc_err_xlate (err);
713 }
714
715 if (name) { cc_string_release (name); }
716
717 return err;
718 }
719
720 /*
721 * set_flags
722 *
723 * - currently a NOP since we don't store any flags in the NC
724 */
725 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)726 krb5_stdccv3_set_flags (krb5_context context,
727 krb5_ccache id,
728 krb5_flags flags)
729 {
730 krb5_error_code err = 0;
731 stdccCacheDataPtr ccapi_data = id->data;
732
733 err = stdccv3_setup (context, ccapi_data);
734
735 return cc_err_xlate (err);
736 }
737
738 /*
739 * get_flags
740 *
741 * - currently a NOP since we don't store any flags in the NC
742 */
743 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_get_flags(krb5_context context,krb5_ccache id,krb5_flags * flags)744 krb5_stdccv3_get_flags (krb5_context context,
745 krb5_ccache id,
746 krb5_flags *flags)
747 {
748 krb5_error_code err = 0;
749 stdccCacheDataPtr ccapi_data = id->data;
750
751 err = stdccv3_setup (context, ccapi_data);
752
753 return cc_err_xlate (err);
754 }
755
756 /*
757 * remove
758 *
759 * - remove the specified credentials from the NC
760 */
761 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_remove(krb5_context context,krb5_ccache id,krb5_flags whichfields,krb5_creds * in_creds)762 krb5_stdccv3_remove (krb5_context context,
763 krb5_ccache id,
764 krb5_flags whichfields,
765 krb5_creds *in_creds)
766 {
767 krb5_error_code err = 0;
768 stdccCacheDataPtr ccapi_data = id->data;
769 cc_credentials_iterator_t iterator = NULL;
770 int found = 0;
771
772 if (!err) {
773 err = stdccv3_setup(context, ccapi_data);
774 }
775
776
777 if (!err) {
778 err = cc_ccache_new_credentials_iterator(ccapi_data->NamedCache,
779 &iterator);
780 }
781
782 while (!err && !found) {
783 cc_credentials_t credentials = NULL;
784
785 err = cc_credentials_iterator_next (iterator, &credentials);
786
787 if (!err && (credentials->data->version == cc_credentials_v5)) {
788 krb5_creds creds;
789
790 err = k5_ccapi_to_krb5_creds (context, credentials->data, &creds);
791
792 if (!err) {
793 found = krb5int_cc_creds_match_request(context,
794 whichfields,
795 in_creds,
796 &creds);
797 krb5_free_cred_contents (context, &creds);
798 }
799
800 if (!err && found) {
801 err = cc_ccache_remove_credentials (ccapi_data->NamedCache, credentials);
802 }
803 }
804
805 if (credentials) { cc_credentials_release (credentials); }
806 }
807 if (err == ccIteratorEnd) { err = ccErrCredentialsNotFound; }
808
809 if (iterator) {
810 err = cc_credentials_iterator_release(iterator);
811 }
812
813 if (!err) {
814 cache_changed ();
815 }
816
817 return cc_err_xlate (err);
818 }
819
820 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_new(krb5_context context,krb5_cc_ptcursor * cursor)821 krb5_stdccv3_ptcursor_new(krb5_context context,
822 krb5_cc_ptcursor *cursor)
823 {
824 krb5_error_code err = 0;
825 krb5_cc_ptcursor ptcursor = NULL;
826 cc_ccache_iterator_t iterator = NULL;
827
828 ptcursor = malloc(sizeof(*ptcursor));
829 if (ptcursor == NULL) {
830 err = ccErrNoMem;
831 }
832 else {
833 memset(ptcursor, 0, sizeof(*ptcursor));
834 }
835
836 if (!err) {
837 err = stdccv3_setup(context, NULL);
838 }
839 if (!err) {
840 ptcursor->ops = &krb5_cc_stdcc_ops;
841 err = cc_context_new_ccache_iterator(gCntrlBlock, &iterator);
842 }
843
844 if (!err) {
845 ptcursor->data = iterator;
846 }
847
848 if (err) {
849 if (ptcursor) { krb5_stdccv3_ptcursor_free(context, &ptcursor); }
850 // krb5_stdccv3_ptcursor_free sets ptcursor to NULL for us
851 }
852
853 *cursor = ptcursor;
854
855 return cc_err_xlate(err);
856 }
857
858 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_next(krb5_context context,krb5_cc_ptcursor cursor,krb5_ccache * ccache)859 krb5_stdccv3_ptcursor_next(
860 krb5_context context,
861 krb5_cc_ptcursor cursor,
862 krb5_ccache *ccache)
863 {
864 krb5_error_code err = 0;
865 cc_ccache_iterator_t iterator = NULL;
866
867 krb5_ccache newCache = NULL;
868 stdccCacheDataPtr ccapi_data = NULL;
869 cc_ccache_t ccCache = NULL;
870 cc_string_t ccstring = NULL;
871 char *name = NULL;
872
873 if (!cursor || !cursor->data) {
874 err = ccErrInvalidContext;
875 }
876
877 *ccache = NULL;
878
879 if (!err) {
880 newCache = (krb5_ccache) malloc (sizeof (*newCache));
881 if (!newCache) { err = ccErrNoMem; }
882 }
883
884 if (!err) {
885 ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
886 if (!ccapi_data) { err = ccErrNoMem; }
887 }
888
889 if (!err) {
890 iterator = cursor->data;
891 err = cc_ccache_iterator_next(iterator, &ccCache);
892 }
893
894 if (!err) {
895 err = cc_ccache_get_name (ccCache, &ccstring);
896 }
897
898 if (!err) {
899 name = strdup (ccstring->data);
900 if (!name) { err = ccErrNoMem; }
901 }
902
903 if (!err) {
904 ccapi_data->cache_name = name;
905 name = NULL; /* take ownership */
906
907 ccapi_data->NamedCache = ccCache;
908 ccCache = NULL; /* take ownership */
909
910 newCache->ops = &krb5_cc_stdcc_ops;
911 newCache->data = ccapi_data;
912 ccapi_data = NULL; /* take ownership */
913
914 /* return a pointer to the new cache */
915 *ccache = newCache;
916 newCache = NULL;
917 }
918
919 if (name) { free (name); }
920 if (ccstring) { cc_string_release (ccstring); }
921 if (ccCache) { cc_ccache_release (ccCache); }
922 if (ccapi_data) { free (ccapi_data); }
923 if (newCache) { free (newCache); }
924
925 if (err == ccIteratorEnd) {
926 err = ccNoError;
927 }
928
929 return cc_err_xlate(err);
930 }
931
932 krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_free(krb5_context context,krb5_cc_ptcursor * cursor)933 krb5_stdccv3_ptcursor_free(
934 krb5_context context,
935 krb5_cc_ptcursor *cursor)
936 {
937 if (*cursor != NULL) {
938 if ((*cursor)->data != NULL) {
939 cc_ccache_iterator_release((cc_ccache_iterator_t)((*cursor)->data));
940 }
941 free(*cursor);
942 *cursor = NULL;
943 }
944 return 0;
945 }
946
krb5_stdccv3_lock(krb5_context context,krb5_ccache id)947 krb5_error_code KRB5_CALLCONV krb5_stdccv3_lock
948 (krb5_context context, krb5_ccache id)
949 {
950 krb5_error_code err = 0;
951 stdccCacheDataPtr ccapi_data = id->data;
952
953 if (!err) {
954 err = stdccv3_setup(context, ccapi_data);
955 }
956 if (!err) {
957 err = cc_ccache_lock(ccapi_data->NamedCache, cc_lock_write, cc_lock_block);
958 }
959 return cc_err_xlate(err);
960 }
961
krb5_stdccv3_unlock(krb5_context context,krb5_ccache id)962 krb5_error_code KRB5_CALLCONV krb5_stdccv3_unlock
963 (krb5_context context, krb5_ccache id)
964 {
965 krb5_error_code err = 0;
966 stdccCacheDataPtr ccapi_data = id->data;
967
968 if (!err) {
969 err = stdccv3_setup(context, ccapi_data);
970 }
971 if (!err) {
972 err = cc_ccache_unlock(ccapi_data->NamedCache);
973 }
974 return cc_err_xlate(err);
975 }
976
krb5_stdccv3_context_lock(krb5_context context)977 krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_lock
978 (krb5_context context)
979 {
980 krb5_error_code err = 0;
981
982 if (!err && !gCntrlBlock) {
983 err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
984 }
985 if (!err) {
986 err = cc_context_lock(gCntrlBlock, cc_lock_write, cc_lock_block);
987 }
988 return cc_err_xlate(err);
989 }
990
krb5_stdccv3_context_unlock(krb5_context context)991 krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_unlock
992 (krb5_context context)
993 {
994 krb5_error_code err = 0;
995
996 if (!err && !gCntrlBlock) {
997 err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
998 }
999 if (!err) {
1000 err = cc_context_unlock(gCntrlBlock);
1001 }
1002 return cc_err_xlate(err);
1003 }
1004
krb5_stdccv3_switch_to(krb5_context context,krb5_ccache id)1005 krb5_error_code KRB5_CALLCONV krb5_stdccv3_switch_to
1006 (krb5_context context, krb5_ccache id)
1007 {
1008 krb5_error_code retval;
1009 stdccCacheDataPtr ccapi_data = id->data;
1010 int err;
1011
1012 retval = stdccv3_setup(context, ccapi_data);
1013 if (retval)
1014 return cc_err_xlate(retval);
1015
1016 err = cc_ccache_set_default(ccapi_data->NamedCache);
1017 return cc_err_xlate(err);
1018 }
1019
1020 #endif /* defined(_WIN32) || defined(USE_CCAPI) */
1021