xref: /freebsd/crypto/krb5/src/lib/krb5/ccache/ccapi/stdcc.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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