Make ccache init atomic

This commit is contained in:
Nicolas Williams
2019-09-06 18:15:20 -05:00
parent ec84667763
commit e163bfd81b

View File

@@ -37,6 +37,7 @@
typedef struct krb5_fcache{
char *filename;
char *tmpfn;
int version;
}krb5_fcache;
@@ -57,6 +58,7 @@ struct fcc_cursor {
#define FCACHE(X) ((krb5_fcache*)(X)->data.data)
#define FILENAME(X) (FCACHE(X)->filename)
#define TMPFILENAME(X) (FCACHE(X)->tmpfn)
#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)
{
krb5_fcache *f;
f = malloc(sizeof(*f));
f = calloc(1, sizeof(*f));
if(f == NULL) {
krb5_set_error_message(context, KRB5_CC_NOMEM,
N_("malloc: out of memory", ""));
return KRB5_CC_NOMEM;
}
f->tmpfn = NULL;
f->filename = strdup(res);
if(f->filename == NULL){
free(f);
@@ -316,12 +319,13 @@ fcc_gen_new(krb5_context context, krb5_ccache *id)
krb5_fcache *f;
int fd;
f = malloc(sizeof(*f));
f = calloc(1, sizeof(*f));
if(f == NULL) {
krb5_set_error_message(context, KRB5_CC_NOMEM,
N_("malloc: out of memory", ""));
return KRB5_CC_NOMEM;
}
f->tmpfn = NULL;
ret = asprintf(&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT);
if(ret < 0 || file == NULL) {
free(f);
@@ -338,7 +342,7 @@ fcc_gen_new(krb5_context context, krb5_ccache *id)
file = exp_file;
fd = mkstemp(exp_file);
fd = mkostemp(exp_file, O_CLOEXEC);
if(fd < 0) {
ret = (krb5_error_code)errno;
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)
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 &&
(context->flags & KRB5_CTX_F_FCACHE_STRICT_CHECKING) != 0;
@@ -537,8 +555,10 @@ fcc_initialize(krb5_context context,
if (f == NULL)
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);
if(ret)
return ret;
@@ -601,7 +621,10 @@ fcc_close(krb5_context context,
if (FCACHE(id) == NULL)
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);
return 0;
}
@@ -613,6 +636,11 @@ fcc_destroy(krb5_context context,
if (FCACHE(id) == NULL)
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));
}
@@ -649,6 +677,21 @@ fcc_store_cred(krb5_context context,
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;
}
@@ -840,12 +883,11 @@ fcc_get_first (krb5_context context,
if (FCACHE(id) == NULL)
return krb5_einval(context, 2);
*cursor = malloc(sizeof(struct fcc_cursor));
*cursor = calloc(1, sizeof(struct fcc_cursor));
if (*cursor == NULL) {
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
return ENOMEM;
}
memset(*cursor, 0, sizeof(struct fcc_cursor));
ret = init_fcc(context, id, "get-first", &FCC_CURSOR(*cursor)->sp,
&FCC_CURSOR(*cursor)->fd, NULL);