diff options
Diffstat (limited to 'crypto/heimdal/lib/krb5/fcache.c')
-rw-r--r-- | crypto/heimdal/lib/krb5/fcache.c | 273 |
1 files changed, 249 insertions, 24 deletions
diff --git a/crypto/heimdal/lib/krb5/fcache.c b/crypto/heimdal/lib/krb5/fcache.c index 38006c3..3857b58 100644 --- a/crypto/heimdal/lib/krb5/fcache.c +++ b/crypto/heimdal/lib/krb5/fcache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: fcache.c,v 1.34.6.6 2004/03/10 13:30:59 lha Exp $"); +RCSID("$Id: fcache.c 22522 2008-01-24 11:56:25Z lha $"); typedef struct krb5_fcache{ char *filename; @@ -105,18 +105,33 @@ _krb5_xlock(krb5_context context, int fd, krb5_boolean exclusive, } int -_krb5_xunlock(int fd) +_krb5_xunlock(krb5_context context, int fd) { -#ifdef HAVE_FCNTL_LOCK + int ret; +#ifdef HAVE_FCNTL struct flock l; l.l_start = 0; l.l_len = 0; l.l_type = F_UNLCK; l.l_whence = SEEK_SET; - return fcntl(fd, F_SETLKW, &l); + ret = fcntl(fd, F_SETLKW, &l); #else - return flock(fd, LOCK_UN); + ret = flock(fd, LOCK_UN); #endif + if (ret < 0) + ret = errno; + switch (ret) { + case 0: + break; + case EINVAL: /* filesystem doesn't support locking, let the user have it */ + ret = 0; + break; + default: + krb5_set_error_string(context, + "Failed to unlock file: %s", strerror(ret)); + break; + } + return ret; } static krb5_error_code @@ -129,7 +144,7 @@ fcc_lock(krb5_context context, krb5_ccache id, static krb5_error_code fcc_unlock(krb5_context context, int fd) { - return _krb5_xunlock(fd); + return _krb5_xunlock(context, fd); } static krb5_error_code @@ -254,10 +269,11 @@ fcc_gen_new(krb5_context context, krb5_ccache *id) } fd = mkstemp(file); if(fd < 0) { + int ret = errno; + krb5_set_error_string(context, "mkstemp %s", file); free(f); free(file); - krb5_set_error_string(context, "mkstemp %s", file); - return errno; + return ret; } close(fd); f->filename = file; @@ -405,13 +421,12 @@ fcc_store_cred(krb5_context context, sp = krb5_storage_from_fd(fd); krb5_storage_set_eof_code(sp, KRB5_CC_END); storage_set_flags(context, sp, FCACHE(id)->version); - if (krb5_config_get_bool_default(context, NULL, FALSE, - "libdefaults", - "fcc-mit-ticketflags", - NULL)) - ret = _krb5_store_creds_heimdal_0_7(sp, creds); - else - ret = _krb5_store_creds_heimdal_pre_0_7(sp, creds); + if (!krb5_config_get_bool_default(context, NULL, TRUE, + "libdefaults", + "fcc-mit-ticketflags", + NULL)) + krb5_storage_set_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER); + ret = krb5_store_creds(sp, creds); krb5_storage_free(sp); } fcc_unlock(context, fd); @@ -436,28 +451,37 @@ init_fcc (krb5_context context, krb5_error_code ret; ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY, 0); - if(ret) return ret; sp = krb5_storage_from_fd(fd); if(sp == NULL) { + krb5_clear_error_string(context); ret = ENOMEM; goto out; } krb5_storage_set_eof_code(sp, KRB5_CC_END); ret = krb5_ret_int8(sp, &pvno); if(ret != 0) { - if(ret == KRB5_CC_END) - ret = ENOENT; /* empty file */ + if(ret == KRB5_CC_END) { + krb5_set_error_string(context, "Empty credential cache file: %s", + FILENAME(id)); + ret = ENOENT; + } else + krb5_set_error_string(context, "Error reading pvno in " + "cache file: %s", FILENAME(id)); goto out; } if(pvno != 5) { + krb5_set_error_string(context, "Bad version number in credential " + "cache file: %s", FILENAME(id)); ret = KRB5_CCACHE_BADVNO; goto out; } ret = krb5_ret_int8(sp, &tag); /* should not be host byte order */ if(ret != 0) { + krb5_set_error_string(context, "Error reading tag in " + "cache file: %s", FILENAME(id)); ret = KRB5_CC_FORMAT; goto out; } @@ -470,32 +494,42 @@ init_fcc (krb5_context context, ret = krb5_ret_int16 (sp, &length); if(ret) { ret = KRB5_CC_FORMAT; + krb5_set_error_string(context, "Error reading tag length in " + "cache file: %s", FILENAME(id)); goto out; } while(length > 0) { - int16_t tag, data_len; + int16_t dtag, data_len; int i; int8_t dummy; - ret = krb5_ret_int16 (sp, &tag); + ret = krb5_ret_int16 (sp, &dtag); if(ret) { + krb5_set_error_string(context, "Error reading dtag in " + "cache file: %s", FILENAME(id)); ret = KRB5_CC_FORMAT; goto out; } ret = krb5_ret_int16 (sp, &data_len); if(ret) { + krb5_set_error_string(context, "Error reading dlength in " + "cache file: %s", FILENAME(id)); ret = KRB5_CC_FORMAT; goto out; } - switch (tag) { + switch (dtag) { case FCC_TAG_DELTATIME : ret = krb5_ret_int32 (sp, &context->kdc_sec_offset); if(ret) { + krb5_set_error_string(context, "Error reading kdc_sec in " + "cache file: %s", FILENAME(id)); ret = KRB5_CC_FORMAT; goto out; } ret = krb5_ret_int32 (sp, &context->kdc_usec_offset); if(ret) { + krb5_set_error_string(context, "Error reading kdc_usec in " + "cache file: %s", FILENAME(id)); ret = KRB5_CC_FORMAT; goto out; } @@ -504,6 +538,9 @@ init_fcc (krb5_context context, for (i = 0; i < data_len; ++i) { ret = krb5_ret_int8 (sp, &dummy); if(ret) { + krb5_set_error_string(context, "Error reading unknown " + "tag in cache file: %s", + FILENAME(id)); ret = KRB5_CC_FORMAT; goto out; } @@ -520,6 +557,9 @@ init_fcc (krb5_context context, break; default : ret = KRB5_CCACHE_BADVNO; + krb5_set_error_string(context, "Unknown version number (%d) in " + "credential cache file: %s", + (int)tag, FILENAME(id)); goto out; } *ret_sp = sp; @@ -547,6 +587,8 @@ fcc_get_principal(krb5_context context, if (ret) return ret; ret = krb5_ret_principal(sp, principal); + if (ret) + krb5_clear_error_string(context); krb5_storage_free(sp); fcc_unlock(context, fd); close(fd); @@ -567,15 +609,22 @@ fcc_get_first (krb5_context context, krb5_principal principal; *cursor = malloc(sizeof(struct fcc_cursor)); + if (*cursor == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + return ENOMEM; + } + memset(*cursor, 0, sizeof(struct fcc_cursor)); ret = init_fcc (context, id, &FCC_CURSOR(*cursor)->sp, &FCC_CURSOR(*cursor)->fd); if (ret) { free(*cursor); + *cursor = NULL; return ret; } ret = krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal); if(ret) { + krb5_clear_error_string(context); fcc_end_get(context, id, cursor); return ret; } @@ -595,6 +644,8 @@ fcc_get_next (krb5_context context, return ret; ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds); + if (ret) + krb5_clear_error_string(context); fcc_unlock(context, FCC_CURSOR(*cursor)->fd); return ret; @@ -618,7 +669,31 @@ fcc_remove_cred(krb5_context context, krb5_flags which, krb5_creds *cred) { - return 0; /* XXX */ + krb5_error_code ret; + krb5_ccache copy; + + ret = krb5_cc_gen_new(context, &krb5_mcc_ops, ©); + if (ret) + return ret; + + ret = krb5_cc_copy_cache(context, id, copy); + if (ret) { + krb5_cc_destroy(context, copy); + return ret; + } + + ret = krb5_cc_remove_cred(context, copy, which, cred); + if (ret) { + krb5_cc_destroy(context, copy); + return ret; + } + + fcc_destroy(context, id); + + ret = krb5_cc_copy_cache(context, copy, id); + krb5_cc_destroy(context, copy); + + return ret; } static krb5_error_code @@ -636,6 +711,151 @@ fcc_get_version(krb5_context context, return FCACHE(id)->version; } +struct fcache_iter { + int first; +}; + +static krb5_error_code +fcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + struct fcache_iter *iter; + + iter = calloc(1, sizeof(*iter)); + if (iter == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return ENOMEM; + } + iter->first = 1; + *cursor = iter; + return 0; +} + +static krb5_error_code +fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + struct fcache_iter *iter = cursor; + krb5_error_code ret; + const char *fn; + char *expandedfn = NULL; + + if (!iter->first) { + krb5_clear_error_string(context); + return KRB5_CC_END; + } + iter->first = 0; + + fn = krb5_cc_default_name(context); + if (strncasecmp(fn, "FILE:", 5) != 0) { + ret = _krb5_expand_default_cc_name(context, + KRB5_DEFAULT_CCNAME_FILE, + &expandedfn); + if (ret) + return ret; + } + ret = krb5_cc_resolve(context, fn, id); + if (expandedfn) + free(expandedfn); + + return ret; +} + +static krb5_error_code +fcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + struct fcache_iter *iter = cursor; + free(iter); + return 0; +} + +static krb5_error_code +fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) +{ + krb5_error_code ret = 0; + + ret = rename(FILENAME(from), FILENAME(to)); + if (ret && errno != EXDEV) { + ret = errno; + krb5_set_error_string(context, + "Rename of file from %s to %s failed: %s", + FILENAME(from), FILENAME(to), + strerror(ret)); + return ret; + } else if (ret && errno == EXDEV) { + /* make a copy and delete the orignal */ + krb5_ssize_t sz1, sz2; + int fd1, fd2; + char buf[BUFSIZ]; + + ret = fcc_open(context, from, &fd1, O_RDONLY | O_BINARY, 0); + if(ret) + return ret; + + unlink(FILENAME(to)); + + ret = fcc_open(context, to, &fd2, + O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600); + if(ret) + goto out1; + + while((sz1 = read(fd1, buf, sizeof(buf))) > 0) { + sz2 = write(fd2, buf, sz1); + if (sz1 != sz2) { + ret = EIO; + krb5_set_error_string(context, + "Failed to write data from one file " + "credential cache to the other"); + goto out2; + } + } + if (sz1 < 0) { + ret = EIO; + krb5_set_error_string(context, + "Failed to read data from one file " + "credential cache to the other"); + goto out2; + } + erase_file(FILENAME(from)); + + out2: + fcc_unlock(context, fd2); + close(fd2); + + out1: + fcc_unlock(context, fd1); + close(fd1); + + if (ret) { + erase_file(FILENAME(to)); + return ret; + } + } + + /* make sure ->version is uptodate */ + { + krb5_storage *sp; + int fd; + ret = init_fcc (context, to, &sp, &fd); + krb5_storage_free(sp); + fcc_unlock(context, fd); + close(fd); + } + return ret; +} + +static krb5_error_code +fcc_default_name(krb5_context context, char **str) +{ + return _krb5_expand_default_cc_name(context, + KRB5_DEFAULT_CCNAME_FILE, + str); +} + +/** + * Variable containing the FILE based credential cache implemention. + * + * @ingroup krb5_ccache + */ + const krb5_cc_ops krb5_fcc_ops = { "FILE", fcc_get_name, @@ -652,5 +872,10 @@ const krb5_cc_ops krb5_fcc_ops = { fcc_end_get, fcc_remove_cred, fcc_set_flags, - fcc_get_version + fcc_get_version, + fcc_get_cache_first, + fcc_get_cache_next, + fcc_end_cache_get, + fcc_move, + fcc_default_name }; |