summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/lib/krb5/fcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/lib/krb5/fcache.c')
-rw-r--r--crypto/heimdal/lib/krb5/fcache.c273
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, &copy);
+ 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
};
OpenPOWER on IntegriCloud