Make fcc_remove_cred() better
Don't use a memory ccache go between, just copy all but the matching credential(s).
This commit is contained in:
@@ -42,6 +42,8 @@ typedef struct krb5_fcache{
|
|||||||
|
|
||||||
struct fcc_cursor {
|
struct fcc_cursor {
|
||||||
int fd;
|
int fd;
|
||||||
|
off_t cred_start;
|
||||||
|
off_t cred_end;
|
||||||
krb5_storage *sp;
|
krb5_storage *sp;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -398,6 +400,8 @@ fcc_open(krb5_context context,
|
|||||||
int strict_checking;
|
int strict_checking;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
*fd_ret = -1;
|
||||||
|
|
||||||
if (FCACHE(id) == NULL)
|
if (FCACHE(id) == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
@@ -827,11 +831,16 @@ fcc_get_next (krb5_context context,
|
|||||||
|
|
||||||
if((ret = fcc_lock(context, id, FCC_CURSOR(*cursor)->fd, FALSE)) != 0)
|
if((ret = fcc_lock(context, id, FCC_CURSOR(*cursor)->fd, FALSE)) != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
FCC_CURSOR(*cursor)->cred_start = lseek(FCC_CURSOR(*cursor)->fd,
|
||||||
|
0, SEEK_CUR);
|
||||||
|
|
||||||
ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds);
|
ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds);
|
||||||
if (ret)
|
if (ret)
|
||||||
krb5_clear_error_message(context);
|
krb5_clear_error_message(context);
|
||||||
|
|
||||||
|
FCC_CURSOR(*cursor)->cred_end = lseek(FCC_CURSOR(*cursor)->fd,
|
||||||
|
0, SEEK_CUR);
|
||||||
|
|
||||||
fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
|
fcc_unlock(context, FCC_CURSOR(*cursor)->fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -855,73 +864,112 @@ fcc_end_get (krb5_context context,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void KRB5_CALLCONV
|
||||||
|
cred_delete(krb5_context context,
|
||||||
|
krb5_ccache id,
|
||||||
|
krb5_cc_cursor *cursor,
|
||||||
|
krb5_creds *cred)
|
||||||
|
{
|
||||||
|
krb5_error_code ret = EINVAL;
|
||||||
|
krb5_storage *sp;
|
||||||
|
off_t new_cred_sz;
|
||||||
|
int fd;
|
||||||
|
krb5_const_realm srealm = krb5_principal_get_realm(context, cred->server);
|
||||||
|
|
||||||
|
heim_assert(FCC_CURSOR(*cursor)->cred_start < FCC_CURSOR(*cursor)->cred_end,
|
||||||
|
"fcache internal error");
|
||||||
|
|
||||||
|
/* Mark the cred for deletion */
|
||||||
|
cred->times.endtime = 1;
|
||||||
|
|
||||||
|
/* Further mark config creds because we don't check their endtimes */
|
||||||
|
if (srealm && strcmp(srealm, "X-CACHECONF:") == 0) {
|
||||||
|
ret = krb5_principal_set_realm(context, cred->server, "X-RMED-CONF:");
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp = krb5_storage_emem();
|
||||||
|
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, TRUE,
|
||||||
|
"libdefaults",
|
||||||
|
"fcc-mit-ticketflags",
|
||||||
|
NULL))
|
||||||
|
krb5_storage_set_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER);
|
||||||
|
|
||||||
|
ret = krb5_store_creds(sp, cred);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* The new cred must be the same size as the old cred */
|
||||||
|
new_cred_sz = krb5_storage_seek(sp, 0, SEEK_END);
|
||||||
|
if (new_cred_sz !=
|
||||||
|
(FCC_CURSOR(*cursor)->cred_end - FCC_CURSOR(*cursor)->cred_start)) {
|
||||||
|
/* XXX This really can't happen. Assert like above? */
|
||||||
|
krb5_set_error_message(context, EINVAL,
|
||||||
|
N_("Credential deletion failed on ccache "
|
||||||
|
"FILE:%s: new credential size did not "
|
||||||
|
"match old credential size", ""),
|
||||||
|
FILENAME(id));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fcc_open(context, id, "remove_cred", &fd,
|
||||||
|
O_WRONLY | O_BINARY | O_CLOEXEC | O_NOFOLLOW, 0);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (lseek(fd, FCC_CURSOR(*cursor)->cred_start, SEEK_SET) == (off_t)-1) {
|
||||||
|
char buf[128];
|
||||||
|
rk_strerror_r(ret, buf, sizeof(buf));
|
||||||
|
ret = errno;
|
||||||
|
krb5_set_error_message(context, ret, N_("seek %s: %s", ""),
|
||||||
|
FILENAME(id), buf);
|
||||||
|
} else {
|
||||||
|
ret = write_storage(context, sp, fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fcc_unlock(context, fd);
|
||||||
|
if (close(fd) < 0) {
|
||||||
|
if (ret == 0) {
|
||||||
|
char buf[128];
|
||||||
|
rk_strerror_r(ret, buf, sizeof(buf));
|
||||||
|
ret = errno;
|
||||||
|
krb5_set_error_message(context, ret, N_("close %s: %s", ""),
|
||||||
|
FILENAME(id), buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
krb5_storage_free(sp);
|
||||||
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
fcc_remove_cred(krb5_context context,
|
fcc_remove_cred(krb5_context context,
|
||||||
krb5_ccache id,
|
krb5_ccache id,
|
||||||
krb5_flags which,
|
krb5_flags which,
|
||||||
krb5_creds *cred)
|
krb5_creds *mcred)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
krb5_ccache copy, newfile;
|
krb5_cc_cursor cursor;
|
||||||
char *newname = NULL;
|
krb5_creds found_cred;
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (FCACHE(id) == NULL)
|
if (FCACHE(id) == NULL)
|
||||||
return krb5_einval(context, 2);
|
return krb5_einval(context, 2);
|
||||||
|
|
||||||
ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, ©);
|
ret = krb5_cc_start_seq_get(context, id, &cursor);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
while ((ret = krb5_cc_next_cred(context, id, &cursor, &found_cred)) == 0) {
|
||||||
ret = krb5_cc_copy_cache(context, id, copy);
|
if (!krb5_compare_creds(context, which, mcred, &found_cred))
|
||||||
if (ret) {
|
continue;
|
||||||
krb5_cc_destroy(context, copy);
|
cred_delete(context, id, &cursor, &found_cred);
|
||||||
|
krb5_free_cred_contents(context, &found_cred);
|
||||||
|
}
|
||||||
|
if (ret && ret != KRB5_CC_END) {
|
||||||
|
krb5_cc_end_seq_get(context, id, &cursor);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
return krb5_cc_end_seq_get(context, id, &cursor);
|
||||||
ret = krb5_cc_remove_cred(context, copy, which, cred);
|
|
||||||
if (ret) {
|
|
||||||
krb5_cc_destroy(context, copy);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = asprintf(&newname, "FILE:%s.XXXXXX", FILENAME(id));
|
|
||||||
if (ret < 0 || newname == NULL) {
|
|
||||||
krb5_cc_destroy(context, copy);
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = mkstemp(&newname[5]);
|
|
||||||
if (fd < 0) {
|
|
||||||
ret = errno;
|
|
||||||
krb5_cc_destroy(context, copy);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
ret = krb5_cc_resolve(context, newname, &newfile);
|
|
||||||
if (ret) {
|
|
||||||
unlink(&newname[5]);
|
|
||||||
free(newname);
|
|
||||||
krb5_cc_destroy(context, copy);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = krb5_cc_copy_cache(context, copy, newfile);
|
|
||||||
krb5_cc_destroy(context, copy);
|
|
||||||
if (ret) {
|
|
||||||
free(newname);
|
|
||||||
krb5_cc_destroy(context, newfile);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = rk_rename(&newname[5], FILENAME(id));
|
|
||||||
if (ret)
|
|
||||||
ret = errno;
|
|
||||||
free(newname);
|
|
||||||
krb5_cc_close(context, newfile);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code KRB5_CALLCONV
|
static krb5_error_code KRB5_CALLCONV
|
||||||
|
|||||||
Reference in New Issue
Block a user