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