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) {