REORG: ssl: move the crt-list CLI functions in src/ssl_crtlist.c

Move the crtlist functions for the CLI to src/ssl_crtlist.c
This commit is contained in:
William Lallemand 2020-05-13 17:23:59 +02:00 committed by William Lallemand
parent fa1d8b4eaa
commit c756bbd3df
4 changed files with 708 additions and 686 deletions

View File

@ -54,6 +54,8 @@ void ckch_store_free(struct ckch_store *store);
void ckch_inst_free(struct ckch_inst *inst);
struct ckch_inst *ckch_inst_new();
int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct bind_conf *bind_conf,
struct ssl_bind_conf *ssl_conf, char **sni_filter, int fcount, struct ckch_inst **ckchi, char **err);
#endif /* USE_OPENSSL */
#endif /* _PROTO_SSL_CRTLIST_H */

View File

@ -35,9 +35,12 @@
extern int sslconns;
extern int totalsslconns;
extern struct eb_root ckchs_tree;
extern struct eb_root crtlists_tree;
extern int sctl_ex_index;
extern struct global_ssl global_ssl;
extern struct ssl_bind_kw ssl_bind_kws[];
extern struct methodVersions methodVersions[];
__decl_hathreads(extern HA_SPINLOCK_T ckch_lock);
/* boolean, returns true if connection is over SSL */
static inline
@ -92,7 +95,7 @@ SSL_CTX *ssl_sock_assign_generated_cert(unsigned int key, struct bind_conf *bind
SSL_CTX *ssl_sock_get_generated_cert(unsigned int key, struct bind_conf *bind_conf);
int ssl_sock_set_generated_cert(SSL_CTX *ctx, unsigned int key, struct bind_conf *bind_conf);
unsigned int ssl_sock_generated_cert_key(const void *data, size_t len);
void ssl_sock_load_cert_sni(struct ckch_inst *ckch_inst, struct bind_conf *bind_conf);
#if (HA_OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC) && !defined(LIBRESSL_VERSION_NUMBER)
void ssl_async_fd_handler(int fd);
void ssl_async_fd_free(int fd);

View File

@ -19,11 +19,16 @@
#include <dirent.h>
#include <ebpttree.h>
#include <ebsttree.h>
#include <types/cli.h>
#include <types/ssl_crtlist.h>
#include <types/ssl_ckch.h>
#include <types/ssl_sock.h>
#include <proto/channel.h>
#include <proto/cli.h>
#include <proto/stream_interface.h>
#include <proto/ssl_crtlist.h>
#include <proto/ssl_ckch.h>
#include <proto/ssl_sock.h>
@ -573,3 +578,697 @@ end:
}
/*
* Take an ssl_bind_conf structure and append the configuration line used to
* create it in the buffer
*/
static void dump_crtlist_sslconf(struct buffer *buf, const struct ssl_bind_conf *conf)
{
int space = 0;
if (conf == NULL)
return;
chunk_appendf(buf, " [");
#ifdef OPENSSL_NPN_NEGOTIATED
if (conf->npn_str) {
int len = conf->npn_len;
char *ptr = conf->npn_str;
int comma = 0;
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "npn ");
while (len) {
unsigned short size;
size = *ptr;
ptr++;
if (comma)
chunk_memcat(buf, ",", 1);
chunk_memcat(buf, ptr, size);
ptr += size;
len -= size + 1;
comma = 1;
}
chunk_memcat(buf, "", 1); /* finish with a \0 */
space++;
}
#endif
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if (conf->alpn_str) {
int len = conf->alpn_len;
char *ptr = conf->alpn_str;
int comma = 0;
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "alpn ");
while (len) {
unsigned short size;
size = *ptr;
ptr++;
if (comma)
chunk_memcat(buf, ",", 1);
chunk_memcat(buf, ptr, size);
ptr += size;
len -= size + 1;
comma = 1;
}
chunk_memcat(buf, "", 1); /* finish with a \0 */
space++;
}
#endif
/* verify */
{
if (conf->verify == SSL_SOCK_VERIFY_NONE) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify none");
space++;
} else if (conf->verify == SSL_SOCK_VERIFY_OPTIONAL) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify optional");
space++;
} else if (conf->verify == SSL_SOCK_VERIFY_REQUIRED) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify required");
space++;
}
}
if (conf->no_ca_names) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "no-ca-names");
space++;
}
if (conf->early_data) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "allow-0rtt");
space++;
}
if (conf->ca_file) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ca-file %s", conf->ca_file);
space++;
}
if (conf->crl_file) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "crl-file %s", conf->crl_file);
space++;
}
if (conf->ciphers) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ciphers %s", conf->ciphers);
space++;
}
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if (conf->ciphersuites) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ciphersuites %s", conf->ciphersuites);
space++;
}
#endif
if (conf->curves) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "curves %s", conf->curves);
space++;
}
if (conf->ecdhe) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ecdhe %s", conf->ecdhe);
space++;
}
/* the crt-lists only support ssl-min-ver and ssl-max-ver */
/* XXX: this part need to be revamp so we don't dump the default settings */
if (conf->ssl_methods.min) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ssl-min-ver %s", methodVersions[conf->ssl_methods.min].name);
space++;
}
if (conf->ssl_methods.max) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ssl-max-ver %s", methodVersions[conf->ssl_methods.max].name);
space++;
}
chunk_appendf(buf, "]");
return;
}
/* dump a list of filters */
static void dump_crtlist_filters(struct buffer *buf, struct crtlist_entry *entry)
{
int i;
if (!entry->fcount)
return;
for (i = 0; i < entry->fcount; i++) {
chunk_appendf(buf, " %s", entry->filters[i]);
}
return;
}
/************************** CLI functions ****************************/
/* CLI IO handler for '(show|dump) ssl crt-list' */
static int cli_io_handler_dump_crtlist(struct appctx *appctx)
{
struct buffer *trash = alloc_trash_chunk();
struct stream_interface *si = appctx->owner;
struct ebmb_node *lnode;
if (trash == NULL)
return 1;
/* dump the list of crt-lists */
lnode = appctx->ctx.cli.p1;
if (lnode == NULL)
lnode = ebmb_first(&crtlists_tree);
while (lnode) {
chunk_appendf(trash, "%s\n", lnode->key);
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
lnode = ebmb_next(lnode);
}
free_trash_chunk(trash);
return 1;
yield:
appctx->ctx.cli.p1 = lnode;
free_trash_chunk(trash);
return 0;
}
/* CLI IO handler for '(show|dump) ssl crt-list <filename>' */
static int cli_io_handler_dump_crtlist_entries(struct appctx *appctx)
{
struct buffer *trash = alloc_trash_chunk();
struct crtlist *crtlist;
struct stream_interface *si = appctx->owner;
struct crtlist_entry *entry;
if (trash == NULL)
return 1;
crtlist = ebmb_entry(appctx->ctx.cli.p0, struct crtlist, node);
entry = appctx->ctx.cli.p1;
if (entry == NULL) {
entry = LIST_ELEM((crtlist->ord_entries).n, typeof(entry), by_crtlist);
chunk_appendf(trash, "# %s\n", crtlist->node.key);
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
}
list_for_each_entry_from(entry, &crtlist->ord_entries, by_crtlist) {
struct ckch_store *store;
const char *filename;
store = entry->node.key;
filename = store->path;
chunk_appendf(trash, "%s", filename);
if (appctx->ctx.cli.i0 == 's') /* show */
chunk_appendf(trash, ":%d", entry->linenum);
dump_crtlist_sslconf(trash, entry->ssl_conf);
dump_crtlist_filters(trash, entry);
chunk_appendf(trash, "\n");
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
}
free_trash_chunk(trash);
return 1;
yield:
appctx->ctx.cli.p1 = entry;
free_trash_chunk(trash);
return 0;
}
/* CLI argument parser for '(show|dump) ssl crt-list' */
static int cli_parse_dump_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
{
struct ebmb_node *lnode;
char *filename = NULL;
int mode;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
appctx->ctx.cli.p0 = NULL;
appctx->ctx.cli.p1 = NULL;
if (*args[3] && !strcmp(args[3], "-n")) {
mode = 's';
filename = args[4];
} else {
mode = 'd';
filename = args[3];
}
if (mode == 's' && !*args[4])
return cli_err(appctx, "'show ssl crt-list -n' expects a filename or a directory\n");
if (filename && *filename) {
lnode = ebst_lookup(&crtlists_tree, filename);
if (lnode == NULL)
return cli_err(appctx, "didn't find the specified filename\n");
appctx->ctx.cli.p0 = lnode;
appctx->io_handler = cli_io_handler_dump_crtlist_entries;
}
appctx->ctx.cli.i0 = mode;
return 0;
}
/* release function of the "add ssl crt-list' command, free things and unlock
the spinlock */
static void cli_release_add_crtlist(struct appctx *appctx)
{
struct crtlist_entry *entry = appctx->ctx.cli.p1;
if (appctx->st2 != SETCERT_ST_FIN) {
struct ckch_inst *inst, *inst_s;
/* upon error free the ckch_inst and everything inside */
ebpt_delete(&entry->node);
LIST_DEL(&entry->by_crtlist);
LIST_DEL(&entry->by_ckch_store);
list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_ckchs) {
ckch_inst_free(inst);
}
crtlist_free_filters(entry->filters);
ssl_sock_free_ssl_conf(entry->ssl_conf);
free(entry->ssl_conf);
free(entry);
}
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
}
/* IO Handler for the "add ssl crt-list" command It adds a new entry in the
* crt-list and generates the ckch_insts for each bind_conf that uses this crt-list
*
* The logic is the same as the "commit ssl cert" command but without the
* freeing of the old structures, because there are none.
*/
static int cli_io_handler_add_crtlist(struct appctx *appctx)
{
struct bind_conf_list *bind_conf_node;
struct stream_interface *si = appctx->owner;
struct crtlist *crtlist = appctx->ctx.cli.p0;
struct crtlist_entry *entry = appctx->ctx.cli.p1;
struct ckch_store *store = entry->node.key;
struct buffer *trash = alloc_trash_chunk();
struct ckch_inst *new_inst;
char *err = NULL;
int i = 0;
int errcode = 0;
if (trash == NULL)
goto error;
/* for each bind_conf which use the crt-list, a new ckch_inst must be
* created.
*/
if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
goto error;
while (1) {
switch (appctx->st2) {
case SETCERT_ST_INIT:
/* This state just print the update message */
chunk_printf(trash, "Inserting certificate '%s' in crt-list '%s'", store->path, crtlist->node.key);
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
appctx->st2 = SETCERT_ST_GEN;
/* fallthrough */
case SETCERT_ST_GEN:
bind_conf_node = appctx->ctx.cli.p2; /* get the previous ptr from the yield */
if (bind_conf_node == NULL)
bind_conf_node = crtlist->bind_conf;
for (; bind_conf_node; bind_conf_node = bind_conf_node->next) {
struct bind_conf *bind_conf = bind_conf_node->bind_conf;
struct sni_ctx *sni;
/* yield every 10 generations */
if (i > 10) {
appctx->ctx.cli.p2 = bind_conf_node;
goto yield;
}
/* we don't support multi-cert bundles, only simple ones */
errcode |= ckch_inst_new_load_store(store->path, store, bind_conf, entry->ssl_conf, entry->filters, entry->fcount, &new_inst, &err);
if (errcode & ERR_CODE)
goto error;
/* we need to initialize the SSL_CTX generated */
/* this iterate on the newly generated SNIs in the new instance to prepare their SSL_CTX */
list_for_each_entry(sni, &new_inst->sni_ctx, by_ckch_inst) {
if (!sni->order) { /* we initialized only the first SSL_CTX because it's the same in the other sni_ctx's */
errcode |= ssl_sock_prepare_ctx(bind_conf, new_inst->ssl_conf, sni->ctx, &err);
if (errcode & ERR_CODE)
goto error;
}
}
/* display one dot for each new instance */
chunk_appendf(trash, ".");
i++;
LIST_ADDQ(&store->ckch_inst, &new_inst->by_ckchs);
}
appctx->st2 = SETCERT_ST_INSERT;
/* fallthrough */
case SETCERT_ST_INSERT:
/* insert SNIs in bind_conf */
list_for_each_entry(new_inst, &store->ckch_inst, by_ckchs) {
HA_RWLOCK_WRLOCK(SNI_LOCK, &new_inst->bind_conf->sni_lock);
ssl_sock_load_cert_sni(new_inst, new_inst->bind_conf);
HA_RWLOCK_WRUNLOCK(SNI_LOCK, &new_inst->bind_conf->sni_lock);
}
entry->linenum = ++crtlist->linecount;
appctx->st2 = SETCERT_ST_FIN;
goto end;
}
}
end:
chunk_appendf(trash, "\n");
if (errcode & ERR_WARN)
chunk_appendf(trash, "%s", err);
chunk_appendf(trash, "Success!\n");
if (ci_putchk(si_ic(si), trash) == -1)
si_rx_room_blk(si);
free_trash_chunk(trash);
/* success: call the release function and don't come back */
return 1;
yield:
/* store the state */
if (ci_putchk(si_ic(si), trash) == -1)
si_rx_room_blk(si);
free_trash_chunk(trash);
si_rx_endp_more(si); /* let's come back later */
return 0; /* should come back */
error:
/* spin unlock and free are done in the release function */
if (trash) {
chunk_appendf(trash, "\n%sFailed!\n", err);
if (ci_putchk(si_ic(si), trash) == -1)
si_rx_room_blk(si);
free_trash_chunk(trash);
}
/* error: call the release function and don't come back */
return 1;
}
/*
* Parse a "add ssl crt-list <crt-list> <certfile>" line.
* Filters and option must be passed through payload:
*/
static int cli_parse_add_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
{
int cfgerr = 0;
struct ckch_store *store;
char *err = NULL;
char path[MAXPATHLEN+1];
char *crtlist_path;
char *cert_path = NULL;
struct ebmb_node *eb;
struct ebpt_node *inserted;
struct crtlist *crtlist;
struct crtlist_entry *entry = NULL;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[3] || (!payload && !*args[4]))
return cli_err(appctx, "'add ssl crtlist' expects a filename and a certificate name\n");
crtlist_path = args[3];
if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
return cli_err(appctx, "Operations on certificates are currently locked!\n");
eb = ebst_lookup(&crtlists_tree, crtlist_path);
if (!eb) {
memprintf(&err, "crt-list '%s' does not exist!", crtlist_path);
goto error;
}
crtlist = ebmb_entry(eb, struct crtlist, node);
entry = crtlist_entry_new();
if (entry == NULL) {
memprintf(&err, "Not enough memory!");
goto error;
}
if (payload) {
char *lf;
lf = strrchr(payload, '\n');
if (lf) {
memprintf(&err, "only one line of payload is supported!");
goto error;
}
/* cert_path is filled here */
cfgerr |= crtlist_parse_line(payload, &cert_path, entry, "CLI", 1, &err);
if (cfgerr & ERR_CODE)
goto error;
} else {
cert_path = args[4];
}
if (!cert_path) {
memprintf(&err, "'add ssl crtlist' should contain the certificate name in the payload");
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
if (eb_gettag(crtlist->entries.b[EB_RGHT])) {
char *slash;
slash = strrchr(cert_path, '/');
if (!slash) {
memprintf(&err, "'%s' is a directory, certificate path '%s' must contain the directory path", (char *)crtlist->node.key, cert_path);
goto error;
}
/* temporary replace / by 0 to do an strcmp */
*slash = '\0';
if (strcmp(cert_path, (char*)crtlist->node.key) != 0) {
*slash = '/';
memprintf(&err, "'%s' is a directory, certificate path '%s' must contain the directory path", (char *)crtlist->node.key, cert_path);
goto error;
}
*slash = '/';
}
if (*cert_path != '/' && global_ssl.crt_base) {
if ((strlen(global_ssl.crt_base) + 1 + strlen(cert_path)) > MAXPATHLEN) {
memprintf(&err, "'%s' : path too long", cert_path);
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
snprintf(path, sizeof(path), "%s/%s", global_ssl.crt_base, cert_path);
cert_path = path;
}
store = ckchs_lookup(cert_path);
if (store == NULL) {
memprintf(&err, "certificate '%s' does not exist!", cert_path);
goto error;
}
if (store->multi) {
memprintf(&err, "certificate '%s' is a bundle. You can disable the bundle merging with the directive 'ssl-load-extra-files' in the global section.", cert_path);
goto error;
}
if (store->ckch == NULL || store->ckch->cert == NULL) {
memprintf(&err, "certificate '%s' is empty!", cert_path);
goto error;
}
/* check if it's possible to insert this new crtlist_entry */
entry->node.key = store;
inserted = ebpt_insert(&crtlist->entries, &entry->node);
if (inserted != &entry->node) {
memprintf(&err, "file already exists in this directory!");
goto error;
}
/* this is supposed to be a directory (EB_ROOT_UNIQUE), so no ssl_conf are allowed */
if ((entry->ssl_conf || entry->filters) && eb_gettag(crtlist->entries.b[EB_RGHT])) {
memprintf(&err, "this is a directory, SSL configuration and filters are not allowed");
goto error;
}
LIST_ADDQ(&crtlist->ord_entries, &entry->by_crtlist);
entry->crtlist = crtlist;
LIST_ADDQ(&store->crtlist_entry, &entry->by_ckch_store);
appctx->st2 = SETCERT_ST_INIT;
appctx->ctx.cli.p0 = crtlist;
appctx->ctx.cli.p1 = entry;
/* unlock is done in the release handler */
return 0;
error:
crtlist_entry_free(entry);
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
err = memprintf(&err, "Can't edit the crt-list: %s\n", err ? err : "");
return cli_dynerr(appctx, err);
}
/* Parse a "del ssl crt-list <crt-list> <certfile>" line. */
static int cli_parse_del_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
{
struct ckch_store *store;
char *err = NULL;
char *crtlist_path, *cert_path;
struct ebmb_node *ebmb;
struct ebpt_node *ebpt;
struct crtlist *crtlist;
struct crtlist_entry *entry = NULL;
struct ckch_inst *inst, *inst_s;
int linenum = 0;
char *colons;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[3] || !*args[4])
return cli_err(appctx, "'del ssl crtlist' expects a filename and a certificate name\n");
if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
return cli_err(appctx, "Can't delete!\nOperations on certificates are currently locked!\n");
crtlist_path = args[3];
cert_path = args[4];
colons = strchr(cert_path, ':');
if (colons) {
char *endptr;
linenum = strtol(colons + 1, &endptr, 10);
if (colons + 1 == endptr || *endptr != '\0') {
memprintf(&err, "wrong line number after colons in '%s'!", cert_path);
goto error;
}
*colons = '\0';
}
/* look for crtlist */
ebmb = ebst_lookup(&crtlists_tree, crtlist_path);
if (!ebmb) {
memprintf(&err, "crt-list '%s' does not exist!", crtlist_path);
goto error;
}
crtlist = ebmb_entry(ebmb, struct crtlist, node);
/* look for store */
store = ckchs_lookup(cert_path);
if (store == NULL) {
memprintf(&err, "certificate '%s' does not exist!", cert_path);
goto error;
}
if (store->multi) {
memprintf(&err, "certificate '%s' is a bundle. You can disable the bundle merging with the directive 'ssl-load-extra-files' in the global section.", cert_path);
goto error;
}
if (store->ckch == NULL || store->ckch->cert == NULL) {
memprintf(&err, "certificate '%s' is empty!", cert_path);
goto error;
}
ebpt = ebpt_lookup(&crtlist->entries, store);
if (!ebpt) {
memprintf(&err, "certificate '%s' can't be found in crt-list '%s'!", cert_path, crtlist_path);
goto error;
}
/* list the line number of entries for errors in err, and select the right ebpt */
for (; ebpt; ebpt = ebpt_next_dup(ebpt)) {
struct crtlist_entry *tmp;
tmp = ebpt_entry(ebpt, struct crtlist_entry, node);
memprintf(&err, "%s%s%d", err ? err : "", err ? ", " : "", tmp->linenum);
/* select the entry we wanted */
if (linenum == 0 || tmp->linenum == linenum) {
if (!entry)
entry = tmp;
}
}
/* we didn't found the specified entry */
if (!entry) {
memprintf(&err, "found a certificate '%s' but the line number is incorrect, please specify a correct line number preceded by colons (%s)!", cert_path, err ? err : NULL);
goto error;
}
/* we didn't specified a line number but there were several entries */
if (linenum == 0 && ebpt_next_dup(&entry->node)) {
memprintf(&err, "found the certificate '%s' in several entries, please specify a line number preceded by colons (%s)!", cert_path, err ? err : NULL);
goto error;
}
/* upon error free the ckch_inst and everything inside */
ebpt_delete(&entry->node);
LIST_DEL(&entry->by_crtlist);
LIST_DEL(&entry->by_ckch_store);
list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_crtlist_entry) {
struct sni_ctx *sni, *sni_s;
HA_RWLOCK_WRLOCK(SNI_LOCK, &inst->bind_conf->sni_lock);
list_for_each_entry_safe(sni, sni_s, &inst->sni_ctx, by_ckch_inst) {
ebmb_delete(&sni->name);
LIST_DEL(&sni->by_ckch_inst);
SSL_CTX_free(sni->ctx);
free(sni);
}
HA_RWLOCK_WRUNLOCK(SNI_LOCK, &inst->bind_conf->sni_lock);
LIST_DEL(&inst->by_ckchs);
free(inst);
}
crtlist_free_filters(entry->filters);
ssl_sock_free_ssl_conf(entry->ssl_conf);
free(entry->ssl_conf);
free(entry);
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
err = memprintf(&err, "Entry '%s' deleted in crtlist '%s'!\n", cert_path, crtlist_path);
return cli_dynmsg(appctx, LOG_NOTICE, err);
error:
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
err = memprintf(&err, "Can't delete the entry: %s\n", err ? err : "");
return cli_dynerr(appctx, err);
}
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
{ { "add", "ssl", "crt-list", NULL }, "add ssl crt-list <filename> <certfile> [options] : add a line <certfile> to a crt-list <filename>", cli_parse_add_crtlist, cli_io_handler_add_crtlist, cli_release_add_crtlist },
{ { "del", "ssl", "crt-list", NULL }, "del ssl crt-list <filename> <certfile[:line]> : delete a line <certfile> in a crt-list <filename>", cli_parse_del_crtlist, NULL, NULL },
{ { "show", "ssl", "crt-list", NULL }, "show ssl crt-list [-n] [<filename>] : show the list of crt-lists or the content of a crt-list <filename>", cli_parse_dump_crtlist, cli_io_handler_dump_crtlist, NULL },
{ { NULL }, NULL, NULL, NULL } }
};
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);

