diff --git a/src/responder/kcm/kcm_renew.c b/src/responder/kcm/kcm_renew.c index 32eccf4b48..f65b1d5971 100644 --- a/src/responder/kcm/kcm_renew.c +++ b/src/responder/kcm/kcm_renew.c @@ -580,10 +580,15 @@ static errno_t kcm_creds_check_times(TALLOC_CTX *mem_ctx, auth_data->upn = talloc_strdup(auth_data, client_name); auth_data->uid = cc->owner.uid; auth_data->gid = cc->owner.gid; - auth_data->ccname = cc->name; - if (auth_data->upn == NULL) { + /* cc is owned by the caller tmp_ctx and freed when the renew scan + * returns; the renew callback runs later on the event loop, so + * the ccache name must be copied onto auth_data. */ + auth_data->ccname = talloc_strdup(auth_data, cc->name); + if (auth_data->upn == NULL || auth_data->ccname == NULL) { ret = ENOMEM; - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to allocate auth_data->upn for renewals\n"); + DEBUG(SSSDBG_CRIT_FAILURE, + "Unable to allocate auth_data for renewals\n"); + talloc_free(auth_data); goto done; } @@ -591,6 +596,7 @@ static errno_t kcm_creds_check_times(TALLOC_CTX *mem_ctx, if (imm == NULL) { ret = ENOMEM; DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed\n"); + talloc_free(auth_data); goto done; } diff --git a/src/tests/system/tests/test_kcm.py b/src/tests/system/tests/test_kcm.py index 02eb1fc7a3..6847c26681 100644 --- a/src/tests/system/tests/test_kcm.py +++ b/src/tests/system/tests/test_kcm.py @@ -383,12 +383,21 @@ def test_kcm__tgt_renewal_updates_ticket_as_configured(client: Client, kdc: KDC) with client.ssh("tuser", "Secret123") as ssh: with client.auth.kerberos(ssh) as krb: - # KCM runs renew only after ~50% of ticket lifetime (kcm_creds_check_times). - # Keep lifetime short for faster test runs; poll past half-life + slack. - krb.kinit("tuser", password="Secret123", args=["-r", "5s", "-l", "5s"]) + # KCM renews only after ~50% of ticket lifetime (kcm_creds_check_times), + # and only while the ticket is still valid. Use renew_till > lifetime so + # renew_till >= endtime holds, and leave a few renew_interval ticks after + # half-life for the async krb5_child path. + lifetime_s = 10 + renewable_s = 30 + krb.kinit( + "tuser", + password="Secret123", + args=["-r", f"{renewable_s}s", "-l", f"{lifetime_s}s"], + ) init_start, init_end = krb.list_tgt_times(kdc.realm) - deadline = time.monotonic() + 9.0 + # Half-life + a few renew_interval ticks + slack for child latency. + deadline = time.monotonic() + (lifetime_s / 2) + 5.0 renew_start, renew_end = init_start, init_end while time.monotonic() < deadline: time.sleep(0.5)