implement locking
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@12993 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997 - 2002 Kungliga Tekniska H<>gskolan
|
||||
* Copyright (c) 1997 - 2003 Kungliga Tekniska H<>gskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -58,6 +58,9 @@ struct fcc_cursor {
|
||||
|
||||
#define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
|
||||
|
||||
#define KRB5_CC_LOCK_RETRY_COUNT 50
|
||||
#define KRB5_CC_LOCK_RETRY 1
|
||||
|
||||
static const char*
|
||||
fcc_get_name(krb5_context context,
|
||||
krb5_ccache id)
|
||||
@@ -65,6 +68,67 @@ fcc_get_name(krb5_context context,
|
||||
return FILENAME(id);
|
||||
}
|
||||
|
||||
static int
|
||||
xlock(int fd, krb5_boolean exclusive)
|
||||
{
|
||||
#ifdef HAVE_FCNTL
|
||||
struct flock l;
|
||||
l.l_start = 0;
|
||||
l.l_len = 0;
|
||||
l.l_type = exclusive ? F_WRLCK : F_RDLCK;
|
||||
l.l_whence = SEEK_SET;
|
||||
return fcntl(fd, F_SETLK, &l);
|
||||
#else
|
||||
return flock(fd, (exclusive ? LOCK_EX : LOCK_SH) | LOCK_NB);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
xunlock(int fd)
|
||||
{
|
||||
#ifdef HAVE_FCNTL_LOCK
|
||||
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_SETLK, &l);
|
||||
#else
|
||||
return flock(fd, LOCK_UN);
|
||||
#endif
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fcc_lock(krb5_context context, krb5_ccache id,
|
||||
int fd, krb5_boolean exclusive)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
int i;
|
||||
for (i = 0; i < KRB5_CC_LOCK_RETRY_COUNT; i++) {
|
||||
if (xlock(fd, exclusive) < 0) {
|
||||
ret = errno;
|
||||
if(ret == EAGAIN) {
|
||||
sleep(KRB5_CC_LOCK_RETRY);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(ret == EAGAIN)
|
||||
krb5_set_error_string(context, "timed out locking cache file %s",
|
||||
fcc_get_name(context, id));
|
||||
else if(ret != 0)
|
||||
krb5_set_error_string(context, "error locking cache file %s: %s",
|
||||
fcc_get_name(context, id), strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fcc_unlock(krb5_context context, int fd)
|
||||
{
|
||||
return xunlock(fd);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
||||
{
|
||||
@@ -138,11 +202,6 @@ erase_file(const char *filename)
|
||||
else
|
||||
return errno;
|
||||
}
|
||||
if (unlink(filename) < 0) {
|
||||
close (fd);
|
||||
return errno;
|
||||
}
|
||||
|
||||
ret = fstat (fd, &sb2);
|
||||
if (ret < 0) {
|
||||
close (fd);
|
||||
@@ -156,6 +215,17 @@ erase_file(const char *filename)
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
if (unlink(filename) < 0) {
|
||||
close (fd);
|
||||
return errno;
|
||||
}
|
||||
|
||||
ret = fstat (fd, &sb2);
|
||||
if (ret < 0) {
|
||||
close (fd);
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* there are still hard links to this file */
|
||||
|
||||
if (sb2.st_nlink != 0) {
|
||||
@@ -226,6 +296,34 @@ storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
|
||||
krb5_storage_set_flags(sp, flags);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fcc_open(krb5_context context,
|
||||
krb5_ccache id,
|
||||
int *fd_ret,
|
||||
int flags,
|
||||
mode_t mode)
|
||||
{
|
||||
krb5_boolean exclusive = ((flags | O_WRONLY) == flags ||
|
||||
(flags | O_RDWR) == flags);
|
||||
krb5_error_code ret;
|
||||
const char *filename = FILENAME(id);
|
||||
int fd;
|
||||
fd = open(filename, flags, mode);
|
||||
if(fd < 0) {
|
||||
ret = errno;
|
||||
krb5_set_error_string(context, "open(%s): %s", filename,
|
||||
strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if((ret = fcc_lock(context, id, fd, exclusive)) != 0) {
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
*fd_ret = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fcc_initialize(krb5_context context,
|
||||
krb5_ccache id,
|
||||
@@ -238,13 +336,9 @@ fcc_initialize(krb5_context context,
|
||||
|
||||
unlink (filename);
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
|
||||
if(fd == -1) {
|
||||
ret = errno;
|
||||
krb5_set_error_string(context, "open(%s): %s", filename,
|
||||
strerror(ret));
|
||||
ret = fcc_open(context, id, &fd, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
{
|
||||
krb5_storage *sp;
|
||||
sp = krb5_storage_from_fd(fd);
|
||||
@@ -269,15 +363,16 @@ fcc_initialize(krb5_context context,
|
||||
}
|
||||
}
|
||||
ret |= krb5_store_principal(sp, primary_principal);
|
||||
|
||||
krb5_storage_free(sp);
|
||||
}
|
||||
if(close(fd) < 0)
|
||||
fcc_unlock(context, fd);
|
||||
if (close(fd) < 0)
|
||||
if (ret == 0) {
|
||||
ret = errno;
|
||||
krb5_set_error_string (context, "close %s: %s", filename,
|
||||
strerror(ret));
|
||||
krb5_set_error_string (context, "close %s: %s",
|
||||
FILENAME(id), strerror(ret));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -294,11 +389,7 @@ static krb5_error_code
|
||||
fcc_destroy(krb5_context context,
|
||||
krb5_ccache id)
|
||||
{
|
||||
char *f;
|
||||
f = FILENAME(id);
|
||||
|
||||
erase_file(f);
|
||||
|
||||
erase_file(FILENAME(id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -309,16 +400,10 @@ fcc_store_cred(krb5_context context,
|
||||
{
|
||||
int ret;
|
||||
int fd;
|
||||
char *f;
|
||||
|
||||
f = FILENAME(id);
|
||||
|
||||
fd = open(f, O_WRONLY | O_APPEND | O_BINARY);
|
||||
if(fd < 0) {
|
||||
ret = errno;
|
||||
krb5_set_error_string (context, "open(%s): %s", f, strerror(ret));
|
||||
ret = fcc_open(context, id, &fd, O_WRONLY | O_APPEND | O_BINARY, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
{
|
||||
krb5_storage *sp;
|
||||
sp = krb5_storage_from_fd(fd);
|
||||
@@ -327,31 +412,19 @@ fcc_store_cred(krb5_context context,
|
||||
ret = krb5_store_creds(sp, creds);
|
||||
krb5_storage_free(sp);
|
||||
}
|
||||
fcc_unlock(context, fd);
|
||||
if (close(fd) < 0)
|
||||
if (ret == 0) {
|
||||
ret = errno;
|
||||
krb5_set_error_string (context, "close %s: %s", f, strerror(ret));
|
||||
krb5_set_error_string (context, "close %s: %s",
|
||||
FILENAME(id), strerror(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fcc_read_cred (krb5_context context,
|
||||
krb5_fcache *fc,
|
||||
krb5_storage *sp,
|
||||
krb5_creds *creds)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
storage_set_flags(context, sp, fc->version);
|
||||
|
||||
ret = krb5_ret_creds(sp, creds);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
init_fcc (krb5_context context,
|
||||
krb5_fcache *fcache,
|
||||
krb5_ccache id,
|
||||
krb5_storage **ret_sp,
|
||||
int *ret_fd)
|
||||
{
|
||||
@@ -360,48 +433,79 @@ init_fcc (krb5_context context,
|
||||
krb5_storage *sp;
|
||||
krb5_error_code ret;
|
||||
|
||||
fd = open(fcache->filename, O_RDONLY | O_BINARY);
|
||||
if(fd < 0) {
|
||||
ret = errno;
|
||||
krb5_set_error_string(context, "open(%s): %s", fcache->filename,
|
||||
strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
sp = krb5_storage_from_fd(fd);
|
||||
krb5_storage_set_eof_code(sp, KRB5_CC_END);
|
||||
ret = krb5_ret_int8(sp, &pvno);
|
||||
if(ret == KRB5_CC_END)
|
||||
return ENOENT;
|
||||
ret = fcc_open(context, id, &fd, O_RDONLY | O_BINARY, 0);
|
||||
|
||||
if(ret)
|
||||
return ret;
|
||||
if(pvno != 5) {
|
||||
krb5_storage_free(sp);
|
||||
close(fd);
|
||||
return KRB5_CCACHE_BADVNO;
|
||||
|
||||
sp = krb5_storage_from_fd(fd);
|
||||
if(sp == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
krb5_ret_int8(sp, &tag); /* should not be host byte order */
|
||||
fcache->version = tag;
|
||||
storage_set_flags(context, sp, fcache->version);
|
||||
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 */
|
||||
goto out;
|
||||
}
|
||||
if(pvno != 5) {
|
||||
ret = KRB5_CCACHE_BADVNO;
|
||||
goto out;
|
||||
}
|
||||
ret = krb5_ret_int8(sp, &tag); /* should not be host byte order */
|
||||
if(ret != 0) {
|
||||
ret = KRB5_CC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
FCACHE(id)->version = tag;
|
||||
storage_set_flags(context, sp, FCACHE(id)->version);
|
||||
switch (tag) {
|
||||
case KRB5_FCC_FVNO_4: {
|
||||
int16_t length;
|
||||
|
||||
krb5_ret_int16 (sp, &length);
|
||||
ret = krb5_ret_int16 (sp, &length);
|
||||
if(ret) {
|
||||
ret = KRB5_CC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
while(length > 0) {
|
||||
int16_t tag, data_len;
|
||||
int i;
|
||||
int8_t dummy;
|
||||
|
||||
krb5_ret_int16 (sp, &tag);
|
||||
krb5_ret_int16 (sp, &data_len);
|
||||
ret = krb5_ret_int16 (sp, &tag);
|
||||
if(ret) {
|
||||
ret = KRB5_CC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
ret = krb5_ret_int16 (sp, &data_len);
|
||||
if(ret) {
|
||||
ret = KRB5_CC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
switch (tag) {
|
||||
case FCC_TAG_DELTATIME :
|
||||
krb5_ret_int32 (sp, &context->kdc_sec_offset);
|
||||
krb5_ret_int32 (sp, &context->kdc_usec_offset);
|
||||
ret = krb5_ret_int32 (sp, &context->kdc_sec_offset);
|
||||
if(ret) {
|
||||
ret = KRB5_CC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
ret = krb5_ret_int32 (sp, &context->kdc_usec_offset);
|
||||
if(ret) {
|
||||
ret = KRB5_CC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
for (i = 0; i < data_len; ++i)
|
||||
krb5_ret_int8 (sp, &dummy);
|
||||
for (i = 0; i < data_len; ++i) {
|
||||
ret = krb5_ret_int8 (sp, &dummy);
|
||||
if(ret) {
|
||||
ret = KRB5_CC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
length -= 4 + data_len;
|
||||
@@ -413,13 +517,19 @@ init_fcc (krb5_context context,
|
||||
case KRB5_FCC_FVNO_1:
|
||||
break;
|
||||
default :
|
||||
krb5_storage_free (sp);
|
||||
close (fd);
|
||||
return KRB5_CCACHE_BADVNO;
|
||||
ret = KRB5_CCACHE_BADVNO;
|
||||
goto out;
|
||||
}
|
||||
*ret_sp = sp;
|
||||
*ret_fd = fd;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
if(sp != NULL)
|
||||
krb5_storage_free(sp);
|
||||
fcc_unlock(context, fd);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
@@ -428,19 +538,24 @@ fcc_get_principal(krb5_context context,
|
||||
krb5_principal *principal)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_fcache *f = FCACHE(id);
|
||||
int fd;
|
||||
krb5_storage *sp;
|
||||
|
||||
ret = init_fcc (context, f, &sp, &fd);
|
||||
ret = init_fcc (context, id, &sp, &fd);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = krb5_ret_principal(sp, principal);
|
||||
krb5_storage_free(sp);
|
||||
fcc_unlock(context, fd);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fcc_end_get (krb5_context context,
|
||||
krb5_ccache id,
|
||||
krb5_cc_cursor *cursor);
|
||||
|
||||
static krb5_error_code
|
||||
fcc_get_first (krb5_context context,
|
||||
krb5_ccache id,
|
||||
@@ -448,16 +563,22 @@ fcc_get_first (krb5_context context,
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_principal principal;
|
||||
krb5_fcache *f = FCACHE(id);
|
||||
|
||||
*cursor = malloc(sizeof(struct fcc_cursor));
|
||||
|
||||
ret = init_fcc (context, f, &FCC_CURSOR(*cursor)->sp,
|
||||
ret = init_fcc (context, id, &FCC_CURSOR(*cursor)->sp,
|
||||
&FCC_CURSOR(*cursor)->fd);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
free(*cursor);
|
||||
return ret;
|
||||
krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal);
|
||||
}
|
||||
ret = krb5_ret_principal (FCC_CURSOR(*cursor)->sp, &principal);
|
||||
if(ret) {
|
||||
fcc_end_get(context, id, cursor);
|
||||
return ret;
|
||||
}
|
||||
krb5_free_principal (context, principal);
|
||||
fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -467,7 +588,14 @@ fcc_get_next (krb5_context context,
|
||||
krb5_cc_cursor *cursor,
|
||||
krb5_creds *creds)
|
||||
{
|
||||
return fcc_read_cred (context, FCACHE(id), FCC_CURSOR(*cursor)->sp, creds);
|
||||
krb5_error_code ret;
|
||||
if((ret = fcc_lock(context, id, FCC_CURSOR(*cursor)->fd, FALSE)) != 0)
|
||||
return ret;
|
||||
|
||||
ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds);
|
||||
|
||||
fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
@@ -478,6 +606,7 @@ fcc_end_get (krb5_context context,
|
||||
krb5_storage_free(FCC_CURSOR(*cursor)->sp);
|
||||
close (FCC_CURSOR(*cursor)->fd);
|
||||
free(*cursor);
|
||||
*cursor = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user