Make ccache init atomic
This commit is contained in:
@@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
typedef struct krb5_fcache{
|
typedef struct krb5_fcache{
|
||||||
char *filename;
|
char *filename;
|
||||||
|
char *tmpfn;
|
||||||
int version;
|
int version;
|
||||||
}krb5_fcache;
|
}krb5_fcache;
|
||||||
|
|
||||||
@@ -57,6 +58,7 @@ struct fcc_cursor {
|
|||||||
#define FCACHE(X) ((krb5_fcache*)(X)->data.data)
|
#define FCACHE(X) ((krb5_fcache*)(X)->data.data)
|
||||||
|
|
||||||
#define FILENAME(X) (FCACHE(X)->filename)
|
#define FILENAME(X) (FCACHE(X)->filename)
|
||||||
|
#define TMPFILENAME(X) (FCACHE(X)->tmpfn)
|
||||||
|
|
||||||
#define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
|
#define FCC_CURSOR(C) ((struct fcc_cursor*)(C))
|
||||||
|
|
||||||
@@ -185,12 +187,13 @@ static krb5_error_code KRB5_CALLCONV
|
|||||||
fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
fcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
||||||
{
|
{
|
||||||
krb5_fcache *f;
|
krb5_fcache *f;
|
||||||
f = malloc(sizeof(*f));
|
f = calloc(1, sizeof(*f));
|
||||||
if(f == NULL) {
|
if(f == NULL) {
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
||||||
N_("malloc: out of memory", ""));
|
N_("malloc: out of memory", ""));
|
||||||
return KRB5_CC_NOMEM;
|
return KRB5_CC_NOMEM;
|
||||||
}
|
}
|
||||||
|
f->tmpfn = NULL;
|
||||||
f->filename = strdup(res);
|
f->filename = strdup(res);
|
||||||
if(f->filename == NULL){
|
if(f->filename == NULL){
|
||||||
free(f);
|
free(f);
|
||||||
@@ -316,12 +319,13 @@ fcc_gen_new(krb5_context context, krb5_ccache *id)
|
|||||||
krb5_fcache *f;
|
krb5_fcache *f;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
f = malloc(sizeof(*f));
|
f = calloc(1, sizeof(*f));
|
||||||
if(f == NULL) {
|
if(f == NULL) {
|
||||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
||||||
N_("malloc: out of memory", ""));
|
N_("malloc: out of memory", ""));
|
||||||
return KRB5_CC_NOMEM;
|
return KRB5_CC_NOMEM;
|
||||||
}
|
}
|
||||||
|
f->tmpfn = NULL;
|
||||||
ret = asprintf(&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT);
|
ret = asprintf(&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT);
|
||||||
if(ret < 0 || file == NULL) {
|
if(ret < 0 || file == NULL) {
|
||||||
free(f);
|
free(f);
|
||||||
@@ -338,7 +342,7 @@ fcc_gen_new(krb5_context context, krb5_ccache *id)
|
|||||||
|
|
||||||
file = exp_file;
|
file = exp_file;
|
||||||
|
|
||||||
fd = mkstemp(exp_file);
|
fd = mkostemp(exp_file, O_CLOEXEC);
|
||||||
if(fd < 0) {
|
if(fd < 0) {
|
||||||
ret = (krb5_error_code)errno;
|
ret = (krb5_error_code)errno;
|
||||||
krb5_set_error_message(context, ret, N_("mkstemp %s failed", ""), exp_file);
|
krb5_set_error_message(context, ret, N_("mkstemp %s failed", ""), exp_file);
|
||||||
@@ -406,8 +410,22 @@ fcc_open(krb5_context context,
|
|||||||
if (FCACHE(id) == NULL)
|
if (FCACHE(id) == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
filename = FILENAME(id);
|
if ((flags & O_EXCL)) {
|
||||||
|
flags &= ~O_EXCL;
|
||||||
|
if (asprintf(&TMPFILENAME(id), "%s-XXXXXX", FILENAME(id)) < 0 ||
|
||||||
|
TMPFILENAME(id) == NULL)
|
||||||
|
return krb5_enomem(context);
|
||||||
|
if ((*fd_ret = mkostemp(TMPFILENAME(id), O_CLOEXEC)) == -1) {
|
||||||
|
free(TMPFILENAME(id));
|
||||||
|
TMPFILENAME(id) = NULL;
|
||||||
|
krb5_set_error_message(context, ret = errno,
|
||||||
|
N_("Refuses to open symlinks for caches FILE:%s", ""),
|
||||||
|
FILENAME(id));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = TMPFILENAME(id) ? TMPFILENAME(id) : FILENAME(id);
|
||||||
strict_checking = (flags & O_CREAT) == 0 &&
|
strict_checking = (flags & O_CREAT) == 0 &&
|
||||||
(context->flags & KRB5_CTX_F_FCACHE_STRICT_CHECKING) != 0;
|
(context->flags & KRB5_CTX_F_FCACHE_STRICT_CHECKING) != 0;
|
||||||
|
|
||||||
@@ -537,8 +555,10 @@ fcc_initialize(krb5_context context,
|
|||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
unlink (f->filename);
|
/*
|
||||||
|
* fcc_open() will notice the O_EXCL and will make a temporary file that
|
||||||
|
* will later be renamed into place.
|
||||||
|
*/
|
||||||
ret = fcc_open(context, id, "initialize", &fd, O_RDWR | O_CREAT | O_EXCL, 0600);
|
ret = fcc_open(context, id, "initialize", &fd, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||||
if(ret)
|
if(ret)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -601,7 +621,10 @@ fcc_close(krb5_context context,
|
|||||||
if (FCACHE(id) == NULL)
|
if (FCACHE(id) == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
free (FILENAME(id));
|
if (TMPFILENAME(id))
|
||||||
|
(void) unlink(TMPFILENAME(id));
|
||||||
|
free(TMPFILENAME(id));
|
||||||
|
free(FILENAME(id));
|
||||||
krb5_data_free(&id->data);
|
krb5_data_free(&id->data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -613,6 +636,11 @@ fcc_destroy(krb5_context context,
|
|||||||
if (FCACHE(id) == NULL)
|
if (FCACHE(id) == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
|
if (TMPFILENAME(id)) {
|
||||||
|
(void) _krb5_erase_file(context, TMPFILENAME(id));
|
||||||
|
free(TMPFILENAME(id));
|
||||||
|
TMPFILENAME(id) = NULL;
|
||||||
|
}
|
||||||
return _krb5_erase_file(context, FILENAME(id));
|
return _krb5_erase_file(context, FILENAME(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,6 +677,21 @@ fcc_store_cred(krb5_context context,
|
|||||||
FILENAME(id), buf);
|
FILENAME(id), buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ret == 0 && TMPFILENAME(id) &&
|
||||||
|
!krb5_is_config_principal(context, creds->server)) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Portability note: there's no need to have WIN32 or other code here
|
||||||
|
* for odd rename cases because rk_rename() is meant to handle that.
|
||||||
|
*/
|
||||||
|
ret = rk_rename(TMPFILENAME(id), FILENAME(id));
|
||||||
|
if (ret == 0) {
|
||||||
|
free(TMPFILENAME(id));
|
||||||
|
TMPFILENAME(id) = NULL;
|
||||||
|
} else {
|
||||||
|
ret = errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,12 +883,11 @@ fcc_get_first (krb5_context context,
|
|||||||
if (FCACHE(id) == NULL)
|
if (FCACHE(id) == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
*cursor = malloc(sizeof(struct fcc_cursor));
|
*cursor = calloc(1, sizeof(struct fcc_cursor));
|
||||||
if (*cursor == NULL) {
|
if (*cursor == NULL) {
|
||||||
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
|
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
memset(*cursor, 0, sizeof(struct fcc_cursor));
|
|
||||||
|
|
||||||
ret = init_fcc(context, id, "get-first", &FCC_CURSOR(*cursor)->sp,
|
ret = init_fcc(context, id, "get-first", &FCC_CURSOR(*cursor)->sp,
|
||||||
&FCC_CURSOR(*cursor)->fd, NULL);
|
&FCC_CURSOR(*cursor)->fd, NULL);
|
||||||
|
Reference in New Issue
Block a user