From 6b45c3512e37cc2ea8c87f1e96b02bec25967544 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Tue, 22 Mar 2022 17:00:23 -0500 Subject: [PATCH] kadmin: LIST interrupt message needs no reply The online LIST interrupt message is a NOP, but it's expected to not have a reply (the server doesn't send one if it receives it before the LIST finishes). However, if the interrupt message arrives after the LIST finished, then it does get a reply, and this causes the client to get out of step with the server. Fixes include: 1) flavor the interrupt NOP to make sure it never gets a reply, 2) introduce a new kadm_list_interrtupt message that is like a NOP that produces no reply 3) always consume -after the LIST ends- a reply to any list interrupt NOP on the client side. This implements (1). --- kadmin/server.c | 12 +++++++++++- lib/kadm5/get_princs_c.c | 12 ++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/kadmin/server.c b/kadmin/server.c index 94c2ae3c5..281822a30 100644 --- a/kadmin/server.c +++ b/kadmin/server.c @@ -238,6 +238,15 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, * interrupt a long-running LIST operation. */ op = "NOP"; + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0 && tmp == 0) { + /* + * Reply not wanted. This would be a LIST interrupt request. + */ + krb5_storage_free(rsp); + krb5_storage_free(sp); + return 0; + } ret_sp = krb5_store_int32(rsp, ret = 0); break; } @@ -1027,7 +1036,8 @@ v5_loop (krb5_context contextp, if (ret) krb5_err(contextp, 1, ret, "kadmind_dispatch"); krb5_data_free(&in); - ret = krb5_write_priv_message(contextp, ac, &fd, &out); + if (out.length) + ret = krb5_write_priv_message(contextp, ac, &fd, &out); krb5_data_free(&out); if(ret) krb5_err(contextp, 1, ret, "krb5_write_priv_message"); diff --git a/lib/kadm5/get_princs_c.c b/lib/kadm5/get_princs_c.c index 82994a8e3..93d7ce7ed 100644 --- a/lib/kadm5/get_princs_c.c +++ b/lib/kadm5/get_princs_c.c @@ -232,10 +232,18 @@ kadm5_c_iter_principals(void *server_handle, if (!stop) { stop = cb(cbdata, princ); if (stop) { - /* Tell the server to stop */ + /* + * Tell the server to stop. + * + * We use a NOP for this, but with a payload that says + * "don't reply to the NOP" just in case the NOP + * arrives and is processed _after_ the LISTing has + * finished. + */ krb5_storage_free(sp); if ((sp = krb5_storage_emem()) && - krb5_store_int32(sp, kadm_nop) == 0) + krb5_store_int32(sp, kadm_nop) == 0 && + krb5_store_int32(sp, 0)) (void) _kadm5_client_send(context, sp); } }