MINOR: acme: introduce acme_challenge_ready() for reuse outside the CLI

Extract the challenge-readiness logic from cli_acme_chall_ready_parse()
into a new acme_challenge_ready(crt, dns) function so it can be called
from other contexts such as Lua event handlers.

It slightly changes the messages on the CLI.
This commit is contained in:
William Lallemand 2026-06-10 11:29:18 +02:00
parent 0a90ff6b3d
commit 9e60d35aaf
2 changed files with 61 additions and 38 deletions

View file

@ -5,6 +5,7 @@
#include <haproxy/ssl_ckch-t.h>
int ckch_conf_acme_init(void *value, char *buf, struct ckch_store *s, int cli, const char *filename, int linenum, char **err);
int acme_challenge_ready(const char *crt, const char *dns);
EVP_PKEY *acme_gen_tmp_pkey();
X509 *acme_gen_tmp_x509();

View file

@ -3506,16 +3506,64 @@ err:
return cli_dynerr(appctx, errmsg);
}
/*
* Change the readiness of an ACME challenge per couple <crt>+<dns>
* Return:
* - -2 if the crt was not found
* - -1 if an non-ready couple crt+dns wasn't not found
* - 0 if the challenges are ready for the certificate
* - > 0 with the number of remaining challenge to enable
*/
int acme_challenge_ready(const char *crt, const char *dns)
{
struct ebmb_node *node = NULL;
struct acme_ctx *ctx = NULL;
struct acme_auth *auth = NULL;
int found = 0;
int remain = 0;
HA_RWLOCK_WRLOCK(OTHER_LOCK, &acme_lock);
node = ebst_lookup(&acme_tasks, crt);
if (!node) {
HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &acme_lock);
return -2;
}
ctx = ebmb_entry(node, struct acme_ctx, node);
if (ctx->cfg->cond_ready & ACME_RDY_CLI)
auth = ctx->auths;
while (auth) {
if (strncmp(dns, auth->dns.ptr, auth->dns.len) == 0) {
if ((auth->ready & ACME_RDY_CLI) == 0) {
auth->ready |= ACME_RDY_CLI;
found++;
}
}
if ((auth->ready & ACME_RDY_CLI) == 0)
remain++;
auth = auth->next;
}
/* no remaining challenge to ready: wake the task only if it is
* currently suspended in ACME_CLI_WAIT, not in the middle of an
* HTTP exchange.
*/
if (!remain && ctx->state == ACME_CLI_WAIT)
task_wakeup(ctx->task, TASK_WOKEN_MSG);
HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &acme_lock);
if (!found)
return -1;
return remain;
}
static int cli_acme_chall_ready_parse(char **args, char *payload, struct appctx *appctx, void *private)
{
char *msg = NULL;
const char *crt;
const char *dns;
struct acme_ctx *ctx = NULL;
struct acme_auth *auth = NULL;
int found = 0;
int remain = 0;
struct ebmb_node *node = NULL;
int ret;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
@ -3528,39 +3576,13 @@ static int cli_acme_chall_ready_parse(char **args, char *payload, struct appctx
crt = args[2];
dns = args[4];
HA_RWLOCK_WRLOCK(OTHER_LOCK, &acme_lock);
node = ebst_lookup(&acme_tasks, crt);
if (node) {
ctx = ebmb_entry(node, struct acme_ctx, node);
if (ctx->cfg->cond_ready & ACME_RDY_CLI)
auth = ctx->auths;
while (auth) {
if (strncmp(dns, auth->dns.ptr, auth->dns.len) == 0) {
if (!(auth->ready & ACME_RDY_CLI)) {
auth->ready |= ACME_RDY_CLI;
found++;
} else {
memprintf(&msg, "ACME challenge for crt \"%s\" and dns \"%s\" was already READY !\n", crt, dns);
}
}
if ((auth->ready & ACME_RDY_CLI) == 0)
remain++;
auth = auth->next;
}
}
HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &acme_lock);
if (!found) {
if (!msg)
memprintf(&msg, "Couldn't find an ACME task using crt \"%s\" and dns \"%s\" to set as ready!\n", crt, dns);
goto err;
} else {
if (!remain) {
if (ctx)
task_wakeup(ctx->task, TASK_WOKEN_MSG);
return cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "%d '%s' challenge(s) ready! All challenges ready, starting challenges validation!", found, dns));
} else {
return cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "%d '%s' challenge(s) ready! Remaining challenges to deploy: %d", found, dns, remain));
}
ret = acme_challenge_ready(crt, dns);
if (ret < 0) {
return cli_dynerr(appctx, memprintf(&msg, "Couldn't find an ACME task using crt \"%s\" and dns \"%s\" to set as ready!\n", crt, dns));
} else if (ret == 0) {
return cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "'%s' challenges ready! All challenges ready, starting challenges validation!", crt));
} else if (ret > 0) {
return cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "'%s' challenge(s) ready! Remaining challenges to deploy: %d", crt, ret));
}
err: