No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / krb5 / fcache.c
blob9509602da26dbc16510af58b0cfc5d964dd429fd
1 /*
2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
36 __RCSID("$Heimdal: fcache.c 22522 2008-01-24 11:56:25Z lha $"
37 "$NetBSD$");
39 typedef struct krb5_fcache{
40 char *filename;
41 int version;
42 }krb5_fcache;
44 struct fcc_cursor {
45 int fd;
46 krb5_storage *sp;
49 #define KRB5_FCC_FVNO_1 1
50 #define KRB5_FCC_FVNO_2 2
51 #define KRB5_FCC_FVNO_3 3
52 #define KRB5_FCC_FVNO_4 4
54 #define FCC_TAG_DELTATIME 1
56 #define FCACHE(X) ((krb5_fcache*)(X)->data.data)
58 #define FILENAME(X) (FCACHE(X)->filename)
60 #define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
62 static const char*
63 fcc_get_name(krb5_context context,
64 krb5_ccache id)
66 return FILENAME(id);
69 int
70 _krb5_xlock(krb5_context context, int fd, krb5_boolean exclusive,
71 const char *filename)
73 int ret;
74 #ifdef HAVE_FCNTL
75 struct flock l;
77 l.l_start = 0;
78 l.l_len = 0;
79 l.l_type = exclusive ? F_WRLCK : F_RDLCK;
80 l.l_whence = SEEK_SET;
81 ret = fcntl(fd, F_SETLKW, &l);
82 #else
83 ret = flock(fd, exclusive ? LOCK_EX : LOCK_SH);
84 #endif
85 if(ret < 0)
86 ret = errno;
87 if(ret == EACCES) /* fcntl can return EACCES instead of EAGAIN */
88 ret = EAGAIN;
90 switch (ret) {
91 case 0:
92 break;
93 case EINVAL: /* filesystem doesn't support locking, let the user have it */
94 ret = 0;
95 break;
96 case EAGAIN:
97 krb5_set_error_string(context, "timed out locking cache file %s",
98 filename);
99 break;
100 default:
101 krb5_set_error_string(context, "error locking cache file %s: %s",
102 filename, strerror(ret));
103 break;
105 return ret;
109 _krb5_xunlock(krb5_context context, int fd)
111 int ret;
112 #ifdef HAVE_FCNTL
113 struct flock l;
114 l.l_start = 0;
115 l.l_len = 0;
116 l.l_type = F_UNLCK;
117 l.l_whence = SEEK_SET;
118 ret = fcntl(fd, F_SETLKW, &l);
119 #else
120 ret = flock(fd, LOCK_UN);
121 #endif
122 if (ret < 0)
123 ret = errno;
124 switch (ret) {
125 case 0:
126 break;
127 case EINVAL: /* filesystem doesn't support locking, let the user have it */
128 ret = 0;
129 break;
130 default:
131 krb5_set_error_string(context,
132 "Failed to unlock file: %s", strerror(ret));
133 break;
135 return ret;
138 static krb5_error_code
139 fcc_lock(krb5_context context, krb5_ccache id,
140 int fd, krb5_boolean exclusive)
142 return _krb5_xlock(context, fd, exclusive, fcc_get_name(context, id));
145 static krb5_error_code
146 fcc_unlock(krb5_context context, int fd)
148 return _krb5_xunlock(context, fd);
151 static krb5_error_code
152 fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
154 krb5_fcache *f;
155 f = malloc(sizeof(*f));
156 if(f == NULL) {
157 krb5_set_error_string(context, "malloc: out of memory");
158 return KRB5_CC_NOMEM;
160 f->filename = strdup(res);
161 if(f->filename == NULL){
162 free(f);
163 krb5_set_error_string(context, "malloc: out of memory");
164 return KRB5_CC_NOMEM;
166 f->version = 0;
167 (*id)->data.data = f;
168 (*id)->data.length = sizeof(*f);
169 return 0;
173 * Try to scrub the contents of `filename' safely.
176 static int
177 scrub_file (int fd)
179 off_t pos;
180 char buf[128];
182 pos = lseek(fd, 0, SEEK_END);
183 if (pos < 0)
184 return errno;
185 if (lseek(fd, 0, SEEK_SET) < 0)
186 return errno;
187 memset(buf, 0, sizeof(buf));
188 while(pos > 0) {
189 ssize_t tmp = write(fd, buf, min(sizeof(buf), pos));
191 if (tmp < 0)
192 return errno;
193 pos -= tmp;
195 fsync (fd);
196 return 0;
200 * Erase `filename' if it exists, trying to remove the contents if
201 * it's `safe'. We always try to remove the file, it it exists. It's
202 * only overwritten if it's a regular file (not a symlink and not a
203 * hardlink)
206 static krb5_error_code
207 erase_file(const char *filename)
209 int fd;
210 struct stat sb1, sb2;
211 int ret;
213 ret = lstat (filename, &sb1);
214 if (ret < 0)
215 return errno;
217 fd = open(filename, O_RDWR | O_BINARY);
218 if(fd < 0) {
219 if(errno == ENOENT)
220 return 0;
221 else
222 return errno;
224 if (unlink(filename) < 0) {
225 close (fd);
226 return errno;
228 ret = fstat (fd, &sb2);
229 if (ret < 0) {
230 close (fd);
231 return errno;
234 /* check if someone was playing with symlinks */
236 if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
237 close (fd);
238 return EPERM;
241 /* there are still hard links to this file */
243 if (sb2.st_nlink != 0) {
244 close (fd);
245 return 0;
248 ret = scrub_file (fd);
249 close (fd);
250 return ret;
253 static krb5_error_code
254 fcc_gen_new(krb5_context context, krb5_ccache *id)
256 krb5_fcache *f;
257 int fd;
258 char *file;
260 f = malloc(sizeof(*f));
261 if(f == NULL) {
262 krb5_set_error_string(context, "malloc: out of memory");
263 return KRB5_CC_NOMEM;
265 asprintf (&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT);
266 if(file == NULL) {
267 free(f);
268 krb5_set_error_string(context, "malloc: out of memory");
269 return KRB5_CC_NOMEM;
271 fd = mkstemp(file);
272 if(fd < 0) {
273 int ret = errno;
274 krb5_set_error_string(context, "mkstemp %s", file);
275 free(f);
276 free(file);
277 return ret;
279 close(fd);
280 f->filename = file;
281 f->version = 0;
282 (*id)->data.data = f;
283 (*id)->data.length = sizeof(*f);
284 return 0;
287 static void
288 storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
290 int flags = 0;
291 switch(vno) {
292 case KRB5_FCC_FVNO_1:
293 flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
294 flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
295 flags |= KRB5_STORAGE_HOST_BYTEORDER;
296 break;
297 case KRB5_FCC_FVNO_2:
298 flags |= KRB5_STORAGE_HOST_BYTEORDER;
299 break;
300 case KRB5_FCC_FVNO_3:
301 flags |= KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE;
302 break;
303 case KRB5_FCC_FVNO_4:
304 break;
305 default:
306 krb5_abortx(context,
307 "storage_set_flags called with bad vno (%x)", vno);
309 krb5_storage_set_flags(sp, flags);
312 static krb5_error_code
313 fcc_open(krb5_context context,
314 krb5_ccache id,
315 int *fd_ret,
316 int flags,
317 mode_t mode)
319 krb5_boolean exclusive = ((flags | O_WRONLY) == flags ||
320 (flags | O_RDWR) == flags);
321 krb5_error_code ret;
322 const char *filename = FILENAME(id);
323 int fd;
324 fd = open(filename, flags, mode);
325 if(fd < 0) {
326 ret = errno;
327 krb5_set_error_string(context, "open(%s): %s", filename,
328 strerror(ret));
329 return ret;
332 if((ret = fcc_lock(context, id, fd, exclusive)) != 0) {
333 close(fd);
334 return ret;
336 *fd_ret = fd;
337 return 0;
340 static krb5_error_code
341 fcc_initialize(krb5_context context,
342 krb5_ccache id,
343 krb5_principal primary_principal)
345 krb5_fcache *f = FCACHE(id);
346 int ret = 0;
347 int fd;
348 char *filename = f->filename;
350 unlink (filename);
352 ret = fcc_open(context, id, &fd, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
353 if(ret)
354 return ret;
356 krb5_storage *sp;
357 sp = krb5_storage_from_fd(fd);
358 krb5_storage_set_eof_code(sp, KRB5_CC_END);
359 if(context->fcache_vno != 0)
360 f->version = context->fcache_vno;
361 else
362 f->version = KRB5_FCC_FVNO_4;
363 ret |= krb5_store_int8(sp, 5);
364 ret |= krb5_store_int8(sp, f->version);
365 storage_set_flags(context, sp, f->version);
366 if(f->version == KRB5_FCC_FVNO_4 && ret == 0) {
367 /* V4 stuff */
368 if (context->kdc_sec_offset) {
369 ret |= krb5_store_int16 (sp, 12); /* length */
370 ret |= krb5_store_int16 (sp, FCC_TAG_DELTATIME); /* Tag */
371 ret |= krb5_store_int16 (sp, 8); /* length of data */
372 ret |= krb5_store_int32 (sp, context->kdc_sec_offset);
373 ret |= krb5_store_int32 (sp, context->kdc_usec_offset);
374 } else {
375 ret |= krb5_store_int16 (sp, 0);
378 ret |= krb5_store_principal(sp, primary_principal);
380 krb5_storage_free(sp);
382 fcc_unlock(context, fd);
383 if (close(fd) < 0)
384 if (ret == 0) {
385 ret = errno;
386 krb5_set_error_string (context, "close %s: %s",
387 FILENAME(id), strerror(ret));
389 return ret;
392 static krb5_error_code
393 fcc_close(krb5_context context,
394 krb5_ccache id)
396 free (FILENAME(id));
397 krb5_data_free(&id->data);
398 return 0;
401 static krb5_error_code
402 fcc_destroy(krb5_context context,
403 krb5_ccache id)
405 erase_file(FILENAME(id));
406 return 0;
409 static krb5_error_code
410 fcc_store_cred(krb5_context context,
411 krb5_ccache id,
412 krb5_creds *creds)
414 int ret;
415 int fd;
417 ret = fcc_open(context, id, &fd, O_WRONLY | O_APPEND | O_BINARY, 0);
418 if(ret)
419 return ret;
421 krb5_storage *sp;
422 sp = krb5_storage_from_fd(fd);
423 krb5_storage_set_eof_code(sp, KRB5_CC_END);
424 storage_set_flags(context, sp, FCACHE(id)->version);
425 if (!krb5_config_get_bool_default(context, NULL, TRUE,
426 "libdefaults",
427 "fcc-mit-ticketflags",
428 NULL))
429 krb5_storage_set_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER);
430 ret = krb5_store_creds(sp, creds);
431 krb5_storage_free(sp);
433 fcc_unlock(context, fd);
434 if (close(fd) < 0)
435 if (ret == 0) {
436 ret = errno;
437 krb5_set_error_string (context, "close %s: %s",
438 FILENAME(id), strerror(ret));
440 return ret;
443 static krb5_error_code
444 init_fcc (krb5_context context,
445 krb5_ccache id,
446 krb5_storage **ret_sp,
447 int *ret_fd)
449 int fd;
450 int8_t pvno, tag;
451 krb5_storage *sp;
452 krb5_error_code ret;
454 ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY, 0);
455 if(ret)
456 return ret;
458 sp = krb5_storage_from_fd(fd);
459 if(sp == NULL) {
460 krb5_clear_error_string(context);
461 ret = ENOMEM;
462 goto out;
464 krb5_storage_set_eof_code(sp, KRB5_CC_END);
465 ret = krb5_ret_int8(sp, &pvno);
466 if(ret != 0) {
467 if(ret == KRB5_CC_END) {
468 krb5_set_error_string(context, "Empty credential cache file: %s",
469 FILENAME(id));
470 ret = ENOENT;
471 } else
472 krb5_set_error_string(context, "Error reading pvno in "
473 "cache file: %s", FILENAME(id));
474 goto out;
476 if(pvno != 5) {
477 krb5_set_error_string(context, "Bad version number in credential "
478 "cache file: %s", FILENAME(id));
479 ret = KRB5_CCACHE_BADVNO;
480 goto out;
482 ret = krb5_ret_int8(sp, &tag); /* should not be host byte order */
483 if(ret != 0) {
484 krb5_set_error_string(context, "Error reading tag in "
485 "cache file: %s", FILENAME(id));
486 ret = KRB5_CC_FORMAT;
487 goto out;
489 FCACHE(id)->version = tag;
490 storage_set_flags(context, sp, FCACHE(id)->version);
491 switch (tag) {
492 case KRB5_FCC_FVNO_4: {
493 int16_t length;
495 ret = krb5_ret_int16 (sp, &length);
496 if(ret) {
497 ret = KRB5_CC_FORMAT;
498 krb5_set_error_string(context, "Error reading tag length in "
499 "cache file: %s", FILENAME(id));
500 goto out;
502 while(length > 0) {
503 int16_t dtag, data_len;
504 int i;
505 int8_t dummy;
507 ret = krb5_ret_int16 (sp, &dtag);
508 if(ret) {
509 krb5_set_error_string(context, "Error reading dtag in "
510 "cache file: %s", FILENAME(id));
511 ret = KRB5_CC_FORMAT;
512 goto out;
514 ret = krb5_ret_int16 (sp, &data_len);
515 if(ret) {
516 krb5_set_error_string(context, "Error reading dlength in "
517 "cache file: %s", FILENAME(id));
518 ret = KRB5_CC_FORMAT;
519 goto out;
521 switch (dtag) {
522 case FCC_TAG_DELTATIME :
523 ret = krb5_ret_int32 (sp, &context->kdc_sec_offset);
524 if(ret) {
525 krb5_set_error_string(context, "Error reading kdc_sec in "
526 "cache file: %s", FILENAME(id));
527 ret = KRB5_CC_FORMAT;
528 goto out;
530 ret = krb5_ret_int32 (sp, &context->kdc_usec_offset);
531 if(ret) {
532 krb5_set_error_string(context, "Error reading kdc_usec in "
533 "cache file: %s", FILENAME(id));
534 ret = KRB5_CC_FORMAT;
535 goto out;
537 break;
538 default :
539 for (i = 0; i < data_len; ++i) {
540 ret = krb5_ret_int8 (sp, &dummy);
541 if(ret) {
542 krb5_set_error_string(context, "Error reading unknown "
543 "tag in cache file: %s",
544 FILENAME(id));
545 ret = KRB5_CC_FORMAT;
546 goto out;
549 break;
551 length -= 4 + data_len;
553 break;
555 case KRB5_FCC_FVNO_3:
556 case KRB5_FCC_FVNO_2:
557 case KRB5_FCC_FVNO_1:
558 break;
559 default :
560 ret = KRB5_CCACHE_BADVNO;
561 krb5_set_error_string(context, "Unknown version number (%d) in "
562 "credential cache file: %s",
563 (int)tag, FILENAME(id));
564 goto out;
566 *ret_sp = sp;
567 *ret_fd = fd;
569 return 0;
570 out:
571 if(sp != NULL)
572 krb5_storage_free(sp);
573 fcc_unlock(context, fd);
574 close(fd);
575 return ret;
578 static krb5_error_code
579 fcc_get_principal(krb5_context context,
580 krb5_ccache id,
581 krb5_principal *principal)
583 krb5_error_code ret;
584 int fd;
585 krb5_storage *sp;
587 ret = init_fcc (context, id, &sp, &fd);
588 if (ret)
589 return ret;
590 ret = krb5_ret_principal(sp, principal);
591 if (ret)
592 krb5_clear_error_string(context);
593 krb5_storage_free(sp);
594 fcc_unlock(context, fd);
595 close(fd);
596 return ret;
599 static krb5_error_code
600 fcc_end_get (krb5_context context,
601 krb5_ccache id,
602 krb5_cc_cursor *cursor);
604 static krb5_error_code
605 fcc_get_first (krb5_context context,
606 krb5_ccache id,
607 krb5_cc_cursor *cursor)
609 krb5_error_code ret;
610 krb5_principal principal;
612 *cursor = malloc(sizeof(struct fcc_cursor));
613 if (*cursor == NULL) {
614 krb5_set_error_string (context, "malloc: out of memory");
615 return ENOMEM;
617 memset(*cursor, 0, sizeof(struct fcc_cursor));
619 ret = init_fcc (context, id, &FCC_CURSOR(*cursor)->sp,
620 &FCC_CURSOR(*cursor)->fd);
621 if (ret) {
622 free(*cursor);
623 *cursor = NULL;
624 return ret;
626 ret = krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal);
627 if(ret) {
628 krb5_clear_error_string(context);
629 fcc_end_get(context, id, cursor);
630 return ret;
632 krb5_free_principal (context, principal);
633 fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
634 return 0;
637 static krb5_error_code
638 fcc_get_next (krb5_context context,
639 krb5_ccache id,
640 krb5_cc_cursor *cursor,
641 krb5_creds *creds)
643 krb5_error_code ret;
644 if((ret = fcc_lock(context, id, FCC_CURSOR(*cursor)->fd, FALSE)) != 0)
645 return ret;
647 ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds);
648 if (ret)
649 krb5_clear_error_string(context);
651 fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
652 return ret;
655 static krb5_error_code
656 fcc_end_get (krb5_context context,
657 krb5_ccache id,
658 krb5_cc_cursor *cursor)
660 krb5_storage_free(FCC_CURSOR(*cursor)->sp);
661 close (FCC_CURSOR(*cursor)->fd);
662 free(*cursor);
663 *cursor = NULL;
664 return 0;
667 static krb5_error_code
668 fcc_remove_cred(krb5_context context,
669 krb5_ccache id,
670 krb5_flags which,
671 krb5_creds *cred)
673 krb5_error_code ret;
674 krb5_ccache copy;
676 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &copy);
677 if (ret)
678 return ret;
680 ret = krb5_cc_copy_cache(context, id, copy);
681 if (ret) {
682 krb5_cc_destroy(context, copy);
683 return ret;
686 ret = krb5_cc_remove_cred(context, copy, which, cred);
687 if (ret) {
688 krb5_cc_destroy(context, copy);
689 return ret;
692 fcc_destroy(context, id);
694 ret = krb5_cc_copy_cache(context, copy, id);
695 krb5_cc_destroy(context, copy);
697 return ret;
700 static krb5_error_code
701 fcc_set_flags(krb5_context context,
702 krb5_ccache id,
703 krb5_flags flags)
705 return 0; /* XXX */
708 static krb5_error_code
709 fcc_get_version(krb5_context context,
710 krb5_ccache id)
712 return FCACHE(id)->version;
715 struct fcache_iter {
716 int first;
719 static krb5_error_code
720 fcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
722 struct fcache_iter *iter;
724 iter = calloc(1, sizeof(*iter));
725 if (iter == NULL) {
726 krb5_set_error_string(context, "malloc - out of memory");
727 return ENOMEM;
729 iter->first = 1;
730 *cursor = iter;
731 return 0;
734 static krb5_error_code
735 fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
737 struct fcache_iter *iter = cursor;
738 krb5_error_code ret;
739 const char *fn;
740 char *expandedfn = NULL;
742 if (!iter->first) {
743 krb5_clear_error_string(context);
744 return KRB5_CC_END;
746 iter->first = 0;
748 fn = krb5_cc_default_name(context);
749 if (strncasecmp(fn, "FILE:", 5) != 0) {
750 ret = _krb5_expand_default_cc_name(context,
751 KRB5_DEFAULT_CCNAME_FILE,
752 &expandedfn);
753 if (ret)
754 return ret;
756 ret = krb5_cc_resolve(context, fn, id);
757 if (expandedfn)
758 free(expandedfn);
760 return ret;
763 static krb5_error_code
764 fcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
766 struct fcache_iter *iter = cursor;
767 free(iter);
768 return 0;
771 static krb5_error_code
772 fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
774 krb5_error_code ret = 0;
776 ret = rename(FILENAME(from), FILENAME(to));
777 if (ret && errno != EXDEV) {
778 ret = errno;
779 krb5_set_error_string(context,
780 "Rename of file from %s to %s failed: %s",
781 FILENAME(from), FILENAME(to),
782 strerror(ret));
783 return ret;
784 } else if (ret && errno == EXDEV) {
785 /* make a copy and delete the orignal */
786 krb5_ssize_t sz1, sz2;
787 int fd1, fd2;
788 char buf[BUFSIZ];
790 ret = fcc_open(context, from, &fd1, O_RDONLY | O_BINARY, 0);
791 if(ret)
792 return ret;
794 unlink(FILENAME(to));
796 ret = fcc_open(context, to, &fd2,
797 O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600);
798 if(ret)
799 goto out1;
801 while((sz1 = read(fd1, buf, sizeof(buf))) > 0) {
802 sz2 = write(fd2, buf, sz1);
803 if (sz1 != sz2) {
804 ret = EIO;
805 krb5_set_error_string(context,
806 "Failed to write data from one file "
807 "credential cache to the other");
808 goto out2;
811 if (sz1 < 0) {
812 ret = EIO;
813 krb5_set_error_string(context,
814 "Failed to read data from one file "
815 "credential cache to the other");
816 goto out2;
818 erase_file(FILENAME(from));
820 out2:
821 fcc_unlock(context, fd2);
822 close(fd2);
824 out1:
825 fcc_unlock(context, fd1);
826 close(fd1);
828 if (ret) {
829 erase_file(FILENAME(to));
830 return ret;
834 /* make sure ->version is uptodate */
836 krb5_storage *sp;
837 int fd;
838 ret = init_fcc (context, to, &sp, &fd);
839 krb5_storage_free(sp);
840 fcc_unlock(context, fd);
841 close(fd);
843 return ret;
846 static krb5_error_code
847 fcc_default_name(krb5_context context, char **str)
849 return _krb5_expand_default_cc_name(context,
850 KRB5_DEFAULT_CCNAME_FILE,
851 str);
855 * Variable containing the FILE based credential cache implemention.
857 * @ingroup krb5_ccache
860 const krb5_cc_ops krb5_fcc_ops = {
861 "FILE",
862 fcc_get_name,
863 fcc_resolve,
864 fcc_gen_new,
865 fcc_initialize,
866 fcc_destroy,
867 fcc_close,
868 fcc_store_cred,
869 NULL, /* fcc_retrieve */
870 fcc_get_principal,
871 fcc_get_first,
872 fcc_get_next,
873 fcc_end_get,
874 fcc_remove_cred,
875 fcc_set_flags,
876 fcc_get_version,
877 fcc_get_cache_first,
878 fcc_get_cache_next,
879 fcc_end_cache_get,
880 fcc_move,
881 fcc_default_name