From: William Lallemand Date: Fri, 26 Sep 2025 08:09:27 +0000 (+0200) Subject: MINOR: acme: provider-name for dpapi sink X-Git-Tag: v3.3-dev9~34 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3e72a9f6185d0538b84fa891fd8e622526a56f62;p=thirdparty%2Fhaproxy.git MINOR: acme: provider-name for dpapi sink Like "acme-vars", the "provider-name" in the acme section is used in case of DNS-01 challenge and is sent to the dpapi sink. This is used to pass the name of a DNS provider in order to chose the DNS API to use. This patch implements the cfg_parse_acme_vars_provider() which parses either acme-vars or provider-name options and escape their strings. Example: $ ( echo "@@1 show events dpapi -w -0"; cat - ) | socat /tmp/master.sock - | cat -e <0>2025-09-18T17:53:58.831140+02:00 acme deploy foobpar.pem thumbprint gDvbPL3w4J4rxb8gj20mGEgtuicpvltnTl6j1kSZ3vQ$ acme-vars "var1=foobar\"toto\",var2=var2"$ provider-name "godaddy"$ {$ "identifier": {$ "type": "dns",$ "value": "example.com"$ },$ "status": "pending",$ "expires": "2025-09-25T14:41:57Z",$ [...] --- diff --git a/include/haproxy/acme-t.h b/include/haproxy/acme-t.h index 62121ef1d..6babf6d93 100644 --- a/include/haproxy/acme-t.h +++ b/include/haproxy/acme-t.h @@ -28,6 +28,7 @@ struct acme_cfg { } key; char *challenge; /* HTTP-01, DNS-01, etc */ char *vars; /* variables put in the dpapi sink */ + char *provider; /* DNS provider put in the dpapi sink */ struct acme_cfg *next; }; diff --git a/src/acme.c b/src/acme.c index abf79b846..dcd26c8cd 100644 --- a/src/acme.c +++ b/src/acme.c @@ -439,56 +439,77 @@ static int cfg_parse_acme_kws(char **args, int section_type, struct proxy *curpx ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum); goto out; } - } else if (strcmp(args[0], "acme-vars") == 0) { - /* save acme-vars */ - char *src = args[1]; - char *dst = NULL; - int i = 0; - int len; + } else if (*args[0] != 0) { + ha_alert("parsing [%s:%d]: unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } +out: + free(errmsg); + return err_code; +} - if (!*args[1]) { - ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - if (alertif_too_many_args(1, file, linenum, args, &err_code)) - goto out; - len = strlen(src); - dst = malloc(len + 1); - if (!dst) - goto vars_end; - - /* escape the " character */ - while (*src) { - if (*src == '"') { - char *dst2 = NULL; - - len++; - dst2 = realloc(dst, len + 1); - if (!dst2) { - ha_free(&dst); - goto vars_end; - } - dst = dst2; - dst[i++] = '\\'; /* add escaping */ +/* parsing "acme-provider" and "acme-vars" and add escaping of double quotes */ +static int cfg_parse_acme_vars_provider(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, + const char *file, int linenum, char **err) +{ + int err_code = 0; + char *errmsg = NULL; + char **dst = NULL; + char *src = args[1]; + char *tmp = NULL; + int i = 0; + int len; + + if (strcmp(args[0], "acme-vars") == 0) { + dst = &cur_acme->vars; + } else if (strcmp(args[0], "provider-name") == 0) { + dst = &cur_acme->provider; + } + + free(*dst); + + if (!*args[1]) { + ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + if (alertif_too_many_args(1, file, linenum, args, &err_code)) + goto out; + + len = strlen(src); + tmp = malloc(len + 1); + if (!tmp) + goto vars_end; + + /* escape the " character */ + while (*src) { + if (*src == '"') { + char *tmp2 = NULL; + + len++; + tmp2 = realloc(tmp, len + 1); + if (!tmp2) { + ha_free(&tmp); + goto vars_end; } - dst[i++] = *src; - src++; + tmp = tmp2; + tmp[i++] = '\\'; /* add escaping */ } - dst[i] = '\0'; + tmp[i++] = *src; + src++; + } + tmp[i] = '\0'; + vars_end: - cur_acme->vars = dst; - if (!cur_acme->vars) { - err_code |= ERR_ALERT | ERR_FATAL; - ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum); - goto out; - } - } else if (*args[0] != 0) { - ha_alert("parsing [%s:%d]: unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection); + *dst = tmp; + if (!*dst) { err_code |= ERR_ALERT | ERR_FATAL; + ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum); goto out; } + out: free(errmsg); return err_code; @@ -753,6 +774,7 @@ void deinit_acme() ha_free(&acme_cfgs->account.file); ha_free(&acme_cfgs->account.thumbprint); ha_free(&acme_cfgs->vars); + ha_free(&acme_cfgs->provider); free(acme_cfgs); acme_cfgs = next; @@ -768,7 +790,8 @@ static struct cfg_kw_list cfg_kws_acme = {ILH, { { CFG_ACME, "bits", cfg_parse_acme_cfg_key }, { CFG_ACME, "curves", cfg_parse_acme_cfg_key }, { CFG_ACME, "map", cfg_parse_acme_kws }, - { CFG_ACME, "acme-vars", cfg_parse_acme_kws }, + { CFG_ACME, "acme-vars", cfg_parse_acme_vars_provider }, + { CFG_ACME, "provider-name", cfg_parse_acme_vars_provider }, { CFG_GLOBAL, "acme.scheduler", cfg_parse_global_acme_sched }, { 0, NULL, NULL }, }}; @@ -1631,7 +1654,7 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut /* compute a response for the TXT entry */ if (strcasecmp(ctx->cfg->challenge, "dns-01") == 0) { struct sink *dpapi; - struct ist line[10]; + struct ist line[13]; int nmsg = 0; if (acme_txt_record(ist(ctx->cfg->account.thumbprint), auth->token, &trash) == 0) { @@ -1649,6 +1672,11 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut line[nmsg++] = ist(ctx->cfg->account.thumbprint); line[nmsg++] = ist("\n"); + if (ctx->cfg->provider) { + line[nmsg++] = ist("provider-name \""); + line[nmsg++] = ist(ctx->cfg->provider); + line[nmsg++] = ist("\"\n"); + } if (ctx->cfg->vars) { line[nmsg++] = ist("acme-vars \""); line[nmsg++] = ist(ctx->cfg->vars);