View File

@ -2744,7 +2744,7 @@ static int ckch_inst_add_cert_sni(SSL_CTX *ctx, struct ckch_inst *ckch_inst,
*
* *CAUTION*: The caller must lock the sni tree if called in multithreading mode
*/
static void ssl_sock_load_cert_sni(struct ckch_inst *ckch_inst, struct bind_conf *bind_conf)
void ssl_sock_load_cert_sni(struct ckch_inst *ckch_inst, struct bind_conf *bind_conf)
{
struct sni_ctx *sc0, *sc0b, *sc1;
@ -2801,7 +2801,7 @@ static void ssl_sock_load_cert_sni(struct ckch_inst *ckch_inst, struct bind_conf
struct eb_root ckchs_tree = EB_ROOT_UNIQUE;
/* tree of crtlist (crt-list/directory) */
static struct eb_root crtlists_tree = EB_ROOT_UNIQUE;
struct eb_root crtlists_tree = EB_ROOT_UNIQUE;
/* Loads Diffie-Hellman parameter from a ckchs to an SSL_CTX.
* If there is no DH parameter available in the ckchs, the global
@ -3317,7 +3317,7 @@ static int ckch_inst_new_load_multi_store(const char *path, struct ckch_store *c
* ERR_ALERT if the reason of the error is available in err
* ERR_WARN if a warning is available into err
*/
static int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct bind_conf *bind_conf,
int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct bind_conf *bind_conf,
struct ssl_bind_conf *ssl_conf, char **sni_filter, int fcount, struct ckch_inst **ckchi, char **err)
{
SSL_CTX *ctx;
@ -9555,685 +9555,6 @@ static int cli_parse_set_tlskeys(char **args, char *payload, struct appctx *appc
}
#endif
/*
* Take an ssl_bind_conf structure and append the configuration line used to
* create it in the buffer
*/
static void dump_crtlist_sslconf(struct buffer *buf, const struct ssl_bind_conf *conf)
{
int space = 0;
if (conf == NULL)
return;
chunk_appendf(buf, " [");
#ifdef OPENSSL_NPN_NEGOTIATED
if (conf->npn_str) {
int len = conf->npn_len;
char *ptr = conf->npn_str;
int comma = 0;
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "npn ");
while (len) {
unsigned short size;
size = *ptr;
ptr++;
if (comma)
chunk_memcat(buf, ",", 1);
chunk_memcat(buf, ptr, size);
ptr += size;
len -= size + 1;
comma = 1;
}
chunk_memcat(buf, "", 1); /* finish with a \0 */
space++;
}
#endif
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if (conf->alpn_str) {
int len = conf->alpn_len;
char *ptr = conf->alpn_str;
int comma = 0;
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "alpn ");
while (len) {
unsigned short size;
size = *ptr;
ptr++;
if (comma)
chunk_memcat(buf, ",", 1);
chunk_memcat(buf, ptr, size);
ptr += size;
len -= size + 1;
comma = 1;
}
chunk_memcat(buf, "", 1); /* finish with a \0 */
space++;
}
#endif
/* verify */
{
if (conf->verify == SSL_SOCK_VERIFY_NONE) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify none");
space++;
} else if (conf->verify == SSL_SOCK_VERIFY_OPTIONAL) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify optional");
space++;
} else if (conf->verify == SSL_SOCK_VERIFY_REQUIRED) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify required");
space++;
}
}
if (conf->no_ca_names) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "no-ca-names");
space++;
}
if (conf->early_data) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "allow-0rtt");
space++;
}
if (conf->ca_file) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ca-file %s", conf->ca_file);
space++;
}
if (conf->crl_file) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "crl-file %s", conf->crl_file);
space++;
}
if (conf->ciphers) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ciphers %s", conf->ciphers);
space++;
}
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if (conf->ciphersuites) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ciphersuites %s", conf->ciphersuites);
space++;
}
#endif
if (conf->curves) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "curves %s", conf->curves);
space++;
}
if (conf->ecdhe) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ecdhe %s", conf->ecdhe);
space++;
}
/* the crt-lists only support ssl-min-ver and ssl-max-ver */
/* XXX: this part need to be revamp so we don't dump the default settings */
if (conf->ssl_methods.min) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ssl-min-ver %s", methodVersions[conf->ssl_methods.min].name);
space++;
}
if (conf->ssl_methods.max) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ssl-max-ver %s", methodVersions[conf->ssl_methods.max].name);
space++;
}
chunk_appendf(buf, "]");
return;
}
/* dump a list of filters */
static void dump_crtlist_filters(struct buffer *buf, struct crtlist_entry *entry)
{
int i;
if (!entry->fcount)
return;
for (i = 0; i < entry->fcount; i++) {
chunk_appendf(buf, " %s", entry->filters[i]);
}
return;
}
/* CLI IO handler for '(show|dump) ssl crt-list' */
static int cli_io_handler_dump_crtlist(struct appctx *appctx)
{
struct buffer *trash = alloc_trash_chunk();
struct stream_interface *si = appctx->owner;
struct ebmb_node *lnode;
if (trash == NULL)
return 1;
/* dump the list of crt-lists */
lnode = appctx->ctx.cli.p1;
if (lnode == NULL)
lnode = ebmb_first(&crtlists_tree);
while (lnode) {
chunk_appendf(trash, "%s\n", lnode->key);
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
lnode = ebmb_next(lnode);
}
free_trash_chunk(trash);
return 1;
yield:
appctx->ctx.cli.p1 = lnode;
free_trash_chunk(trash);
return 0;
}
/* CLI IO handler for '(show|dump) ssl crt-list <filename>' */
static int cli_io_handler_dump_crtlist_entries(struct appctx *appctx)
{
struct buffer *trash = alloc_trash_chunk();
struct crtlist *crtlist;
struct stream_interface *si = appctx->owner;
struct crtlist_entry *entry;
if (trash == NULL)
return 1;
crtlist = ebmb_entry(appctx->ctx.cli.p0, struct crtlist, node);
entry = appctx->ctx.cli.p1;
if (entry == NULL) {
entry = LIST_ELEM((crtlist->ord_entries).n, typeof(entry), by_crtlist);
chunk_appendf(trash, "# %s\n", crtlist->node.key);
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
}
list_for_each_entry_from(entry, &crtlist->ord_entries, by_crtlist) {
struct ckch_store *store;
const char *filename;
store = entry->node.key;
filename = store->path;
chunk_appendf(trash, "%s", filename);
if (appctx->ctx.cli.i0 == 's') /* show */
chunk_appendf(trash, ":%d", entry->linenum);
dump_crtlist_sslconf(trash, entry->ssl_conf);
dump_crtlist_filters(trash, entry);
chunk_appendf(trash, "\n");
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
}
free_trash_chunk(trash);
return 1;
yield:
appctx->ctx.cli.p1 = entry;
free_trash_chunk(trash);
return 0;
}
/* CLI argument parser for '(show|dump) ssl crt-list' */
static int cli_parse_dump_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
{
struct ebmb_node *lnode;
char *filename = NULL;
int mode;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
appctx->ctx.cli.p0 = NULL;
appctx->ctx.cli.p1 = NULL;
if (*args[3] && !strcmp(args[3], "-n")) {
mode = 's';
filename = args[4];
} else {
mode = 'd';
filename = args[3];
}
if (mode == 's' && !*args[4])
return cli_err(appctx, "'show ssl crt-list -n' expects a filename or a directory\n");
if (filename && *filename) {
lnode = ebst_lookup(&crtlists_tree, filename);
if (lnode == NULL)
return cli_err(appctx, "didn't find the specified filename\n");
appctx->ctx.cli.p0 = lnode;
appctx->io_handler = cli_io_handler_dump_crtlist_entries;
}
appctx->ctx.cli.i0 = mode;
return 0;
}
/* release function of the "add ssl crt-list' command, free things and unlock
the spinlock */
static void cli_release_add_crtlist(struct appctx *appctx)
{
struct crtlist_entry *entry = appctx->ctx.cli.p1;
if (appctx->st2 != SETCERT_ST_FIN) {
struct ckch_inst *inst, *inst_s;
/* upon error free the ckch_inst and everything inside */
ebpt_delete(&entry->node);
LIST_DEL(&entry->by_crtlist);
LIST_DEL(&entry->by_ckch_store);
list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_ckchs) {
ckch_inst_free(inst);
}
crtlist_free_filters(entry->filters);
ssl_sock_free_ssl_conf(entry->ssl_conf);
free(entry->ssl_conf);
free(entry);
}
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
}
/* IO Handler for the "add ssl crt-list" command It adds a new entry in the
* crt-list and generates the ckch_insts for each bind_conf that uses this crt-list
*
* The logic is the same as the "commit ssl cert" command but without the
* freeing of the old structures, because there are none.
*/
static int cli_io_handler_add_crtlist(struct appctx *appctx)
{
struct bind_conf_list *bind_conf_node;
struct stream_interface *si = appctx->owner;
struct crtlist *crtlist = appctx->ctx.cli.p0;
struct crtlist_entry *entry = appctx->ctx.cli.p1;
struct ckch_store *store = entry->node.key;
struct buffer *trash = alloc_trash_chunk();
struct ckch_inst *new_inst;
char *err = NULL;
int i = 0;
int errcode = 0;
if (trash == NULL)
goto error;
/* for each bind_conf which use the crt-list, a new ckch_inst must be
* created.
*/
if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
goto error;
while (1) {
switch (appctx->st2) {
case SETCERT_ST_INIT:
/* This state just print the update message */
chunk_printf(trash, "Inserting certificate '%s' in crt-list '%s'", store->path, crtlist->node.key);
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
appctx->st2 = SETCERT_ST_GEN;
/* fallthrough */
case SETCERT_ST_GEN:
bind_conf_node = appctx->ctx.cli.p2; /* get the previous ptr from the yield */
if (bind_conf_node == NULL)
bind_conf_node = crtlist->bind_conf;
for (; bind_conf_node; bind_conf_node = bind_conf_node->next) {
struct bind_conf *bind_conf = bind_conf_node->bind_conf;
struct sni_ctx *sni;
/* yield every 10 generations */
if (i > 10) {
appctx->ctx.cli.p2 = bind_conf_node;
goto yield;
}
/* we don't support multi-cert bundles, only simple ones */
errcode |= ckch_inst_new_load_store(store->path, store, bind_conf, entry->ssl_conf, entry->filters, entry->fcount, &new_inst, &err);
if (errcode & ERR_CODE)
goto error;
/* we need to initialize the SSL_CTX generated */
/* this iterate on the newly generated SNIs in the new instance to prepare their SSL_CTX */
list_for_each_entry(sni, &new_inst->sni_ctx, by_ckch_inst) {
if (!sni->order) { /* we initialized only the first SSL_CTX because it's the same in the other sni_ctx's */
errcode |= ssl_sock_prepare_ctx(bind_conf, new_inst->ssl_conf, sni->ctx, &err);
if (errcode & ERR_CODE)
goto error;
}
}
/* display one dot for each new instance */
chunk_appendf(trash, ".");
i++;
LIST_ADDQ(&store->ckch_inst, &new_inst->by_ckchs);
}
appctx->st2 = SETCERT_ST_INSERT;
/* fallthrough */
case SETCERT_ST_INSERT:
/* insert SNIs in bind_conf */
list_for_each_entry(new_inst, &store->ckch_inst, by_ckchs) {
HA_RWLOCK_WRLOCK(SNI_LOCK, &new_inst->bind_conf->sni_lock);
ssl_sock_load_cert_sni(new_inst, new_inst->bind_conf);
HA_RWLOCK_WRUNLOCK(SNI_LOCK, &new_inst->bind_conf->sni_lock);
}
entry->linenum = ++crtlist->linecount;
appctx->st2 = SETCERT_ST_FIN;
goto end;
}
}
end:
chunk_appendf(trash, "\n");
if (errcode & ERR_WARN)
chunk_appendf(trash, "%s", err);
chunk_appendf(trash, "Success!\n");
if (ci_putchk(si_ic(si), trash) == -1)
si_rx_room_blk(si);
free_trash_chunk(trash);
/* success: call the release function and don't come back */
return 1;
yield:
/* store the state */
if (ci_putchk(si_ic(si), trash) == -1)
si_rx_room_blk(si);
free_trash_chunk(trash);
si_rx_endp_more(si); /* let's come back later */
return 0; /* should come back */
error:
/* spin unlock and free are done in the release function */
if (trash) {
chunk_appendf(trash, "\n%sFailed!\n", err);
if (ci_putchk(si_ic(si), trash) == -1)
si_rx_room_blk(si);
free_trash_chunk(trash);
}
/* error: call the release function and don't come back */
return 1;
}
/*
* Parse a "add ssl crt-list <crt-list> <certfile>" line.
* Filters and option must be passed through payload:
*/
static int cli_parse_add_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
{
int cfgerr = 0;
struct ckch_store *store;
char *err = NULL;
char path[MAXPATHLEN+1];
char *crtlist_path;
char *cert_path = NULL;
struct ebmb_node *eb;
struct ebpt_node *inserted;
struct crtlist *crtlist;
struct crtlist_entry *entry = NULL;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[3] || (!payload && !*args[4]))
return cli_err(appctx, "'add ssl crtlist' expects a filename and a certificate name\n");
crtlist_path = args[3];
if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
return cli_err(appctx, "Operations on certificates are currently locked!\n");
eb = ebst_lookup(&crtlists_tree, crtlist_path);
if (!eb) {
memprintf(&err, "crt-list '%s' does not exist!", crtlist_path);
goto error;
}
crtlist = ebmb_entry(eb, struct crtlist, node);
entry = crtlist_entry_new();
if (entry == NULL) {
memprintf(&err, "Not enough memory!");
goto error;
}
if (payload) {
char *lf;
lf = strrchr(payload, '\n');
if (lf) {
memprintf(&err, "only one line of payload is supported!");
goto error;
}
/* cert_path is filled here */
cfgerr |= crtlist_parse_line(payload, &cert_path, entry, "CLI", 1, &err);
if (cfgerr & ERR_CODE)
goto error;
} else {
cert_path = args[4];
}
if (!cert_path) {
memprintf(&err, "'add ssl crtlist' should contain the certificate name in the payload");
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
if (eb_gettag(crtlist->entries.b[EB_RGHT])) {
char *slash;
slash = strrchr(cert_path, '/');
if (!slash) {
memprintf(&err, "'%s' is a directory, certificate path '%s' must contain the directory path", (char *)crtlist->node.key, cert_path);
goto error;
}
/* temporary replace / by 0 to do an strcmp */
*slash = '\0';
if (strcmp(cert_path, (char*)crtlist->node.key) != 0) {
*slash = '/';
memprintf(&err, "'%s' is a directory, certificate path '%s' must contain the directory path", (char *)crtlist->node.key, cert_path);
goto error;
}
*slash = '/';
}
if (*cert_path != '/' && global_ssl.crt_base) {
if ((strlen(global_ssl.crt_base) + 1 + strlen(cert_path)) > MAXPATHLEN) {
memprintf(&err, "'%s' : path too long", cert_path);
cfgerr |= ERR_ALERT | ERR_FATAL;
goto error;
}
snprintf(path, sizeof(path), "%s/%s", global_ssl.crt_base, cert_path);
cert_path = path;
}
store = ckchs_lookup(cert_path);
if (store == NULL) {
memprintf(&err, "certificate '%s' does not exist!", cert_path);
goto error;
}
if (store->multi) {
memprintf(&err, "certificate '%s' is a bundle. You can disable the bundle merging with the directive 'ssl-load-extra-files' in the global section.", cert_path);
goto error;
}
if (store->ckch == NULL || store->ckch->cert == NULL) {
memprintf(&err, "certificate '%s' is empty!", cert_path);
goto error;
}
/* check if it's possible to insert this new crtlist_entry */
entry->node.key = store;
inserted = ebpt_insert(&crtlist->entries, &entry->node);
if (inserted != &entry->node) {
memprintf(&err, "file already exists in this directory!");
goto error;
}
/* this is supposed to be a directory (EB_ROOT_UNIQUE), so no ssl_conf are allowed */
if ((entry->ssl_conf || entry->filters) && eb_gettag(crtlist->entries.b[EB_RGHT])) {
memprintf(&err, "this is a directory, SSL configuration and filters are not allowed");
goto error;
}
LIST_ADDQ(&crtlist->ord_entries, &entry->by_crtlist);
entry->crtlist = crtlist;
LIST_ADDQ(&store->crtlist_entry, &entry->by_ckch_store);
appctx->st2 = SETCERT_ST_INIT;
appctx->ctx.cli.p0 = crtlist;
appctx->ctx.cli.p1 = entry;
/* unlock is done in the release handler */
return 0;
error:
crtlist_entry_free(entry);
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
err = memprintf(&err, "Can't edit the crt-list: %s\n", err ? err : "");
return cli_dynerr(appctx, err);
}
/* Parse a "del ssl crt-list <crt-list> <certfile>" line. */
static int cli_parse_del_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
{
struct ckch_store *store;
char *err = NULL;
char *crtlist_path, *cert_path;
struct ebmb_node *ebmb;
struct ebpt_node *ebpt;
struct crtlist *crtlist;
struct crtlist_entry *entry = NULL;
struct ckch_inst *inst, *inst_s;
int linenum = 0;
char *colons;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (!*args[3] || !*args[4])
return cli_err(appctx, "'del ssl crtlist' expects a filename and a certificate name\n");
if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
return cli_err(appctx, "Can't delete!\nOperations on certificates are currently locked!\n");
crtlist_path = args[3];
cert_path = args[4];
colons = strchr(cert_path, ':');
if (colons) {
char *endptr;
linenum = strtol(colons + 1, &endptr, 10);
if (colons + 1 == endptr || *endptr != '\0') {
memprintf(&err, "wrong line number after colons in '%s'!", cert_path);
goto error;
}
*colons = '\0';
}
/* look for crtlist */
ebmb = ebst_lookup(&crtlists_tree, crtlist_path);
if (!ebmb) {
memprintf(&err, "crt-list '%s' does not exist!", crtlist_path);
goto error;
}
crtlist = ebmb_entry(ebmb, struct crtlist, node);
/* look for store */
store = ckchs_lookup(cert_path);
if (store == NULL) {
memprintf(&err, "certificate '%s' does not exist!", cert_path);
goto error;
}
if (store->multi) {
memprintf(&err, "certificate '%s' is a bundle. You can disable the bundle merging with the directive 'ssl-load-extra-files' in the global section.", cert_path);
goto error;
}
if (store->ckch == NULL || store->ckch->cert == NULL) {
memprintf(&err, "certificate '%s' is empty!", cert_path);
goto error;
}
ebpt = ebpt_lookup(&crtlist->entries, store);
if (!ebpt) {
memprintf(&err, "certificate '%s' can't be found in crt-list '%s'!", cert_path, crtlist_path);
goto error;
}
/* list the line number of entries for errors in err, and select the right ebpt */
for (; ebpt; ebpt = ebpt_next_dup(ebpt)) {
struct crtlist_entry *tmp;
tmp = ebpt_entry(ebpt, struct crtlist_entry, node);
memprintf(&err, "%s%s%d", err ? err : "", err ? ", " : "", tmp->linenum);
/* select the entry we wanted */
if (linenum == 0 || tmp->linenum == linenum) {
if (!entry)
entry = tmp;
}
}
/* we didn't found the specified entry */
if (!entry) {
memprintf(&err, "found a certificate '%s' but the line number is incorrect, please specify a correct line number preceded by colons (%s)!", cert_path, err ? err : NULL);
goto error;
}
/* we didn't specified a line number but there were several entries */
if (linenum == 0 && ebpt_next_dup(&entry->node)) {
memprintf(&err, "found the certificate '%s' in several entries, please specify a line number preceded by colons (%s)!", cert_path, err ? err : NULL);
goto error;
}
/* upon error free the ckch_inst and everything inside */
ebpt_delete(&entry->node);
LIST_DEL(&entry->by_crtlist);
LIST_DEL(&entry->by_ckch_store);
list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_crtlist_entry) {
struct sni_ctx *sni, *sni_s;
HA_RWLOCK_WRLOCK(SNI_LOCK, &inst->bind_conf->sni_lock);
list_for_each_entry_safe(sni, sni_s, &inst->sni_ctx, by_ckch_inst) {
ebmb_delete(&sni->name);
LIST_DEL(&sni->by_ckch_inst);
SSL_CTX_free(sni->ctx);
free(sni);
}
HA_RWLOCK_WRUNLOCK(SNI_LOCK, &inst->bind_conf->sni_lock);
LIST_DEL(&inst->by_ckchs);
free(inst);
}
crtlist_free_filters(entry->filters);
ssl_sock_free_ssl_conf(entry->ssl_conf);
free(entry->ssl_conf);
free(entry);
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
err = memprintf(&err, "Entry '%s' deleted in crtlist '%s'!\n", cert_path, crtlist_path);
return cli_dynmsg(appctx, LOG_NOTICE, err);
error:
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
err = memprintf(&err, "Can't delete the entry: %s\n", err ? err : "");
return cli_dynerr(appctx, err);
}
/* Type of SSL payloads that can be updated over the CLI */
enum {
@ -11235,9 +10556,6 @@ static struct cli_kw_list cli_kws = {{ },{
{ { "abort", "ssl", "cert", NULL }, "abort ssl cert <certfile> : abort a transaction for a certificate file", cli_parse_abort_cert, NULL, NULL },
{ { "del", "ssl", "cert", NULL }, "del ssl cert <certfile> : delete an unused certificate file", cli_parse_del_cert, NULL, NULL },
{ { "show", "ssl", "cert", NULL }, "show ssl cert [<certfile>] : display the SSL certificates used in memory, or the details of a <certfile>", cli_parse_show_cert, cli_io_handler_show_cert, cli_release_show_cert },
{ { "add", "ssl", "crt-list", NULL }, "add ssl crt-list <filename> <certfile> [options] : add a line <certfile> to a crt-list <filename>", cli_parse_add_crtlist, cli_io_handler_add_crtlist, cli_release_add_crtlist },
{ { "del", "ssl", "crt-list", NULL }, "del ssl crt-list <filename> <certfile[:line]> : delete a line <certfile> in a crt-list <filename>", cli_parse_del_crtlist, NULL, NULL },
{ { "show", "ssl", "crt-list", NULL }, "show ssl crt-list [-n] [<filename>] : show the list of crt-lists or the content of a crt-list <filename>", cli_parse_dump_crtlist, cli_io_handler_dump_crtlist, NULL },
{ { NULL }, NULL, NULL, NULL }
}};