kdc: Make --kdc-request-log-file concrrency-safe

Build the entry to write to the log file in memory, the write it with
O_APPEND.  This should make writes to the request log file safer in
multi-process KDC configurations.

Also, check results of krb5_store_*() functions (coverity alerted to
this).
This commit is contained in:
Nicolas Williams
2022-01-18 00:19:15 -06:00
parent d41467dcde
commit 1a08b3b47f

View File

@@ -469,58 +469,87 @@ krb5_kdc_save_request(krb5_context context,
{ {
krb5_storage *sp; krb5_storage *sp;
krb5_address a; krb5_address a;
int fd, ret; int fd = -1;
int ret = 0;
uint32_t t; uint32_t t;
krb5_data d; krb5_data d;
memset(&a, 0, sizeof(a)); memset(&a, 0, sizeof(a));
d.data = rk_UNCONST(buf); d.data = rk_UNCONST(buf); /* do not free here */
d.length = len; d.length = len;
t = _kdc_now.tv_sec; t = _kdc_now.tv_sec;
fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600); sp = krb5_storage_emem();
if (fd < 0) { if (sp == NULL)
int saved_errno = errno; ret = krb5_enomem(context);
krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn);
return saved_errno;
}
sp = krb5_storage_from_fd(fd); if (ret == 0)
close(fd); ret = krb5_sockaddr2address(context, sa, &a);
if (sp == NULL) { if (ret == 0)
krb5_set_error_message(context, ENOMEM, "Storage failed to open fd"); ret = krb5_store_uint32(sp, 1);
return ENOMEM; if (ret == 0)
} ret = krb5_store_uint32(sp, t);
if (ret == 0)
ret = krb5_sockaddr2address(context, sa, &a); ret = krb5_store_address(sp, a);
if (ret) if (ret == 0)
goto out; ret = krb5_store_data(sp, d);
d.length = 0;
krb5_store_uint32(sp, 1); d.data = NULL;
krb5_store_uint32(sp, t); if (ret == 0) {
krb5_store_address(sp, a);
krb5_store_data(sp, d);
{
Der_class cl; Der_class cl;
Der_type ty; Der_type ty;
unsigned int tag; unsigned int tag;
ret = der_get_tag (reply->data, reply->length, ret = der_get_tag (reply->data, reply->length,
&cl, &ty, &tag, NULL); &cl, &ty, &tag, NULL);
if (ret) { if (ret) {
krb5_store_uint32(sp, 0xffffffff); ret = krb5_store_uint32(sp, 0xffffffff);
krb5_store_uint32(sp, 0xffffffff); if (ret == 0)
} else { ret = krb5_store_uint32(sp, 0xffffffff);
krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0)); } else {
krb5_store_uint32(sp, tag); ret = krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0));
if (ret == 0)
ret = krb5_store_uint32(sp, tag);
} }
} }
krb5_free_address(context, &a); if (ret == 0)
out: ret = krb5_storage_to_data(sp, &d);
krb5_storage_free(sp); krb5_storage_free(sp);
sp = NULL;
return 0; /*
* We've got KDC concurrency, so we're going to try to do a single O_APPEND
* write(2). Hopefully we manage to write enough of the header that one
* can skip this request if it fails to write completely.
*/
if (ret == 0)
fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600);
if (fd < 0)
krb5_set_error_message(context, ret = errno, "Failed to open: %s", fn);
if (ret == 0) {
sp = krb5_storage_from_fd(fd);
if (sp == NULL)
krb5_set_error_message(context, ret = ENOMEM,
"Storage failed to open fd");
}
(void) close(fd);
if (ret == 0)
ret = krb5_store_data(sp, d);
krb5_free_address(context, &a);
/*
* krb5_storage_free() currently always returns 0, but for FDs it sets
* errno to whatever close() set it to if it failed.
*/
errno = 0;
if (ret == 0)
ret = krb5_storage_free(sp);
else
(void) krb5_storage_free(sp);
if (ret == 0 && errno)
ret = errno;
return ret;
} }
KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL