diff --git a/modules/tls_mgm/doc/tls_mgm_admin.xml b/modules/tls_mgm/doc/tls_mgm_admin.xml
index 63a27c469cf..9945550f9b1 100644
--- a/modules/tls_mgm/doc/tls_mgm_admin.xml
+++ b/modules/tls_mgm/doc/tls_mgm_admin.xml
@@ -196,9 +196,10 @@ if (is_peer_verified()) {
tls_reload
- Reloads the TLS domains information from the database.
- The previous DB defined domains are discarded but the
- script defined domains are preserved.
+ Reloads all TLS domain information. Domains defined in the database are
+ re-queried, and script-defined domains are re-initialized (which
+ reloads their certificates and key files). The entire previous
+ domain configuration is discarded and replaced.
diff --git a/modules/tls_mgm/tls_domain.c b/modules/tls_mgm/tls_domain.c
index 27916394870..c6b3d990280 100644
--- a/modules/tls_mgm/tls_domain.c
+++ b/modules/tls_mgm/tls_domain.c
@@ -37,7 +37,6 @@
#include "../../lib/csv.h"
#include "tls_domain.h"
#include "tls_params.h"
-#include "api.h"
#include
#include
@@ -45,13 +44,13 @@
struct tls_domain **tls_server_domains;
struct tls_domain **tls_client_domains;
-map_t server_dom_matching;
-map_t client_dom_matching;
+struct tls_domain **script_srv_domains_template;
+struct tls_domain **script_cli_domains_template;
-rw_lock_t *dom_lock;
+map_t *server_dom_matching;
+map_t *client_dom_matching;
-extern struct openssl_binds openssl_api;
-extern struct wolfssl_binds wolfssl_api;
+rw_lock_t *dom_lock;
void destroy_tls_dom(struct tls_domain *d);
@@ -67,112 +66,52 @@ struct tls_domain *tls_find_domain_by_name(str *name, struct tls_domain **dom_li
return NULL;
}
-struct tls_domain *find_first_script_dom(struct tls_domain *dom)
-{
- struct tls_domain *d;
-
- for (d = dom; d && d->flags & DOM_FLAG_DB; d = d->next) ;
-
- return d;
-}
-
void map_free_node(void *val)
{
if (val)
shm_free(val);
}
-void map_remove_tls_dom(struct tls_domain *dom)
-{
- map_t map = dom->flags & DOM_FLAG_SRV ? server_dom_matching : client_dom_matching;
- map_iterator_t it, it_tmp;
- struct dom_filt_array *doms_array;
- void **val;
- int i, j;
-
- map_first(map, &it);
- while (iterator_is_valid(&it)) {
- it_tmp = it;
- iterator_next(&it);
-
- val = iterator_val(&it_tmp);
- doms_array = (struct dom_filt_array *)*val;
- for (i = 0; i < doms_array->size;)
- if (doms_array->arr[i].dom_link == dom) {
- for (j = i + 1; j < doms_array->size; j++)
- doms_array->arr[j-1] = doms_array->arr[j];
- doms_array->size--;
- }
- else {
- i++;
- }
- if (doms_array->size == 0) {
- map_free_node(doms_array);
- iterator_delete(&it_tmp);
- }
- }
-}
-
-void tls_free_domain(struct tls_domain *dom)
+void tls_release_domain(struct tls_domain *dom)
{
str_list *m_it, *m_tmp;
+ int free_it = 0;
- dom->refs--;
- if (dom->refs == 0) {
- LM_DBG("Freeing domain: %.*s\n",
- dom->name.len, dom->name.s);
+ if (!dom)
+ return;
- destroy_tls_dom(dom);
+ lock_get(dom->lock);
+ if (--dom->refs == 0)
+ free_it = 1;
+ lock_release(dom->lock);
- lock_destroy(dom->lock);
- lock_dealloc(dom->lock);
+ if (!free_it)
+ return;
- map_remove_tls_dom(dom);
+ LM_DBG("Freeing domain: %.*s\n",
+ dom->name.len, dom->name.s);
- m_it = dom->match_domains;
- while (m_it) {
- m_tmp = m_it;
- m_it = m_it->next;
- shm_free(m_tmp->s.s);
- shm_free(m_tmp);
- }
- m_it = dom->match_addresses;
- while (m_it) {
- m_tmp = m_it;
- m_it = m_it->next;
- shm_free(m_tmp->s.s);
- shm_free(m_tmp);
- }
+ destroy_tls_dom(dom);
- shm_free(dom);
- }
-}
-
-/* frees the DB domains */
-void tls_free_db_domains(struct tls_domain *dom)
-{
- struct tls_domain *tmp;
+ lock_destroy(dom->lock);
+ lock_dealloc(dom->lock);
- while (dom && dom->flags & DOM_FLAG_DB) {
- tmp = dom;
- dom = dom->next;
- map_remove_tls_dom(tmp);
- tls_free_domain(tmp);
+ m_it = dom->match_domains;
+ while (m_it) {
+ m_tmp = m_it;
+ m_it = m_it->next;
+ shm_free(m_tmp->s.s);
+ shm_free(m_tmp);
+ }
+ m_it = dom->match_addresses;
+ while (m_it) {
+ m_tmp = m_it;
+ m_it = m_it->next;
+ shm_free(m_tmp->s.s);
+ shm_free(m_tmp);
}
-}
-
-void tls_release_domain(struct tls_domain* dom)
-{
- if (!dom || !(dom->flags & DOM_FLAG_DB))
- return;
-
- if (dom_lock)
- lock_start_write(dom_lock);
-
- tls_free_domain(dom);
- if (dom_lock)
- lock_stop_write(dom_lock);
+ shm_free(dom);
}
int set_all_domain_attr(struct tls_domain **dom, char **str_vals, int *int_vals,
@@ -222,6 +161,13 @@ int set_all_domain_attr(struct tls_domain **dom, char **str_vals, int *int_vals,
if(blob_vals[BLOB_VALS_DHPARAMS_COL].len && blob_vals[BLOB_VALS_DHPARAMS_COL].s)
len += blob_vals[BLOB_VALS_DHPARAMS_COL].len;
+ if (d->name.len >= sizeof(name_buf)) {
+ LM_ERR("domain name '%.*s' is too long (max %zu chars)\n",
+ d->name.len, d->name.s, sizeof(name_buf) - 1);
+ *dom = d->next;
+ tls_release_domain(d);
+ return -1;
+ }
memcpy(name_buf, d->name.s, d->name.len);
name_len = d->name.len;
@@ -342,10 +288,10 @@ tls_find_server_domain(struct ip_addr *ip, unsigned short port)
addr_s.s = addr_buf;
addr_s.len = strlen(addr_buf);
- val = map_find(server_dom_matching, addr_s);
+ val = map_find(*server_dom_matching, addr_s);
if (!val) {
/* try to find a domain which matches any address */
- val = map_find(server_dom_matching, match_any_s);
+ val = map_find(*server_dom_matching, match_any_s);
if (!val) {
if (dom_lock)
lock_stop_read(dom_lock);
@@ -386,11 +332,11 @@ tls_find_domain_by_filters(struct ip_addr *ip, unsigned short port,
addr_s.len = strlen(addr_buf);
val = map_find(type == DOM_FLAG_SRV ?
- server_dom_matching : client_dom_matching, addr_s);
+ *server_dom_matching : *client_dom_matching, addr_s);
if (!val) {
/* try to find domains which match any address */
val = map_find(type == DOM_FLAG_SRV ?
- server_dom_matching : client_dom_matching, match_any_s);
+ *server_dom_matching : *client_dom_matching, match_any_s);
if (!val) {
if (dom_lock)
lock_stop_read(dom_lock);
@@ -401,6 +347,11 @@ tls_find_domain_by_filters(struct ip_addr *ip, unsigned short port,
dom_array = (struct dom_filt_array *)*val;
for (i = 0; i < dom_array->size; i++) {
+ if (domain_filter->len >= sizeof(fnm_s)) {
+ LM_WARN("domain filter '%.*s' too long, skipping match\n",
+ domain_filter->len, domain_filter->s);
+ continue;
+ }
memcpy(fnm_s, domain_filter->s, domain_filter->len);
fnm_s[domain_filter->len] = 0;
if (!fnmatch(dom_array->arr[i].hostname->s.s, fnm_s, 0)) {
@@ -556,6 +507,77 @@ int tls_new_domain(str *name, int type, struct tls_domain **dom)
return 0;
}
+
+/*
+ * Creates a deep-copy of a TLS domain. This is only appropriate for
+ * script-defined domains that are instantiated from a template, as it
+ * performs a mix of shallow and deep copying.
+ */
+struct tls_domain* tls_copy_domain(struct tls_domain* d)
+{
+ struct tls_domain *n;
+
+ if (!d) return NULL;
+
+ /* Allocate space for the struct and the domain name, like tls_new_domain */
+ n = shm_malloc(sizeof(struct tls_domain) + d->name.len);
+ if (!n) {
+ LM_ERR("No more shm mem\n");
+ return NULL;
+ }
+ memset(n, 0, sizeof(struct tls_domain));
+
+ /* copy config fields */
+ n->flags = d->flags;
+ n->verify_cert = d->verify_cert;
+ n->require_client_cert = d->require_client_cert;
+ n->crl_check_all = d->crl_check_all;
+ n->cert = d->cert;
+ n->pkey = d->pkey;
+ n->crl_directory = d->crl_directory;
+ n->ca = d->ca;
+ n->dh_param = d->dh_param;
+ n->tls_ec_curve = d->tls_ec_curve;
+ n->ca_directory = d->ca_directory;
+ n->ciphers_list = d->ciphers_list;
+ n->method_str = d->method_str;
+ n->method = d->method;
+ n->method_max = d->method_max;
+
+ /* Fix the name pointer and copy the content from the template */
+ n->name.s = (char*)(n + 1);
+ n->name.len = d->name.len;
+ memcpy(n->name.s, d->name.s, d->name.len);
+
+ /* Initialize runtime state that must not be shared from the template */
+ n->refs = 1;
+ n->lock = lock_alloc();
+ if (!n->lock || lock_init(n->lock) == NULL) {
+ LM_ERR("failed to init lock for domain clone\n");
+ if (n->lock) lock_dealloc(n->lock);
+ shm_free(n);
+ return NULL;
+ }
+
+ /*
+ * The matching lists are dynamically built in shm and freed by
+ * tls_free_domain, so they need a deep copy. Other config strings
+ * are pointers into the static config buffer and are correctly
+ * shallow-copied.
+ */
+ if ((d->match_domains && !(n->match_domains = dup_shm_str_list(d->match_domains))) ||
+ (d->match_addresses && !(n->match_addresses = dup_shm_str_list(d->match_addresses)))
+ ) {
+ goto error;
+ }
+
+ return n;
+
+error:
+ if (n) tls_release_domain(n);
+ return NULL;
+}
+
static int add_match_filt_to_dom(str *filter_s, str_list **filter_list)
{
str_list *match_filt;
@@ -770,7 +792,7 @@ int db_add_domain(char **str_vals, int *int_vals, str* blob_vals,
return 0;
}
-int update_matching_map(struct tls_domain *tls_dom)
+int update_matching_map(struct tls_domain *tls_dom, map_t matching_map)
{
str_list *addrf_s, *domf_s;
struct dom_filt_array *doms_array;
@@ -778,8 +800,7 @@ int update_matching_map(struct tls_domain *tls_dom)
int pos;
for (addrf_s = tls_dom->match_addresses; addrf_s; addrf_s = addrf_s->next) {
- val = map_get(tls_dom->flags & DOM_FLAG_SRV ?
- server_dom_matching : client_dom_matching, addrf_s->s);
+ val = map_get(matching_map, addrf_s->s);
if (!val) {
LM_ERR("No more shm memory!\n");
return -1;
diff --git a/modules/tls_mgm/tls_domain.h b/modules/tls_mgm/tls_domain.h
index ae2067f7966..618462bd319 100644
--- a/modules/tls_mgm/tls_domain.h
+++ b/modules/tls_mgm/tls_domain.h
@@ -96,18 +96,19 @@ struct dom_filt_array {
#define ref_tls_dom(_d) \
do { \
- if ((_d)->flags & DOM_FLAG_DB) { \
- lock_get((_d)->lock); \
- (_d)->refs++; \
- lock_release((_d)->lock); \
- } \
+ lock_get((_d)->lock); \
+ (_d)->refs++; \
+ lock_release((_d)->lock); \
} while (0)
extern struct tls_domain **tls_server_domains;
extern struct tls_domain **tls_client_domains;
-extern map_t server_dom_matching;
-extern map_t client_dom_matching;
+extern struct tls_domain **script_srv_domains_template;
+extern struct tls_domain **script_cli_domains_template;
+
+extern map_t *server_dom_matching;
+extern map_t *client_dom_matching;
extern rw_lock_t *dom_lock;
@@ -130,15 +131,10 @@ struct tls_domain *tls_find_client_domain_name(str *name);
* TLS domain structure
*/
int tls_new_domain(str *name, int type, struct tls_domain **dom);
+struct tls_domain* tls_copy_domain(struct tls_domain* d);
void tls_release_domain(struct tls_domain* dom);
-void tls_free_domain(struct tls_domain *dom);
-
-void tls_free_db_domains(struct tls_domain* dom);
-
-struct tls_domain *find_first_script_dom(struct tls_domain *dom);
-
int set_all_domain_attr(struct tls_domain **dom, char **str_vals, int *int_vals,
str* blob_vals);
@@ -149,7 +145,7 @@ int db_add_domain(char **str_vals, int *int_vals, str* blob_vals,
int parse_match_domains(struct tls_domain *tls_dom, str *domains_s);
int parse_match_addresses(struct tls_domain *tls_dom, str *addresses_s);
-int update_matching_map(struct tls_domain *tls_dom);
+int update_matching_map(struct tls_domain *tls_dom, map_t matching_map);
int sort_map_dom_arrays(map_t matching_map);
void map_free_node(void *val);
diff --git a/modules/tls_mgm/tls_mgm.c b/modules/tls_mgm/tls_mgm.c
index 29b1241bb62..99efa65a989 100644
--- a/modules/tls_mgm/tls_mgm.c
+++ b/modules/tls_mgm/tls_mgm.c
@@ -69,7 +69,7 @@
#include "api.h"
#define DB_CAP DB_CAP_QUERY | DB_CAP_UPDATE
-#define len(s) s == NULL?0:strlen(s)
+#define len(s) ((s) == NULL ? 0 : strlen(s))
#define check_val( _col, _val, _type, _not_null, _is_empty_str) \
do{\
@@ -165,7 +165,7 @@ static const cmd_export_t cmds[] = {
* Exported MI functions
*/
static const mi_export_t mi_cmds[] = {
- { "tls_reload", "reloads stored data from the database", 0, 0, {
+ { "tls_reload", "reloads TLS configuration from files and/or database", 0, 0, {
{tls_reload, {0}},
{EMPTY_MI_RECIPE}}
},
@@ -583,11 +583,11 @@ int tls_sni_cb(struct tls_domain *dom, struct tcp_connection *c,
rc = wolfssl_api.switch_ssl_ctx(new_dom, ssl_ctx);
} else {
LM_CRIT("No TLS library module loaded\n");
- tls_release_domain(dom);
+ tls_release_domain(new_dom);
return -1;
}
if (rc < 0) {
- tls_release_domain(dom);
+ tls_release_domain(new_dom);
return -1;
}
@@ -705,7 +705,7 @@ static int init_tls_domains(struct tls_domain **dom)
tmp = d;
d = d->next;
- tls_free_domain(tmp);
+ tls_release_domain(tmp);
if (!db)
return -1;
@@ -755,7 +755,7 @@ static int init_tls_domains(struct tls_domain **dom)
tmp = d;
d = d->next;
- tls_free_domain(tmp);
+ tls_release_domain(tmp);
if (!db)
return -1;
@@ -787,94 +787,221 @@ static inline char *get_ssl_method_name(enum tls_method method)
return ssl_versions_struct[method-1].name;
}
-/* reloads data from the db */
-static int reload_data(void)
+static void free_domain_list(struct tls_domain *d)
{
- struct tls_domain *tls_client_domains_tmp = NULL;
- struct tls_domain *tls_server_domains_tmp = NULL;
- struct tls_domain *script_cli_doms, *script_srv_doms, *dom;
+ struct tls_domain *d_tmp;
+ while(d) {
+ d_tmp = d;
+ d = d->next;
+ tls_release_domain(d_tmp);
+ }
+}
- script_srv_doms = find_first_script_dom(*tls_server_domains);
- script_cli_doms = find_first_script_dom(*tls_client_domains);
- /* load new domains from db */
- if (load_info(&tls_server_domains_tmp, &tls_client_domains_tmp,
- script_srv_doms, script_cli_doms) < 0)
- return -1;
+static struct tls_domain* clone_domain_list(struct tls_domain *src_list)
+{
+ struct tls_domain *new_list = NULL, **p;
+ struct tls_domain *new_dom;
- /*
- * initialize new domains
- */
- init_tls_domains(&tls_server_domains_tmp);
- init_tls_domains(&tls_client_domains_tmp);
+ p = &new_list;
+ for (; src_list; src_list = src_list->next) {
+ new_dom = tls_copy_domain(src_list);
+ if (!new_dom) {
+ free_domain_list(new_list);
+ return NULL;
+ }
+ *p = new_dom;
+ p = &new_dom->next;
+ }
+ return new_list;
+}
- lock_start_write(dom_lock);
+/* reloads data from config files and/or the db */
+static int reload_data(void)
+{
+ struct tls_domain *tls_client_domains_new = NULL;
+ struct tls_domain *tls_server_domains_new = NULL;
+ struct tls_domain *tls_client_domains_old = NULL;
+ struct tls_domain *tls_server_domains_old = NULL;
+
+ struct tls_domain *script_cli_doms_new = NULL;
+ struct tls_domain *script_srv_doms_new = NULL;
+ struct tls_domain *db_cli_doms_new = NULL;
+ struct tls_domain *db_srv_doms_new = NULL;
+ struct tls_domain *dom;
+ str s;
- tls_free_db_domains(*tls_server_domains);
+ /* 1. clone and init script domains from templates */
+ if (script_srv_domains_template) {
+ script_srv_doms_new = clone_domain_list(*script_srv_domains_template);
+ if (!script_srv_doms_new && *script_srv_domains_template) {
+ LM_ERR("failed to clone script-defined server TLS domains\n");
+ goto error;
+ }
+ }
+ if (script_cli_domains_template) {
+ script_cli_doms_new = clone_domain_list(*script_cli_domains_template);
+ if (!script_cli_doms_new && *script_cli_domains_template) {
+ LM_ERR("failed to clone script-defined client TLS domains\n");
+ goto error;
+ }
+ }
- /* link the new DB domains with the existing script domains */
- if (script_srv_doms) {
- for (dom = tls_server_domains_tmp; dom; dom = dom->next)
- if (!dom->next)
- break;
- if (dom)
- dom->next = script_srv_doms;
+ if (init_tls_domains(&script_srv_doms_new) < 0) {
+ LM_ERR("failed to re-initialize script-defined server TLS domains\n");
+ goto error;
+ }
+ if (init_tls_domains(&script_cli_doms_new) < 0) {
+ LM_ERR("failed to re-initialize script-defined client TLS domains\n");
+ goto error;
}
- if (tls_server_domains_tmp)
- *tls_server_domains = tls_server_domains_tmp;
- else
- *tls_server_domains = script_srv_doms;
+ /* 2. load and init DB domains */
+ if (tls_db_url.s) {
+ int ret = 0;
+ if (load_info(&db_srv_doms_new, &db_cli_doms_new, script_srv_doms_new, script_cli_doms_new) < 0) {
+ LM_ERR("failed to load TLS domains from database\n");
+ ret = -1;
+ }
- tls_free_db_domains(*tls_client_domains);
+ if (ret == 0 && init_tls_domains(&db_srv_doms_new) < 0) {
+ LM_ERR("failed to initialize DB-defined server TLS domains\n");
+ ret = -1;
+ }
+ if (ret == 0 && init_tls_domains(&db_cli_doms_new) < 0) {
+ LM_ERR("failed to initialize DB-defined client TLS domains\n");
+ ret = -1;
+ }
+
+ if (db_hdl) {
+ dr_dbf.close(db_hdl);
+ db_hdl = NULL;
+ }
- if (script_cli_doms) {
- for (dom = tls_client_domains_tmp; dom; dom = dom->next)
- if (!dom->next)
- break;
- if (dom)
- dom->next = script_cli_doms;
+ if (ret < 0)
+ goto error;
}
- if (tls_client_domains_tmp)
- *tls_client_domains = tls_client_domains_tmp;
- else
- *tls_client_domains = script_cli_doms;
+ /* 3. link new domain lists */
+ tls_server_domains_new = db_srv_doms_new;
+ if (tls_server_domains_new) {
+ for (dom = tls_server_domains_new; dom && dom->next; dom = dom->next);
+ if (dom) dom->next = script_srv_doms_new;
+ } else {
+ tls_server_domains_new = script_srv_doms_new;
+ }
+ script_srv_doms_new = NULL; /* ownership transferred */
+ db_srv_doms_new = NULL;
- for (dom = *tls_server_domains; dom; dom = dom->next)
- if (update_matching_map(dom) < 0) {
- LM_ERR("Unable to update domain matching map\n");
- return -1;
+ tls_client_domains_new = db_cli_doms_new;
+ if (tls_client_domains_new) {
+ for (dom = tls_client_domains_new; dom && dom->next; dom = dom->next);
+ if (dom) dom->next = script_cli_doms_new;
+ } else {
+ tls_client_domains_new = script_cli_doms_new;
+ }
+ script_cli_doms_new = NULL; /* ownership transferred */
+ db_cli_doms_new = NULL;
+
+ /* 4. Create and populate new matching maps */
+ map_t server_dom_matching_new = map_create(AVLMAP_SHARED);
+ map_t client_dom_matching_new = map_create(AVLMAP_SHARED);
+ map_t server_dom_matching_old;
+ map_t client_dom_matching_old;
+
+ if (!server_dom_matching_new || !client_dom_matching_new) {
+ LM_CRIT("failed to create new matching maps\n");
+ if (server_dom_matching_new) map_destroy(server_dom_matching_new, map_free_node);
+ if (client_dom_matching_new) map_destroy(client_dom_matching_new, map_free_node);
+ if (tls_server_domains_new)
+ free_domain_list(tls_server_domains_new);
+ if (tls_client_domains_new)
+ free_domain_list(tls_client_domains_new);
+ return -1;
+ }
+
+ s.s = NULL;
+ for (dom = tls_server_domains_new; dom; dom = dom->next) {
+ if (!dom->match_domains && parse_match_domains(dom, &s) < 0) {
+ LM_ERR("Failed to parse domain matching filters for domain [%.*s]\n",
+ dom->name.len, dom->name.s);
+ goto map_error;
}
- for (dom = *tls_client_domains; dom; dom = dom->next)
- if (update_matching_map(dom) < 0) {
- LM_ERR("Unable to update domain matching map\n");
- return -1;
+ if (!dom->match_addresses && parse_match_addresses(dom, &s) < 0) {
+ LM_ERR("Failed to parse address matching filters for domain [%.*s]\n",
+ dom->name.len, dom->name.s);
+ goto map_error;
+ }
+ if (update_matching_map(dom, server_dom_matching_new) < 0) {
+ LM_ERR("Unable to update new server domain matching map\n");
+ goto map_error;
+ }
+ }
+ for (dom = tls_client_domains_new; dom; dom = dom->next) {
+ if (!dom->match_domains && parse_match_domains(dom, &s) < 0) {
+ LM_ERR("Failed to parse domain matching filters for domain [%.*s]\n",
+ dom->name.len, dom->name.s);
+ goto map_error;
}
+ if (!dom->match_addresses && parse_match_addresses(dom, &s) < 0) {
+ LM_ERR("Failed to parse address matching filters for domain [%.*s]\n",
+ dom->name.len, dom->name.s);
+ goto map_error;
+ }
+ if (update_matching_map(dom, client_dom_matching_new) < 0) {
+ LM_ERR("Unable to update new client domain matching map\n");
+ goto map_error;
+ }
+ }
- /* sort arrays of domain filters in order to be able to select the
- * most specific domain first in case of definitions with wildcard patterns */
- if (*tls_server_domains)
- sort_map_dom_arrays(server_dom_matching);
- if (*tls_client_domains)
- sort_map_dom_arrays(client_dom_matching);
+ if (tls_server_domains_new)
+ sort_map_dom_arrays(server_dom_matching_new);
+ if (tls_client_domains_new)
+ sort_map_dom_arrays(client_dom_matching_new);
+ /* 5. atomic swap */
+ lock_start_write(dom_lock);
+ tls_server_domains_old = *tls_server_domains;
+ tls_client_domains_old = *tls_client_domains;
+ server_dom_matching_old = *server_dom_matching;
+ client_dom_matching_old = *client_dom_matching;
+
+ *tls_server_domains = tls_server_domains_new;
+ *tls_client_domains = tls_client_domains_new;
+ *server_dom_matching = server_dom_matching_new;
+ *client_dom_matching = client_dom_matching_new;
lock_stop_write(dom_lock);
+ /* 6. cleanup old domains and maps */
+ if (server_dom_matching_old) map_destroy(server_dom_matching_old, map_free_node);
+ if (client_dom_matching_old) map_destroy(client_dom_matching_old, map_free_node);
+ if (tls_server_domains_old) free_domain_list(tls_server_domains_old);
+ if (tls_client_domains_old) free_domain_list(tls_client_domains_old);
+
return 0;
+
+map_error:
+ if (server_dom_matching_new) map_destroy(server_dom_matching_new, map_free_node);
+ if (client_dom_matching_new) map_destroy(client_dom_matching_new, map_free_node);
+ if (tls_server_domains_new) free_domain_list(tls_server_domains_new);
+ if (tls_client_domains_new) free_domain_list(tls_client_domains_new);
+ return -1;
+error:
+ if (script_srv_doms_new) free_domain_list(script_srv_doms_new);
+ if (script_cli_doms_new) free_domain_list(script_cli_doms_new);
+ if (db_srv_doms_new) free_domain_list(db_srv_doms_new);
+ if (db_cli_doms_new) free_domain_list(db_cli_doms_new);
+ return -1;
}
-/* reloads data from the db */
+/* reloads data from config files and/or the db */
static mi_response_t *tls_reload(const mi_params_t *params,
struct mi_handler *async_hdl)
{
LM_INFO("reload data MI command received!\n");
- if (!tls_db_url.s)
- return init_mi_error(500, MI_SSTR("DB url not set"));
-
if (reload_data() < 0) {
- LM_ERR("failed to load tls data\n");
+ LM_ERR("failed to reload tls data\n");
return init_mi_error(500, MI_SSTR("Failed to reload"));
}
@@ -954,22 +1081,38 @@ static int load_tls_library(void)
static int mod_init(void) {
str s;
str tls_db_param = str_init(DB_TLS_DOMAIN_PARAM_EQ);
- struct tls_domain *tls_client_domains_tmp = NULL;
- struct tls_domain *tls_server_domains_tmp = NULL;
- struct tls_domain *dom;
LM_INFO("initializing TLS management\n");
+ /*
+ * The modparam functions have populated the template lists.
+ * We now allocate the live lists.
+ */
+ tls_server_domains = shm_malloc(sizeof(struct tls_domain*));
+ if (!tls_server_domains) { LM_ERR("No more shm mem\n"); return -1; }
+ *tls_server_domains = NULL;
+
+ tls_client_domains = shm_malloc(sizeof(struct tls_domain*));
+ if (!tls_client_domains) { LM_ERR("No more shm mem\n"); return -1; }
+ *tls_client_domains = NULL;
+
+ server_dom_matching = shm_malloc(sizeof(map_t));
+ if (!server_dom_matching) { LM_ERR("no more shm mem\n"); return -1; }
+ *server_dom_matching = NULL;
+ client_dom_matching = shm_malloc(sizeof(map_t));
+ if (!client_dom_matching) { LM_ERR("no more shm mem\n"); return -1; }
+ *client_dom_matching = NULL;
+
if (load_tls_library() < 0)
return -1;
- if (tls_db_url.s) {
+ /* create & init lock */
+ if ((dom_lock = lock_init_rw()) == NULL) {
+ LM_CRIT("failed to init lock\n");
+ return -1;
+ }
- /* create & init lock */
- if ((dom_lock = lock_init_rw()) == NULL) {
- LM_CRIT("failed to init lock\n");
- return -1;
- }
+ if (tls_db_url.s) {
init_db_url(tls_db_url, 0 /*cannot be null*/);
@@ -1013,41 +1156,6 @@ static int mod_init(void) {
LM_CRIT("cannot initialize database connection\n");
return -1;
}
-
- if (dr_dbf.use_table(db_hdl, &tls_db_table) < 0) {
- LM_ERR("cannot select table \"%.*s\"\n",
- tls_db_table.len, tls_db_table.s);
- return -1;
- }
- }
-
- if (tls_server_domains == NULL) {
- tls_server_domains = shm_malloc(sizeof *tls_server_domains);
- if (!tls_server_domains) {
- LM_ERR("No more shm mem\n");
- return -1;
- }
- *tls_server_domains = NULL;
- }
-
- if (tls_client_domains == NULL) {
- tls_client_domains = shm_malloc(sizeof *tls_client_domains);
- if (!tls_client_domains) {
- LM_ERR("No more shm mem\n");
- return -1;
- }
- *tls_client_domains = NULL;
- }
-
- server_dom_matching = map_create(AVLMAP_SHARED);
- if (!server_dom_matching) {
- LM_ERR("No more shm memory!\n");
- return -1;
- }
- client_dom_matching = map_create(AVLMAP_SHARED);
- if (!client_dom_matching) {
- LM_ERR("No more shm memory!\n");
- return -1;
}
if (tls_domain_avp) {
@@ -1068,89 +1176,9 @@ static int mod_init(void) {
}
}
- if (tls_db_url.s) {
- if (load_info(&tls_server_domains_tmp, &tls_client_domains_tmp,
- *tls_server_domains, *tls_client_domains))
- return -1;
-
- dr_dbf.close(db_hdl);
- db_hdl = NULL;
-
- /* link the DB domains with the existing script domains */
-
- if (*tls_server_domains && tls_server_domains_tmp) {
- for (dom = tls_server_domains_tmp; dom; dom = dom->next)
- if (!dom->next)
- break;
- dom->next = *tls_server_domains;
- }
- if (tls_server_domains_tmp)
- *tls_server_domains = tls_server_domains_tmp;
-
- if (*tls_client_domains && tls_client_domains_tmp) {
- for (dom = tls_client_domains_tmp; dom; dom = dom->next)
- if (!dom->next)
- break;
- dom->next = *tls_client_domains;
- }
- if (tls_client_domains_tmp)
- *tls_client_domains = tls_client_domains_tmp;
- }
-
- for (dom = *tls_server_domains; dom; dom = dom->next) {
- /* for script defined domains, if match_address/domain parameters
- * are not defined, match any value */
- s.s = NULL;
- if (!dom->match_domains && parse_match_domains(dom, &s) < 0) {
- LM_ERR("Failed to parse domain matching filters for domain [%.*s]\n",
- dom->name.len, dom->name.s);
- return -1;
- }
- if (!dom->match_addresses && parse_match_addresses(dom, &s) < 0) {
- LM_ERR("Failed to parse address matching filters for domain [%.*s]\n",
- dom->name.len, dom->name.s);
- return -1;
- }
-
- if (update_matching_map(dom) < 0) {
- LM_ERR("Unable to update domain matching map\n");
- return -1;
- }
- }
-
- for (dom = *tls_client_domains; dom; dom = dom->next) {
- /* for script defined domains, if match_address/domain parameters
- * are not defined, match any value */
- s.s = NULL;
- if (!dom->match_domains && parse_match_domains(dom, &s) < 0) {
- LM_ERR("Failed to parse domain matching filters for domain [%.*s]\n",
- dom->name.len, dom->name.s);
- return -1;
- }
- if (!dom->match_addresses && parse_match_addresses(dom, &s) < 0) {
- LM_ERR("Failed to parse address matching filters for domain [%.*s]\n",
- dom->name.len, dom->name.s);
- return -1;
- }
-
- if (update_matching_map(dom) < 0) {
- LM_ERR("Unable to update domain matching map\n");
- return -1;
- }
- }
-
- /* sort arrays of domain filters in order to be able to select the
- * most specific domain first in case of definitions with wildcard patterns */
- if (*tls_server_domains)
- sort_map_dom_arrays(server_dom_matching);
- if (*tls_client_domains)
- sort_map_dom_arrays(client_dom_matching);
-
- /* initialize tls virtual domains */
- if (init_tls_domains(tls_server_domains) < 0)
- return -1;
- if (init_tls_domains(tls_client_domains) < 0)
+ if (reload_data() < 0) {
return -1;
+ }
return 0;
}
@@ -1180,20 +1208,46 @@ static void mod_destroy(void)
while (d) {
d_tmp = d;
d = d->next;
- tls_free_domain(d_tmp);
+ tls_release_domain(d_tmp);
}
d = *tls_client_domains;
while (d) {
d_tmp = d;
d = d->next;
- tls_free_domain(d_tmp);
+ tls_release_domain(d_tmp);
}
-
shm_free(tls_server_domains);
shm_free(tls_client_domains);
- map_destroy(server_dom_matching, map_free_node);
- map_destroy(client_dom_matching, map_free_node);
+ if (script_srv_domains_template) {
+ d = *script_srv_domains_template;
+ while (d) {
+ d_tmp = d;
+ d = d->next;
+ tls_release_domain(d_tmp);
+ }
+ shm_free(script_srv_domains_template);
+ }
+ if (script_cli_domains_template) {
+ d = *script_cli_domains_template;
+ while (d) {
+ d_tmp = d;
+ d = d->next;
+ tls_release_domain(d_tmp);
+ }
+ shm_free(script_cli_domains_template);
+ }
+
+ if (server_dom_matching) {
+ if (*server_dom_matching)
+ map_destroy(*server_dom_matching, map_free_node);
+ shm_free(server_dom_matching);
+ }
+ if (client_dom_matching) {
+ if (*client_dom_matching)
+ map_destroy(*client_dom_matching, map_free_node);
+ shm_free(client_dom_matching);
+ }
}
static int list_domain(mi_item_t *domains_arr, struct tls_domain *d)
diff --git a/modules/tls_mgm/tls_params.c b/modules/tls_mgm/tls_params.c
index bb1cb9f8a67..296019c3955 100644
--- a/modules/tls_mgm/tls_params.c
+++ b/modules/tls_mgm/tls_params.c
@@ -44,7 +44,6 @@
#include "../../ut.h"
#include "tls_params.h"
-#include "api.h"
int tlsp_add_srv_domain(modparam_t type, void *val)
@@ -54,22 +53,22 @@ int tlsp_add_srv_domain(modparam_t type, void *val)
name.s = (char *)val;
name.len = strlen(name.s);
- if (tls_server_domains == NULL) {
- tls_server_domains = shm_malloc(sizeof *tls_server_domains);
- if (!tls_server_domains) {
+ if (script_srv_domains_template == NULL) {
+ script_srv_domains_template = shm_malloc(sizeof *script_srv_domains_template);
+ if (!script_srv_domains_template) {
LM_ERR("No more shm mem\n");
return -1;
}
- *tls_server_domains = NULL;
+ *script_srv_domains_template = NULL;
}
- if (tls_find_domain_by_name(&name, tls_server_domains)) {
+ if (tls_find_domain_by_name(&name, script_srv_domains_template)) {
LM_ERR("Domain name: [%.*s] already defined\n", name.len, name.s);
return -1;
}
/* add domain */
- if (tls_new_domain(&name, DOM_FLAG_SRV, tls_server_domains) < 0) {
+ if (tls_new_domain(&name, DOM_FLAG_SRV, script_srv_domains_template) < 0) {
LM_ERR("failed to add new server domain [%.*s]\n", name.len, name.s);
return -1;
}
@@ -85,22 +84,22 @@ int tlsp_add_cli_domain(modparam_t type, void *val)
name.s = (char *)val;
name.len = strlen(name.s);
- if (tls_client_domains == NULL) {
- tls_client_domains = shm_malloc(sizeof *tls_client_domains);
- if (!tls_client_domains) {
+ if (script_cli_domains_template == NULL) {
+ script_cli_domains_template = shm_malloc(sizeof *script_cli_domains_template);
+ if (!script_cli_domains_template) {
LM_ERR("No more shm mem\n");
return -1;
}
- *tls_client_domains = NULL;
+ *script_cli_domains_template = NULL;
}
- if (tls_find_domain_by_name(&name, tls_client_domains)) {
+ if (tls_find_domain_by_name(&name, script_cli_domains_template)) {
LM_ERR("Domain name: [%.*s] already defined\n", name.len, name.s);
return -1;
}
/* add domain */
- if (tls_new_domain(&name, DOM_FLAG_CLI, tls_client_domains) < 0) {
+ if (tls_new_domain(&name, DOM_FLAG_CLI, script_cli_domains_template) < 0) {
LM_ERR("failed to add new client domain [%.*s]\n", name.len, name.s);
return -1;
}
@@ -152,8 +151,8 @@ static int split_param_val(char *in, str *name, str *val)
#define set_domain_attr( _name, _field, _val) \
do { \
struct tls_domain *_d; \
- _d = tls_find_domain_by_name(&(_name), tls_server_domains); \
- if (!_d && (_d = tls_find_domain_by_name(&(_name), tls_client_domains)) == NULL) { \
+ _d = tls_find_domain_by_name(&(_name), script_srv_domains_template); \
+ if (!_d && (_d = tls_find_domain_by_name(&(_name), script_cli_domains_template)) == NULL) { \
LM_ERR("TLS domain [%.*s] not defined in '%s'\n", \
(_name).len, (_name).s, (char*)in); \
return -1; \
@@ -171,8 +170,8 @@ int tlsp_set_match_addr(modparam_t type, void *in)
if (split_param_val((char*)in, &name, &val) < 0)
return -1;
- d = tls_find_domain_by_name(&name, tls_server_domains);
- if (!d && (d = tls_find_domain_by_name(&name, tls_client_domains)) == NULL) {
+ d = tls_find_domain_by_name(&name, script_srv_domains_template);
+ if (!d && (d = tls_find_domain_by_name(&name, script_cli_domains_template)) == NULL) {
LM_ERR("TLS domain [%.*s] not defined\n", name.len, name.s);
return -1;
}
@@ -195,8 +194,8 @@ int tlsp_set_match_dom(modparam_t type, void *in)
if (split_param_val((char*)in, &name, &val) < 0)
return -1;
- d = tls_find_domain_by_name(&name, tls_server_domains);
- if (!d && (d = tls_find_domain_by_name(&name, tls_client_domains)) == NULL) {
+ d = tls_find_domain_by_name(&name, script_srv_domains_template);
+ if (!d && (d = tls_find_domain_by_name(&name, script_cli_domains_template)) == NULL) {
LM_ERR("TLS domain [%.*s] not defined\n", name.len, name.s);
return -1;
}
diff --git a/modules/tls_openssl/openssl_config.c b/modules/tls_openssl/openssl_config.c
index 45d3059bee2..dd0dc9a26a0 100644
--- a/modules/tls_openssl/openssl_config.c
+++ b/modules/tls_openssl/openssl_config.c
@@ -288,12 +288,16 @@ int ssl_servername_cb(SSL *ssl, int *ad, void *arg)
struct tls_domain *dom;
int rc;
- if (!ssl || !arg) {
+ if (!ssl) {
LM_ERR("Bad parameters in servername callback\n");
return SSL_TLSEXT_ERR_NOACK;
}
- dom = (struct tls_domain *)arg;
+ dom = (struct tls_domain *)SSL_get_ex_data(ssl, SSL_EX_DOM_IDX);
+ if (!dom) {
+ LM_ERR("Failed to get tls_domain pointer from SSL struct\n");
+ return SSL_TLSEXT_ERR_NOACK;
+ }
srvname = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (srvname && strlen(srvname) == 0) {
@@ -827,7 +831,6 @@ int openssl_init_tls_dom(struct tls_domain *d, int init_flags)
/* install callback for SNI */
if (mod_sni_cb && d->flags & DOM_FLAG_SRV) {
SSL_CTX_set_tlsext_servername_callback(((void**)d->ctx)[i], ssl_servername_cb);
- SSL_CTX_set_tlsext_servername_arg(((void**)d->ctx)[i], d);
}
/*
diff --git a/modules/tls_wolfssl/wolfssl_config.c b/modules/tls_wolfssl/wolfssl_config.c
index f1394309e39..e4e0e893ca5 100644
--- a/modules/tls_wolfssl/wolfssl_config.c
+++ b/modules/tls_wolfssl/wolfssl_config.c
@@ -155,12 +155,16 @@ static int ssl_servername_cb(WOLFSSL *ssl, int *ret, void *exArg)
struct tls_domain *dom;
int rc;
- if (!ssl || !exArg) {
+ if (!ssl) {
LM_ERR("Bad parameters in servername callback\n");
return alert_warning;
}
- dom = (struct tls_domain *)exArg;
+ dom = (struct tls_domain *)wolfSSL_get_ex_data(ssl, SSL_EX_DOM_IDX);
+ if (!dom) {
+ LM_ERR("Failed to get tls_domain pointer from SSL struct\n");
+ return alert_warning;
+ }
srvname = (char *)wolfSSL_get_servername(ssl, WOLFSSL_SNI_HOST_NAME);
if (srvname && strlen(srvname) == 0) {
@@ -481,7 +485,6 @@ int _wolfssl_init_tls_dom(struct tls_domain *d, int init_flags)
if (mod_sni_cb && d->flags & DOM_FLAG_SRV) {
wolfSSL_CTX_set_servername_callback(d->ctx, ssl_servername_cb);
- wolfSSL_CTX_set_servername_arg(d->ctx, d);
}
if (d->flags & DOM_FLAG_SRV) {