]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: acme: provider-name for dpapi sink
authorWilliam Lallemand <wlallemand@haproxy.com>
Fri, 26 Sep 2025 08:09:27 +0000 (10:09 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Fri, 26 Sep 2025 08:23:35 +0000 (10:23 +0200)
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",$
       [...]

include/haproxy/acme-t.h
src/acme.c

index 62121ef1d84251928b7fa5e9bc45ddcac54feace..6babf6d93e1d54ab1db7e960d23f6575ba2ad370 100644 (file)
@@ -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;
 };
 
index abf79b846d0466637d1c3cd5dcce4cebf307a3ef..dcd26c8cd20a8af33bae7f10df824074891e352d 100644 (file)
@@ -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);