Browse Source

- Support for external TLS configuration file
- support for relative path names (CFG_DIR will be added automaticaly)
- Support for run-time configuration re-load
- tls.reload management command implemented

Jan Janak 19 years ago
parent
commit
38a664796d

+ 140 - 36
modules/tls/tls_config.c

@@ -32,10 +32,12 @@
 
 
 #include <stdio.h>
 #include <stdio.h>
 #include <libgen.h>
 #include <libgen.h>
+#include "../../mem/mem.h"
 #include "../../dprint.h"
 #include "../../dprint.h"
 #include "../../trim.h"
 #include "../../trim.h"
 #include "../../ut.h"
 #include "../../ut.h"
 #include "tls_config.h"
 #include "tls_config.h"
+#include "tls_util.h"
 #include "tls_domain.h"
 #include "tls_domain.h"
 
 
 #define MAX_TOKEN_LEN 256
 #define MAX_TOKEN_LEN 256
@@ -49,6 +51,9 @@ static struct {
 	char* file;
 	char* file;
 	int line;
 	int line;
 	int col;
 	int col;
+
+	tls_cfg_t* cfg;       /* Current configuration data */
+	tls_domain_t* domain; /* Current domain in the configuration data */
 } pstate;
 } pstate;
 
 
 
 
@@ -450,7 +455,6 @@ static struct parser_tab* lookup_token(struct parser_tab* table, str* token)
 	}
 	}
 }
 }
 
 
-
 static int parse_string_val(str* res, token_t* token)
 static int parse_string_val(str* res, token_t* token)
 {
 {
 	int ret;
 	int ret;
@@ -536,6 +540,7 @@ static int parse_method_opt(token_t* token)
 		return -1;
 		return -1;
 	}
 	}
 
 
+	pstate.domain->method = r->u.ival;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -598,7 +603,9 @@ static int parse_bool_val(int* res, token_t* token)
 static int parse_verify_cert_opt(token_t* token)
 static int parse_verify_cert_opt(token_t* token)
 {
 {
 	int ret;
 	int ret;
-	return parse_bool_val(&ret, token);
+	if (parse_bool_val(&ret, token) < 0) return -1;
+	pstate.domain->verify_cert  = ret;
+	return 0;
 }
 }
 
 
 
 
@@ -644,52 +651,84 @@ static int parse_verify_depth_opt(token_t* token)
 
 
 		return -1;
 		return -1;
 	}
 	}
+	pstate.domain->verify_depth = val;
 	return 0;
 	return 0;
 }
 }
 
 
 
 
 static int parse_req_cert_opt(token_t* token)
 static int parse_req_cert_opt(token_t* token)
 {
 {
-	str val;
-	return parse_string_val(&val, token);
+	int ret;
+	if (parse_bool_val(&ret, token) < 0) return -1;
+	pstate.domain->require_cert  = ret;
+	return 0;
 }
 }
 
 
 
 
-static int parse_pkey_opt(token_t* token)
+/*
+ * Parse filename value, the function would add CFG_DIR prefix
+ * if the filename does not start with /. The result is allocated
+ * using shm_malloc and must be freed using shm_free
+ */
+static char* parse_file_val(token_t* token)
 {
 {
+	char* file, *res;
 	str val;
 	str val;
-	return parse_string_val(&val, token);
+        if (parse_string_val(&val, token) < 0) return 0;
+	file = get_pathname(&val);
+	if (!file) return 0;
+	if (shm_asciiz_dup(&res, file) < 0) {
+		pkg_free(file);
+		return 0;
+	}
+	pkg_free(file);
+	return res;
 }
 }
 
 
 
 
-static int parse_ca_list_opt(token_t* token)
+static int parse_pkey_opt(token_t* token)
 {
 {
-	str val;
-	return parse_string_val(&val, token);
+	char* file;
+	file = parse_file_val(token);
+	if (!file) return -1;
+	pstate.domain->pkey_file = file;
+	return 0;
 }
 }
 
 
+static int parse_ca_list_opt(token_t* token)
+{
+	char* file;
+	file = parse_file_val(token);
+	if (!file) return -1;
+	pstate.domain->ca_file = file;
+	return 0;
+}
 
 
 static int parse_cert_opt(token_t* token)
 static int parse_cert_opt(token_t* token)
 {
 {
-	str val;
-	return parse_string_val(&val, token);
+	char* file;
+	file = parse_file_val(token);
+	if (!file) return -1;
+	pstate.domain->cert_file = file;
+	return 0;
 }
 }
 
 
 static int parse_cipher_list_opt(token_t* token)
 static int parse_cipher_list_opt(token_t* token)
 {
 {
 	str val;
 	str val;
-	return parse_string_val(&val, token);
+	if (parse_string_val(&val, token) < 0) return -1;
+	if (shm_str_dup(&pstate.domain->cipher_list, &val) < 0) return -1;
+	return 0;
 }
 }
 
 
-static int parse_ipv6(token_t* token)
+static int parse_ipv6(struct ip_addr* ip, token_t* token)
 {
 {
 	char buf[IP_ADDR_MAX_STR_SIZE];
 	char buf[IP_ADDR_MAX_STR_SIZE];
 	int len, ret;
 	int len, ret;
 	token_t t;
 	token_t t;
-	struct ip_addr ip;
 
 
-	ip.af = AF_INET6;
-	ip.len = 16;
+	ip->af = AF_INET6;
+	ip->len = 16;
 	len = 0;
 	len = 0;
 
 
 	while(1) {
 	while(1) {
@@ -703,7 +742,7 @@ static int parse_ipv6(token_t* token)
 	}
 	}
 	buf[len] = '\0';
 	buf[len] = '\0';
 
 
-	if (inet_pton(ip.af, buf, ip.u.addr) <= 0)  goto err;
+	if (inet_pton(ip->af, buf, ip->u.addr) <= 0)  goto err;
 	return 0;
 	return 0;
  err:
  err:
 	LOG(L_ERR, "ERROR:%s:%d:%d: Invalid IPv6 address\n", 
 	LOG(L_ERR, "ERROR:%s:%d:%d: Invalid IPv6 address\n", 
@@ -711,20 +750,19 @@ static int parse_ipv6(token_t* token)
 	return -1;
 	return -1;
 }
 }
 
 
-static int parse_ipv4(token_t* token)
+static int parse_ipv4(struct ip_addr* ip, token_t* token)
 {
 {
-	struct ip_addr ip;
 	int ret, i;
 	int ret, i;
 	token_t  t;
 	token_t  t;
 	unsigned int v;
 	unsigned int v;
 
 
-	ip.af = AF_INET;
-	ip.len = 4;
+	ip->af = AF_INET;
+	ip->len = 4;
 
 
 	if (str2int(&token->val, &v) < 0) goto err;
 	if (str2int(&token->val, &v) < 0) goto err;
 	if (v < 0 || v > 255) goto err;
 	if (v < 0 || v > 255) goto err;
 
 
-	ip.u.addr[0] = v;
+	ip->u.addr[0] = v;
 
 
 	for(i = 1; i < 4; i++) {
 	for(i = 1; i < 4; i++) {
 		ret = tls_lex(&t, 0);
 		ret = tls_lex(&t, 0);
@@ -736,7 +774,7 @@ static int parse_ipv4(token_t* token)
 		if (ret == 0 || t.type != TOKEN_ALPHA) goto err;
 		if (ret == 0 || t.type != TOKEN_ALPHA) goto err;
 		if (str2int(&t.val, &v) < 0)  goto err;
 		if (str2int(&t.val, &v) < 0)  goto err;
 		if (v < 0 || v > 255) goto err;
 		if (v < 0 || v > 255) goto err;
-		ip.u.addr[i] = v;
+		ip->u.addr[i] = v;
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -746,9 +784,8 @@ static int parse_ipv4(token_t* token)
 	return -1;
 	return -1;
 }
 }
 
 
-static int parse_hostport(token_t* token)
+static int parse_hostport(int* type, struct ip_addr* ip, unsigned int* port, token_t* token)
 {
 {
-	unsigned int port;
 	int ret;
 	int ret;
 	token_t t;
 	token_t t;
 	struct parser_tab* r;
 	struct parser_tab* r;
@@ -762,20 +799,22 @@ static int parse_hostport(token_t* token)
 	}
 	}
 
 
 	if (t.type == '[') {
 	if (t.type == '[') {
-		if (parse_ipv6(&t) < 0) return -1;
+		if (parse_ipv6(ip, &t) < 0) return -1;
 	} else if (t.type == TOKEN_ALPHA) {
 	} else if (t.type == TOKEN_ALPHA) {
 		r = lookup_token(token_default, &t.val);
 		r = lookup_token(token_default, &t.val);
 		if (r) {
 		if (r) {
+			*type = TLS_DOMAIN_DEF;
 			     /* Default domain */
 			     /* Default domain */
 			return 0;
 			return 0;
 		} else {
 		} else {
-			if (parse_ipv4(&t) < 0) return -1;
+			if (parse_ipv4(ip, &t) < 0) return -1;
 		}
 		}
 	} else {
 	} else {
 		LOG(L_ERR, "ERROR:%s:%d:%d: Syntax error, IP address expected\n", 
 		LOG(L_ERR, "ERROR:%s:%d:%d: Syntax error, IP address expected\n", 
 		    pstate.file, t.start.line, t.start.col);
 		    pstate.file, t.start.line, t.start.col);
 		return -1;
 		return -1;
 	}
 	}
+	*type = 0;
 
 
 	     /* Parse port */
 	     /* Parse port */
 	ret = tls_lex(&t, 0);
 	ret = tls_lex(&t, 0);
@@ -800,7 +839,7 @@ static int parse_hostport(token_t* token)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (t.type != TOKEN_ALPHA || (str2int(&t.val, &port) < 0)) {
+	if (t.type != TOKEN_ALPHA || (str2int(&t.val, port) < 0)) {
 		LOG(L_ERR, "ERROR:%s:%d:%d: Invalid port number '%.*s'\n", 
 		LOG(L_ERR, "ERROR:%s:%d:%d: Invalid port number '%.*s'\n", 
 		    pstate.file, t.start.line, t.start.col,
 		    pstate.file, t.start.line, t.start.col,
 		    t.val.len, ZSW(t.val.s));
 		    t.val.len, ZSW(t.val.s));
@@ -815,6 +854,12 @@ static int parse_domain(token_t* token)
 	int ret;
 	int ret;
 	struct parser_tab* r;
 	struct parser_tab* r;
 
 
+	int type;
+	struct ip_addr ip;
+	unsigned int port;
+
+	memset(&ip, 0, sizeof(struct ip_addr));
+
 	ret = tls_lex(&t, 0);
 	ret = tls_lex(&t, 0);
 	if (ret < 0) return -1;
 	if (ret < 0) return -1;
 	if (ret == 0) {
 	if (ret == 0) {
@@ -844,7 +889,7 @@ static int parse_domain(token_t* token)
 		return -1;
 		return -1;
 	}	
 	}	
 
 
-	if (parse_hostport(&t) < 0) return -1;
+	if (parse_hostport(&type, &ip, &port, &t) < 0) return -1;
 
 
 	ret = tls_lex(&t, 0);
 	ret = tls_lex(&t, 0);
 	if (ret < 0) return -1;
 	if (ret < 0) return -1;
@@ -859,6 +904,26 @@ static int parse_domain(token_t* token)
 		return -1;
 		return -1;
 	}	
 	}	
 
 
+	pstate.domain = tls_new_domain(r->u.ival | type, &ip, port);
+	if (!pstate.domain) {
+		LOG(L_ERR, "ERROR:%s:%d: Cannot create TLS domain structure\n", 
+		    pstate.file, token->start.line);
+		return -1;
+	}
+
+	ret = tls_add_domain(pstate.cfg, pstate.domain);
+	if (ret < 0) {
+		LOG(L_ERR, "ERROR:%s:%d: Error while creating TLS domain structure\n", 
+		    pstate.file, token->start.line);
+		tls_free_domain(pstate.domain);
+		return -1;
+	} else if (ret == 1) {
+		LOG(L_ERR, "ERROR:%s:%d: Duplicate TLS domain (appears earlier in the config file)\n", 
+		    pstate.file, token->start.line);
+		tls_free_domain(pstate.domain);
+		return -1;
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -875,6 +940,12 @@ static int parse_config(void)
 
 
 		switch(token.type) {
 		switch(token.type) {
 		case TOKEN_ALPHA:
 		case TOKEN_ALPHA:
+			if (!pstate.domain) {
+				LOG(L_ERR, "ERROR:%s:%d: You need to specify TLS domain first\n", 
+				    pstate.file, token.start.line);
+				return -1;
+			}
+
 			     /* Lookup the option name */
 			     /* Lookup the option name */
 			r = lookup_token(option_name, &token.val);
 			r = lookup_token(option_name, &token.val);
 			if (!r) {
 			if (!r) {
@@ -913,28 +984,61 @@ static int parse_config(void)
 }
 }
 
 
 
 
-int tls_load_config(char* filename)
+/*
+ * Create configuration structures from configuration file
+ */
+tls_cfg_t* tls_load_config(str* filename)
 {
 {
 	str val;
 	str val;
+	char* file;
 	struct token token;
 	struct token token;
 
 
-	pstate.f = fopen(filename, "r");
+	file = get_pathname(filename);
+	if (!file) return 0;
+
+	pstate.f = fopen(file, "r");
 	if (pstate.f == NULL) {
 	if (pstate.f == NULL) {
-		ERR("Unable to open TLS config file '%s'\n", filename);
-		return -1;
+		ERR("Unable to open TLS config file '%s'\n", file);
+		pkg_free(file);
+		return 0;
 	}
 	}
-	pstate.file = basename(filename);
+	pstate.file = basename(file);
 	pstate.line = 1;
 	pstate.line = 1;
 	pstate.col = 0;
 	pstate.col = 0;
+	pstate.domain = 0;
 
 
+	pstate.cfg = tls_new_cfg();
+	if (!pstate.cfg) goto error;
+	
 	if (parse_config() < 0) goto error;
 	if (parse_config() < 0) goto error;
 
 
 	fclose(pstate.f);
 	fclose(pstate.f);
-	return 0;
+	pkg_free(file);
+	return pstate.cfg;
 
 
  error:
  error:
+	pkg_free(file);
+	if (pstate.cfg) tls_free_cfg(pstate.cfg);
 	fclose(pstate.f);
 	fclose(pstate.f);
-	return -1;
+	return 0;
+}
+
+/*
+ * Convert TLS method string to integer
+ */
+int tls_parse_method(str* method)
+{
+	struct parser_tab* r;
+
+	if (!method) {
+		ERR("BUG: Invalid parameter value\n");
+		return -1;
+	}
+
+	r = lookup_token(token_method, method);
+	if (!r) return -1;
+
+	return r->u.ival;
 }
 }
 
 
 
 

+ 8 - 1
modules/tls/tls_config.h

@@ -34,7 +34,14 @@
 #define _TLS_CONFIG_H
 #define _TLS_CONFIG_H
 
 
 #include "../../str.h"
 #include "../../str.h"
+#include "tls_domain.h"
+
+tls_cfg_t* tls_load_config(str* filename);
+
+/*
+ * Convert TLS method string to integer
+ */
+int tls_parse_method(str* method);
 
 
-int load_tls_config(char* filename);
 
 
 #endif /* _TLS_CONFIG_H */
 #endif /* _TLS_CONFIG_H */

+ 468 - 165
modules/tls/tls_domain.c

@@ -28,41 +28,20 @@
  */
  */
 
 
 #include <stdlib.h>
 #include <stdlib.h>
+#include <openssl/ssl.h>
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+# include <openssl/ui.h>
+#endif
 #include "../../ut.h"
 #include "../../ut.h"
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../pt.h"
 #include "../../pt.h"
 #include "tls_server.h"
 #include "tls_server.h"
+#include "tls_util.h"
+#include "tls_mod.h"
+#include "tls_init.h"
 #include "tls_domain.h"
 #include "tls_domain.h"
 
 
-tls_domain_t* tls_def_srv = 0;
-tls_domain_t* tls_def_cli = 0;
-tls_domain_t* tls_srv_list = 0;
-tls_domain_t* tls_cli_list = 0;
-
-
-/*
- * find domain with given ip and port 
- */
-tls_domain_t* tls_find_domain(int type, struct ip_addr *ip, unsigned short port)
-{
-	tls_domain_t *p;
-
-	if (type & TLS_DOMAIN_DEF) {
-		if (type & TLS_DOMAIN_SRV) return tls_def_srv;
-		else return tls_def_cli;
-	} else {
-		if (type & TLS_DOMAIN_SRV) p = tls_srv_list;
-		else p = tls_cli_list;
-	}
-
-	while (p) {
-		if ((p->port == port) && ip_addr_cmp(&p->ip, ip))
-			return p;
-		p = p->next;
-	}
-	return 0;
-}
-
 
 
 /*
 /*
  * create a new domain 
  * create a new domain 
@@ -71,7 +50,7 @@ tls_domain_t* tls_new_domain(int type, struct ip_addr *ip, unsigned short port)
 {
 {
 	tls_domain_t* d;
 	tls_domain_t* d;
 
 
-	d = pkg_malloc(sizeof(tls_domain_t));
+	d = shm_malloc(sizeof(tls_domain_t));
 	if (d == NULL) {
 	if (d == NULL) {
 		ERR("Memory allocation failure\n");
 		ERR("Memory allocation failure\n");
 		return 0;
 		return 0;
@@ -79,82 +58,59 @@ tls_domain_t* tls_new_domain(int type, struct ip_addr *ip, unsigned short port)
 	memset(d, '\0', sizeof(tls_domain_t));
 	memset(d, '\0', sizeof(tls_domain_t));
 
 
 	d->type = type;
 	d->type = type;
-	if (type & TLS_DOMAIN_DEF) {
-		if (type & TLS_DOMAIN_SRV) {
-			     /* Default server domain */
-			d->cert_file = TLS_CERT_FILE;
-			d->pkey_file = TLS_PKEY_FILE;
-			d->verify_cert = 0;
-			d->verify_depth = 3;
-			d->ca_file = TLS_CA_FILE;
-			d->require_cert = 0;
-			d->method = TLS_USE_TLSv1;
-			tls_def_srv = d;
-		} else {
-			     /* Default client domain */
-			d->cert_file = 0;
-			d->pkey_file = 0;
-			d->verify_cert = 0;
-			d->verify_depth = 3;
-			d->ca_file = TLS_CA_FILE;
-			d->require_cert = 0;
-			d->method = TLS_USE_TLSv1;
-			tls_def_cli = d;
-		}		
-	} else {
-		memcpy(&d->ip, ip, sizeof(struct ip_addr));
-		d->port = port;
-		d->verify_cert = -1;
-		d->verify_depth = -1;
-		d->require_cert = -1;
-
-		if (type & TLS_DOMAIN_SRV) {
-			d->next = tls_srv_list;
-			tls_srv_list = d;
-		} else {
-			d->next = tls_cli_list;
-			tls_cli_list = d;
-		}
-	}
+	if (ip) memcpy(&d->ip, ip, sizeof(struct ip_addr));
+	d->port = port;
+	d->verify_cert = -1;
+	d->verify_depth = -1;
+	d->require_cert = -1;
 	return d;
 	return d;
+
+ error:
+	shm_free(d);
+	return 0;
 }
 }
 
 
 
 
-static void free_domain(tls_domain_t* d)
+/*
+ * Free all memory used by configuration domain
+ */
+void tls_free_domain(tls_domain_t* d)
 {
 {
 	int i;
 	int i;
 	if (!d) return;
 	if (!d) return;
 	if (d->ctx) {
 	if (d->ctx) {
-		if (*d->ctx) {
-			for(i = 0; i < process_count; i++) {
-				if ((*d->ctx)[i]) SSL_CTX_free((*d->ctx)[i]);
-			}
-			shm_free(*d->ctx);
+		for(i = 0; i < process_count; i++) {
+			if (d->ctx[i]) SSL_CTX_free(d->ctx[i]);
 		}
 		}
 		shm_free(d->ctx);
 		shm_free(d->ctx);
 	}
 	}
-	pkg_free(d);
+
+	if (d->cipher_list) shm_free(d->cipher_list);
+	if (d->ca_file) shm_free(d->ca_file);
+	if (d->pkey_file) shm_free(d->pkey_file);
+	if (d->cert_file) shm_free(d->cert_file);
+	shm_free(d);
 }
 }
 
 
 
 
 /*
 /*
  * clean up 
  * clean up 
  */
  */
-void tls_free_domains(void)
+void tls_free_cfg(tls_cfg_t* cfg)
 {
 {
 	tls_domain_t* p;
 	tls_domain_t* p;
-	while(tls_srv_list) {
-		p = tls_srv_list;
-		tls_srv_list = tls_srv_list->next;
-		free_domain(p);
-	}
-	while(tls_cli_list) {
-		p = tls_srv_list;
-		tls_srv_list = tls_srv_list->next;
-		free_domain(p);
-	}
-	if (tls_def_srv) free_domain(tls_def_srv);
-	if (tls_def_cli) free_domain(tls_def_cli);
+	while(cfg->srv_list) {
+		p = cfg->srv_list;
+		cfg->srv_list = cfg->srv_list->next;
+		tls_free_domain(p);
+	}
+	while(cfg->cli_list) {
+		p = cfg->cli_list;
+		cfg->cli_list = cfg->cli_list->next;
+		tls_free_domain(p);
+	}
+	if (cfg->srv_default) tls_free_domain(cfg->srv_default);
+	if (cfg->cli_default) tls_free_domain(cfg->cli_default);
 }
 }
 
 
 
 
@@ -169,107 +125,328 @@ char* tls_domain_str(tls_domain_t* d)
 	buf[0] = '\0';
 	buf[0] = '\0';
 	p = buf;
 	p = buf;
 	p = strcat(p, d->type & TLS_DOMAIN_SRV ? "TLSs<" : "TLSc<");
 	p = strcat(p, d->type & TLS_DOMAIN_SRV ? "TLSs<" : "TLSc<");
-	if (d->ip.len) {
+	if (d->type & TLS_DOMAIN_DEF) {
+		p = strcat(p, "default>");
+	} else {
 		p = strcat(p, ip_addr2a(&d->ip));
 		p = strcat(p, ip_addr2a(&d->ip));
 		p = strcat(p, ":");
 		p = strcat(p, ":");
 		p = strcat(p, int2str(d->port, 0));
 		p = strcat(p, int2str(d->port, 0));
 		p = strcat(p, ">");
 		p = strcat(p, ">");
-	} else {
-		p = strcat(p, "default>");
 	}
 	}
 	return buf;
 	return buf;
 }
 }
 
 
 
 
 /*
 /*
- * Initialize all domain attributes from default domains
- * if necessary
+ * Initialize parameters that have not been configured from
+ * parent domain (usualy one of default domains
  */
  */
-static int fix_domain(tls_domain_t* d, tls_domain_t* def)
+static int fill_missing(tls_domain_t* d, tls_domain_t* parent)
 {
 {
-	d->ctx = (SSL_CTX***)shm_malloc(sizeof(SSL_CTX**));
-	if (!d->ctx) {
-		ERR("No shared memory left\n");
-		return -1;
-	}
-	*d->ctx = 0;
-
-	if (d->method == TLS_METHOD_UNSPEC) {
-		INFO("%s: Method not configured, using default value %d\n",
-		     tls_domain_str(d), def->method);
-		d->method = def->method;
-	} else {
-		INFO("%s: using TLS method %d\n",
-		     tls_domain_str(d), d->method);
-	}
+	if (d->method == TLS_METHOD_UNSPEC) d->method = parent->method;
+	LOG(L_INFO, "%s: tls_method=%d\n", tls_domain_str(d), d->method);
 	
 	
 	if (d->method < 1 || d->method >= TLS_METHOD_MAX) {
 	if (d->method < 1 || d->method >= TLS_METHOD_MAX) {
 		ERR("%s: Invalid TLS method value\n", tls_domain_str(d));
 		ERR("%s: Invalid TLS method value\n", tls_domain_str(d));
 		return -1;
 		return -1;
 	}
 	}
 	
 	
+	if (!d->cert_file && 
+	    shm_asciiz_dup(&d->cert_file, parent->cert_file) < 0) return -1;
+	LOG(L_INFO, "%s: certificate='%s'\n", tls_domain_str(d), d->cert_file);
+	
+	if (!d->ca_file &&
+	    shm_asciiz_dup(&d->ca_file, parent->ca_file) < 0) return -1;
+	LOG(L_INFO, "%s: ca_list='%s'\n", tls_domain_str(d), d->ca_file);
+	
+	if (d->require_cert == -1) d->require_cert = parent->require_cert;
+	LOG(L_INFO, "%s: require_certificate=%d\n", tls_domain_str(d), d->require_cert);
+	
+	if (!d->cipher_list &&
+	    shm_asciiz_dup(&d->cipher_list, parent->cipher_list) < 0) return -1;
+	LOG(L_INFO, "%s: cipher_list='%s'\n", tls_domain_str(d), d->cipher_list);
+	
+	if (!d->pkey_file &&
+	    shm_asciiz_dup(&d->pkey_file, parent->pkey_file) < 0) return -1;
+	LOG(L_INFO, "%s: private_key='%s'\n", tls_domain_str(d), d->pkey_file);
+	
+	if (d->verify_cert == -1) d->verify_cert = parent->verify_cert;
+	LOG(L_INFO, "%s: verify_certificate=%d\n", tls_domain_str(d), d->verify_cert);
+	
+	if (d->verify_depth == -1) d->verify_depth = parent->verify_depth;
+	LOG(L_INFO, "%s: verify_depth=%d\n", tls_domain_str(d), d->verify_depth);
+
+	return 0;
+}
+
+
+/* 
+ * Load certificate from file 
+ */
+static int load_cert(tls_domain_t* d)
+{
+	int i;
+
 	if (!d->cert_file) {
 	if (!d->cert_file) {
-		INFO("%s: No certificate configured, using default '%s'\n",
-		     tls_domain_str(d), def->cert_file);
-		d->cert_file = def->cert_file;
-	} else {
-		INFO("%s: using certificate '%s'\n",
-		     tls_domain_str(d), d->cert_file);
+		DBG("%s: No certificate configured\n", tls_domain_str(d));
+		return 0;
 	}
 	}
-	
+
+	for(i = 0; i < process_count; i++) {
+		if (!SSL_CTX_use_certificate_chain_file(d->ctx[i], d->cert_file)) {
+			ERR("%s: Unable to load certificate file '%s'\n",
+			    tls_domain_str(d), d->cert_file);
+			TLS_ERR("load_cert:");
+			return -1;
+		}
+		
+	}
+	return 0;
+}
+
+
+/* 
+ * Load CA list from file 
+ */
+static int load_ca_list(tls_domain_t* d)
+{
+	int i;
+
 	if (!d->ca_file) {
 	if (!d->ca_file) {
-		INFO("%s: No CA list configured, using default '%s'\n",
-		     tls_domain_str(d), def->ca_file);
-		d->ca_file = def->ca_file;
-	} else {
-		INFO("%s: using CA list '%s'\n",
-		     tls_domain_str(d), d->ca_file);
+		DBG("%s: No CA list configured\n", tls_domain_str(d));
+		return 0;
 	}
 	}
-	
-	if (d->require_cert == -1) {
-		INFO("%s: require_certificate not configured, using default value %d\n",
-		     tls_domain_str(d), def->require_cert);
-		d->require_cert = def->require_cert;
+
+	for(i = 0; i < process_count; i++) {
+		if (SSL_CTX_load_verify_locations(d->ctx[i], d->ca_file, 0) != 1) {
+			ERR("%s: Unable to load CA list '%s'\n", tls_domain_str(d), d->ca_file);
+			TLS_ERR("load_ca_list:");
+			return -1;
+		}
+		SSL_CTX_set_client_CA_list(d->ctx[i], SSL_load_client_CA_file(d->ca_file));
+		if (SSL_CTX_get_client_CA_list(d->ctx[i]) == 0) {
+			ERR("%s: Error while setting client CA list\n", tls_domain_str(d));
+			TLS_ERR("load_ca_list:");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+
+/* 
+ * Configure cipher list 
+ */
+static int set_cipher_list(tls_domain_t* d)
+{
+	int i;
+
+	if (!d->cipher_list) return 0;
+	for(i = 0; i < process_count; i++) {
+		if (SSL_CTX_set_cipher_list(d->ctx[i], d->cipher_list) == 0 ) {
+			ERR("%s: Failure to set SSL context cipher list\n", tls_domain_str(d));
+			return -1;
+		}
+	}
+	return 0;
+}
+
+
+/* 
+ * Enable/disable certificate verification 
+ */
+static int set_verification(tls_domain_t* d)
+{
+	int verify_mode, i;
+
+	if (d->require_cert) {
+		verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+		LOG(L_INFO, "%s: %s MUST present valid certificate\n", 
+		     tls_domain_str(d), d->type & TLS_DOMAIN_SRV ? "Client" : "Server");
 	} else {
 	} else {
-		INFO("%s: require_certificate = %d\n",
-		     tls_domain_str(d), d->require_cert);
+		if (d->verify_cert) {
+			verify_mode = SSL_VERIFY_PEER;
+			if (d->type & TLS_DOMAIN_SRV) {
+				LOG(L_INFO, "%s: IF client provides certificate then it MUST be valid\n", 
+				     tls_domain_str(d));
+			} else {
+				LOG(L_INFO, "%s: Server MUST present valid certificate\n", 
+				     tls_domain_str(d));
+			}
+		} else {
+			verify_mode = SSL_VERIFY_NONE;
+			if (d->type & TLS_DOMAIN_SRV) {
+				LOG(L_INFO, "%s: No client certificate required and no checks performed\n", 
+				     tls_domain_str(d));
+			} else {
+				LOG(L_INFO, "%s: Server MAY present invalid certificate\n", 
+				     tls_domain_str(d));
+			}
+		}
 	}
 	}
 	
 	
-	if (!d->cipher_list) {
-		INFO("%s: Cipher list not configured, using default value %s\n",
-		     tls_domain_str(d), def->cipher_list);
-		d->cipher_list = def->cipher_list;
-	} else {
-		INFO("%s: using cipher list %s\n",
-		     tls_domain_str(d), d->cipher_list);
+	for(i = 0; i < process_count; i++) {
+		SSL_CTX_set_verify(d->ctx[i], verify_mode, 0);
+		SSL_CTX_set_verify_depth(d->ctx[i], d->verify_depth);
+		
+	}
+	return 0;
+}
+
+
+/* 
+ * Configure generic SSL parameters 
+ */
+static int set_ssl_options(tls_domain_t* d)
+{
+	int i;
+	for(i = 0; i < process_count; i++) {
+#if OPENSSL_VERSION_NUMBER >= 0x000907000
+		SSL_CTX_set_options(d->ctx[i], 
+				    SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE);
+#else
+		SSL_CTX_set_options(d->ctx[i], 
+				    SSL_OP_ALL);
+#endif
+	}
+	return 0;
+}
+
+
+/* 
+ * Configure session cache parameters 
+ */
+static int set_session_cache(tls_domain_t* d)
+{
+	int i;
+	for(i = 0; i < process_count; i++) {
+		     /* janakj: I am not sure if session cache makes sense in ser, session 
+		      * cache is stored in SSL_CTX and we have one SSL_CTX per process, thus 
+		      * sessions among processes will not be reused
+		      */
+		SSL_CTX_set_session_cache_mode(d->ctx[i], 
+				   tls_session_cache ? SSL_SESS_CACHE_SERVER : SSL_SESS_CACHE_OFF);
+		SSL_CTX_set_session_id_context(d->ctx[i], 
+					       (unsigned char*)tls_session_id.s, tls_session_id.len);
+	}
+	return 0;
+}
+
+
+/*
+ * Initialize all domain attributes from default domains
+ * if necessary
+ */
+static int fix_domain(tls_domain_t* d, tls_domain_t* def)
+{
+	int i;
+
+	if (fill_missing(d, def) < 0) return -1;
+
+	d->ctx = (SSL_CTX**)shm_malloc(sizeof(SSL_CTX*) * process_count);
+	if (!d->ctx) {
+		ERR("%s: Cannot allocate shared memory\n", tls_domain_str(d));
+		return -1;
+	}
+	memset(d->ctx, 0, sizeof(SSL_CTX*) * process_count);
+	for(i = 0; i < process_count; i++) {
+		d->ctx[i] = SSL_CTX_new(ssl_methods[d->method - 1]);
+		if (d->ctx[i] == NULL) {
+			ERR("%s: Cannot create SSL context\n", tls_domain_str(d));
+			return -1;
+		}
 	}
 	}
 	
 	
-	if (!d->pkey_file) {
-		INFO("%s: No private key configured, using default '%s'\n",
-		     tls_domain_str(d), def->pkey_file);
-		d->pkey_file = def->pkey_file;
-	} else {
-		INFO("%s: using private key '%s'\n",
-		     tls_domain_str(d), d->pkey_file);
+	if (load_cert(d) < 0) return -1;
+	if (load_ca_list(d) < 0) return -1;
+	if (set_cipher_list(d) < 0) return -1;
+	if (set_verification(d) < 0) return -1;
+	if (set_ssl_options(d) < 0) return -1;
+	if (set_session_cache(d) < 0) return -1;
+
+	return 0;
+}
+
+
+static int passwd_cb(char *buf, int size, int rwflag, void *filename)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L	
+	UI             *ui;
+	const char     *prompt;
+	
+	ui = UI_new();
+	if (ui == NULL)
+		goto err;
+
+	prompt = UI_construct_prompt(ui, "passphrase", filename);
+	UI_add_input_string(ui, prompt, 0, buf, 0, size - 1);
+	UI_process(ui);
+	UI_free(ui);
+	return strlen(buf);
+ 
+ err:
+	ERR("passwd_cb: Error in passwd_cb\n");
+	if (ui) {
+		UI_free(ui);
 	}
 	}
+	return 0;
 	
 	
-	if (d->verify_cert == -1) {
-		INFO("%s: verify_certificate not configured, using default value %d\n",
-		     tls_domain_str(d), def->verify_cert);
-		d->verify_cert = def->verify_cert;
-	} else {
-		INFO("%s: using verify_certificate = %d\n",
-		     tls_domain_str(d), d->verify_cert);
+#else
+	if (des_read_pw_string(buf, size-1, "Enter Private Key password:", 0)) {
+		ERR("Error in passwd_cb\n");
+		return 0;
 	}
 	}
+	return strlen(buf);
+#endif
+}
+
+
+#define NUM_RETRIES 3
+/*
+ * load a private key from a file 
+ */
+static int load_private_key(tls_domain_t* d)
+{
+	int idx, ret_pwd, i;
 	
 	
-	if (d->verify_depth == -1) {
-		INFO("%s: verify_depth not configured, using default value %d\n",
-		     tls_domain_str(d), def->verify_depth);
-		d->verify_depth = def->verify_depth;
-	} else {
-		INFO("%s: using verify_depth = %d\n",
-		     tls_domain_str(d), d->verify_depth);
+	if (!d->pkey_file) {
+		DBG("%s: No private key specified\n", tls_domain_str(d));
+		return 0;
 	}
 	}
+
+	for(i = 0; i < process_count; i++) {
+		SSL_CTX_set_default_passwd_cb(d->ctx[i], passwd_cb);
+		SSL_CTX_set_default_passwd_cb_userdata(d->ctx[i], d->pkey_file);
+		
+		for(idx = 0, ret_pwd = 0; idx < NUM_RETRIES; idx++) {
+			ret_pwd = SSL_CTX_use_PrivateKey_file(d->ctx[i], d->pkey_file, SSL_FILETYPE_PEM);
+			if (ret_pwd) {
+				break;
+			} else {
+				ERR("%s: Unable to load private key '%s'\n",
+				    tls_domain_str(d), d->pkey_file);
+				TLS_ERR("load_private_key:");
+				continue;
+			}
+		}
+		
+		if (!ret_pwd) {
+			ERR("%s: Unable to load private key file '%s'\n", 
+			    tls_domain_str(d), d->pkey_file);
+			TLS_ERR("load_private_key:");
+			return -1;
+		}
+		
+		if (!SSL_CTX_check_private_key(d->ctx[i])) {
+			ERR("%s: Key '%s' does not match the public key of the certificate\n", 
+			    tls_domain_str(d), d->pkey_file);
+			TLS_ERR("load_private_key:");
+			return -1;
+		}
+	}		
+
+	DBG("%s: Key '%s' successfuly loaded\n",
+	    tls_domain_str(d), d->pkey_file);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -278,25 +455,151 @@ static int fix_domain(tls_domain_t* d, tls_domain_t* def)
  * Initialize attributes of all domains from default domains
  * Initialize attributes of all domains from default domains
  * if necessary
  * if necessary
  */
  */
-int tls_fix_domains(void)
+int tls_fix_cfg(tls_cfg_t* cfg, tls_domain_t* srv_defaults, tls_domain_t* cli_defaults)
 {
 {
 	tls_domain_t* d;
 	tls_domain_t* d;
 
 
-	if (!tls_def_cli) tls_def_cli = tls_new_domain(TLS_DOMAIN_DEF | TLS_DOMAIN_CLI, 0, 0);
-	if (!tls_def_srv) tls_def_srv = tls_new_domain(TLS_DOMAIN_DEF | TLS_DOMAIN_SRV, 0, 0);
+	if (!cfg->cli_default) {
+		cfg->cli_default = tls_new_domain(TLS_DOMAIN_DEF | TLS_DOMAIN_CLI, 0, 0);
+	}
+
+	if (!cfg->srv_default) {
+		cfg->srv_default = tls_new_domain(TLS_DOMAIN_DEF | TLS_DOMAIN_SRV, 0, 0);
+	}
+
+	if (fix_domain(cfg->srv_default, srv_defaults) < 0) return -1;
+	if (fix_domain(cfg->cli_default, cli_defaults) < 0) return -1;
 
 
-	d = tls_srv_list;
+	d = cfg->srv_list;
 	while (d) {
 	while (d) {
-		if (fix_domain(d, tls_def_srv) < 0) return -1;
+		if (fix_domain(d, srv_defaults) < 0) return -1;
 		d = d->next;
 		d = d->next;
 	}
 	}
 
 
-	d = tls_cli_list;
+	d = cfg->cli_list;
 	while (d) {
 	while (d) {
-		if (fix_domain(d, tls_def_cli) < 0) return -1;
+		if (fix_domain(d, cli_defaults) < 0) return -1;
+		d = d->next;
+	}
+
+	     /* Ask for passwords as the last step */
+	d = cfg->srv_list;
+	while(d) {
+		if (load_private_key(d) < 0) return -1;
 		d = d->next;
 		d = d->next;
 	}
 	}
-	if (fix_domain(tls_def_srv, tls_def_srv) < 0) return -1;
-	if (fix_domain(tls_def_cli, tls_def_cli) < 0) return -1;
+
+	d = cfg->cli_list;
+	while(d) {
+		if (load_private_key(d) < 0) return -1;
+		d = d->next;
+	}
+
+	if (load_private_key(cfg->srv_default) < 0) return -1;
+	if (load_private_key(cfg->cli_default) < 0) return -1;
+
+	return 0;
+}
+
+
+/*
+ * Create new configuration structure
+ */
+tls_cfg_t* tls_new_cfg(void)
+{
+	tls_cfg_t* r;
+
+	r = (tls_cfg_t*)shm_malloc(sizeof(tls_cfg_t));
+	if (!r) {
+		ERR("No memory left\n");
+		return 0;
+	}
+	memset(r, 0, sizeof(tls_cfg_t));
+	return r;
+}
+
+
+/*
+ * Lookup TLS configuration based on type, ip, and port
+ */
+tls_domain_t* tls_lookup_cfg(tls_cfg_t* cfg, int type, struct ip_addr* ip, unsigned short port)
+{
+	tls_domain_t *p;
+
+	if (type & TLS_DOMAIN_DEF) {
+		if (type & TLS_DOMAIN_SRV) return cfg->srv_default;
+		else return cfg->cli_default;
+	} else {
+		if (type & TLS_DOMAIN_SRV) p = cfg->srv_list;
+		else p = cfg->cli_list;
+	}
+
+	while (p) {
+		if ((p->port == port) && ip_addr_cmp(&p->ip, ip))
+			return p;
+		p = p->next;
+	}
+
+	     /* No matching domain found, return default */
+	if (type & TLS_DOMAIN_SRV) return cfg->srv_default;
+	else return cfg->cli_default;
+}
+
+
+/*
+ * Check whether configuration domain exists
+ */
+static int domain_exists(tls_cfg_t* cfg, tls_domain_t* d)
+{
+	tls_domain_t *p;
+
+	if (d->type & TLS_DOMAIN_DEF) {
+		if (d->type & TLS_DOMAIN_SRV) return cfg->srv_default != NULL;
+		else return cfg->cli_default != NULL;
+	} else {
+		if (d->type & TLS_DOMAIN_SRV) p = cfg->srv_list;
+		else p = cfg->cli_list;
+	}
+
+	while (p) {
+		if ((p->port == d->port) && ip_addr_cmp(&p->ip, &d->ip))
+			return 1;
+		p = p->next;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Add a domain to the configuration set
+ */
+int tls_add_domain(tls_cfg_t* cfg, tls_domain_t* d)
+{
+	tls_domain_t* p;
+
+	if (!cfg) {
+		ERR("TLS configuration structure missing\n");
+		return -1;
+	}
+
+	     /* Make sure the domain does not exist */
+	if (domain_exists(cfg, d)) return 1;
+
+	if (d->type & TLS_DOMAIN_DEF) {
+		if (d->type & TLS_DOMAIN_CLI) {
+			cfg->cli_default = d;
+		} else {
+			cfg->srv_default = d;
+		}
+	} else {
+		if (d->type & TLS_DOMAIN_SRV) {
+			d->next = cfg->srv_list;
+			cfg->srv_list = d;
+		} else {
+			d->next = cfg->cli_list;
+			cfg->cli_list = d;
+		}
+	}
 	return 0;
 	return 0;
 }
 }

+ 51 - 13
modules/tls/tls_domain.h

@@ -35,6 +35,9 @@
 #include <openssl/ssl.h>
 #include <openssl/ssl.h>
 
 
 
 
+/*
+ * Available TLS methods
+ */
 enum tls_method {
 enum tls_method {
 	TLS_METHOD_UNSPEC = 0,
 	TLS_METHOD_UNSPEC = 0,
 	TLS_USE_SSLv2_cli,
 	TLS_USE_SSLv2_cli,
@@ -52,20 +55,25 @@ enum tls_method {
 	TLS_METHOD_MAX
 	TLS_METHOD_MAX
 };
 };
 
 
+
+/*
+ * TLS configuration domain type
+ */
 enum tls_domain_type {
 enum tls_domain_type {
 	TLS_DOMAIN_DEF = (1 << 0), /* Default domain */
 	TLS_DOMAIN_DEF = (1 << 0), /* Default domain */
 	TLS_DOMAIN_SRV = (1 << 1), /* Server domain */
 	TLS_DOMAIN_SRV = (1 << 1), /* Server domain */
 	TLS_DOMAIN_CLI = (1 << 2)  /* Client domain */
 	TLS_DOMAIN_CLI = (1 << 2)  /* Client domain */
 };
 };
 
 
+
 /*
 /*
- * separate configuration per ip:port 
+ * separate configuration per ip:port
  */
  */
 typedef struct tls_domain {
 typedef struct tls_domain {
 	int type;
 	int type;
 	struct ip_addr ip;
 	struct ip_addr ip;
 	unsigned short port;
 	unsigned short port;
-	SSL_CTX*** ctx;     /* Pointer to the array is stored in shm mem */
+	SSL_CTX** ctx;
 	char* cert_file;
 	char* cert_file;
 	char* pkey_file;
 	char* pkey_file;
 	int verify_cert;
 	int verify_cert;
@@ -77,17 +85,19 @@ typedef struct tls_domain {
 	struct tls_domain* next;
 	struct tls_domain* next;
 } tls_domain_t;
 } tls_domain_t;
 
 
-extern tls_domain_t* tls_def_srv; /* Default server domain */
-extern tls_domain_t* tls_def_cli; /* Default client domain */
-extern tls_domain_t* tls_srv_list;
-extern tls_domain_t* tls_cli_list;
 
 
 /*
 /*
- * find domain with given ip and port, if ip == NULL then the
- * default domain will be returned
+ * TLS configuration structures
  */
  */
-tls_domain_t *tls_find_domain(int type, struct ip_addr *ip,
-			      unsigned short port);
+typedef struct tls_cfg {
+	tls_domain_t* srv_default; /* Default server domain */
+	tls_domain_t* cli_default; /* Default client domain */
+	tls_domain_t* srv_list;    /* Server domain list */
+	tls_domain_t* cli_list;    /* Client domain list */
+	struct tls_cfg* next;      /* Next element in the garbage list */
+	int ref_count;             /* How many connections use this configuration */
+} tls_cfg_t;
+
 
 
 /*
 /*
  * create a new domain 
  * create a new domain 
@@ -95,10 +105,11 @@ tls_domain_t *tls_find_domain(int type, struct ip_addr *ip,
 tls_domain_t *tls_new_domain(int type, struct ip_addr *ip, 
 tls_domain_t *tls_new_domain(int type, struct ip_addr *ip, 
 			     unsigned short port);
 			     unsigned short port);
 
 
+
 /*
 /*
- * clean up 
+ * Free all memory used for configuration domain
  */
  */
-void tls_free_domains(void);
+void tls_free_domain(tls_domain_t* d);
 
 
 
 
 /*
 /*
@@ -106,9 +117,36 @@ void tls_free_domains(void);
  */
  */
 char* tls_domain_str(tls_domain_t* d);
 char* tls_domain_str(tls_domain_t* d);
 
 
+
+
+/*
+ * Create new instance of TLS configuration data
+ */
+tls_cfg_t* tls_new_cfg(void);
+
+
+/*
+ * Add a new configuration domain
+ */
+int tls_add_domain(tls_cfg_t* cfg, tls_domain_t* d);
+
+
 /*
 /*
  * Fill in missing parameters
  * Fill in missing parameters
  */
  */
-int tls_fix_domains(void);
+int tls_fix_cfg(tls_cfg_t* cfg, tls_domain_t* srv_defaults, tls_domain_t* cli_defaults);
+
+
+/*
+ * Lookup TLS configuration
+ */
+tls_domain_t* tls_lookup_cfg(tls_cfg_t* cfg, int type, struct ip_addr* ip, unsigned short port);
+
+
+/*
+ * Free TLS configuration data
+ */
+void tls_free_cfg(tls_cfg_t* cfg);
+
 
 
 #endif /* _TLS_DOMAIN_H */
 #endif /* _TLS_DOMAIN_H */

+ 12 - 287
modules/tls/tls_init.c

@@ -34,10 +34,6 @@
 #include <unistd.h>
 #include <unistd.h>
 
 
 #include <openssl/ssl.h>
 #include <openssl/ssl.h>
-#include <openssl/opensslv.h>
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
-# include <openssl/ui.h>
-#endif
 
 
  
  
 #include "../../dprint.h"
 #include "../../dprint.h"
@@ -70,7 +66,7 @@
 #endif
 #endif
 
 
 
 
-static SSL_METHOD* ssl_methods[TLS_USE_SSLv23 + 1];
+SSL_METHOD* ssl_methods[TLS_USE_SSLv23 + 1];
 
 
 
 
 /*
 /*
@@ -95,39 +91,6 @@ static void ser_free(void *ptr)
 }
 }
 
 
 
 
-static int passwd_cb(char *buf, int size, int rwflag, void *filename)
-{
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L	
-	UI             *ui;
-	const char     *prompt;
-	
-	ui = UI_new();
-	if (ui == NULL)
-		goto err;
-
-	prompt = UI_construct_prompt(ui, "passphrase", filename);
-	UI_add_input_string(ui, prompt, 0, buf, 0, size - 1);
-	UI_process(ui);
-	UI_free(ui);
-	return strlen(buf);
- 
- err:
-	ERR("passwd_cb: Error in passwd_cb\n");
-	if (ui) {
-		UI_free(ui);
-	}
-	return 0;
-	
-#else
-	if (des_read_pw_string(buf, size-1, "Enter Private Key password:", 0)) {
-		ERR("Error in passwd_cb\n");
-		return 0;
-	}
-	return strlen(buf);
-#endif
-}
-
-
 /*
 /*
  * Initialize TLS socket
  * Initialize TLS socket
  */
  */
@@ -156,109 +119,6 @@ int tls_init(struct socket_info *si)
 }
 }
 
 
 
 
-#define NUM_RETRIES 3
-/*
- * load a private key from a file 
- */
-static int load_private_key(tls_domain_t* d)
-{
-	int idx, ret_pwd, i;
-	
-	if (!d->pkey_file) {
-		DBG("%s: No private key specified\n", tls_domain_str(d));
-		return 0;
-	}
-
-	for(i = 0; i < process_count; i++) {
-		SSL_CTX_set_default_passwd_cb((*d->ctx)[i], passwd_cb);
-		SSL_CTX_set_default_passwd_cb_userdata((*d->ctx)[i], d->pkey_file);
-		
-		for(idx = 0, ret_pwd = 0; idx < NUM_RETRIES; idx++) {
-			ret_pwd = SSL_CTX_use_PrivateKey_file((*d->ctx)[i], d->pkey_file, SSL_FILETYPE_PEM);
-			if (ret_pwd) {
-				break;
-			} else {
-				ERR("%s: Unable to load private key '%s'\n",
-				    tls_domain_str(d), d->pkey_file);
-				TLS_ERR("load_private_key:");
-				continue;
-			}
-		}
-		
-		if (!ret_pwd) {
-			ERR("%s: Unable to load private key file '%s'\n", 
-			    tls_domain_str(d), d->pkey_file);
-			TLS_ERR("load_private_key:");
-			return -1;
-		}
-		
-		if (!SSL_CTX_check_private_key((*d->ctx)[i])) {
-			ERR("%s: Key '%s' does not match the public key of the certificate\n", 
-			    tls_domain_str(d), d->pkey_file);
-			TLS_ERR("load_private_key:");
-			return -1;
-		}
-	}		
-
-	DBG("%s: Key '%s' successfuly loaded\n",
-	    tls_domain_str(d), d->pkey_file);
-	return 0;
-}
-
-
-/* 
- * Load CA list from file 
- */
-static int load_ca_list(tls_domain_t* d)
-{
-	int i;
-
-	if (!d->ca_file) {
-		DBG("%s: No CA list configured\n", tls_domain_str(d));
-		return 0;
-	}
-
-	for(i = 0; i < process_count; i++) {
-		if (SSL_CTX_load_verify_locations((*d->ctx)[i], d->ca_file, 0) != 1) {
-			ERR("%s: Unable to load CA list '%s'\n", tls_domain_str(d), d->ca_file);
-			TLS_ERR("load_ca_list:");
-			return -1;
-		}
-		SSL_CTX_set_client_CA_list((*d->ctx)[i], SSL_load_client_CA_file(d->ca_file));
-		if (SSL_CTX_get_client_CA_list((*d->ctx)[i]) == 0) {
-			ERR("%s: Error while setting client CA list\n", tls_domain_str(d));
-			TLS_ERR("load_ca_list:");
-			return -1;
-		}
-	}
-	return 0;
-}
-
-
-/* 
- * Load certificate from file 
- */
-static int load_cert(tls_domain_t* d)
-{
-	int i;
-
-	if (!d->cert_file) {
-		DBG("%s: No certificate configured\n", tls_domain_str(d));
-		return 0;
-	}
-
-	for(i = 0; i < process_count; i++) {
-		if (!SSL_CTX_use_certificate_chain_file((*d->ctx)[i], d->cert_file)) {
-			ERR("%s: Unable to load certificate file '%s'\n",
-			    tls_domain_str(d), d->cert_file);
-			TLS_ERR("load_cert:");
-			return -1;
-		}
-		
-	}
-	return 0;
-}
-
 
 
 /*
 /*
  * initialize ssl methods 
  * initialize ssl methods 
@@ -283,103 +143,9 @@ static void init_ssl_methods(void)
 }
 }
 
 
 
 
-/* 
- * Configure cipher list 
- */
-static int set_cipher_list(tls_domain_t* d)
-{
-	int i;
-
-	if (!d->cipher_list) return 0;
-	for(i = 0; i < process_count; i++) {
-		if (SSL_CTX_set_cipher_list((*d->ctx)[i], d->cipher_list) == 0 ) {
-			ERR("%s: Failure to set SSL context cipher list\n", tls_domain_str(d));
-			return -1;
-		}
-	}
-	return 0;
-}
-
-
-/* 
- * Enable/disable certificate verification 
- */
-static int set_verification(tls_domain_t* d)
-{
-	int verify_mode, i;
 
 
-	if (d->require_cert) {
-		verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-		INFO("%s: %s MUST present valid certificate\n", 
-		     tls_domain_str(d), d->type & TLS_DOMAIN_SRV ? "Client" : "Server");
-	} else {
-		if (d->verify_cert) {
-			verify_mode = SSL_VERIFY_PEER;
-			if (d->type & TLS_DOMAIN_SRV) {
-				INFO("%s: IF client provides certificate then it MUST be valid\n", 
-				     tls_domain_str(d));
-			} else {
-				INFO("%s: Server MUST present valid certificate\n", 
-				     tls_domain_str(d));
-			}
-		} else {
-			verify_mode = SSL_VERIFY_NONE;
-			if (d->type & TLS_DOMAIN_SRV) {
-				INFO("%s: No client certificate required and no checks performed\n", 
-				     tls_domain_str(d));
-			} else {
-				INFO("%s: Server MAY present invalid certificate\n", 
-				     tls_domain_str(d));
-			}
-		}
-	}
-	
-	for(i = 0; i < process_count; i++) {
-		SSL_CTX_set_verify((*d->ctx)[i], verify_mode, 0);
-		SSL_CTX_set_verify_depth((*d->ctx)[i], d->verify_depth);
-		
-	}
-	return 0;
-}
 
 
 
 
-/* 
- * Configure generic SSL parameters 
- */
-static int set_ssl_options(tls_domain_t* d)
-{
-	int i;
-	for(i = 0; i < process_count; i++) {
-#if OPENSSL_VERSION_NUMBER >= 0x000907000
-		SSL_CTX_set_options((*d->ctx)[i], 
-				    SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE);
-#else
-		SSL_CTX_set_options((*d->ctx)[i], 
-				    SSL_OP_ALL);
-#endif
-	}
-	return 0;
-}
-
-
-/* 
- * Configure session cache parameters 
- */
-static int set_session_cache(tls_domain_t* d)
-{
-	int i;
-	for(i = 0; i < process_count; i++) {
-		     /* janakj: I am not sure if session cache makes sense in ser, session 
-		      * cache is stored in SSL_CTX and we have one SSL_CTX per process, thus 
-		      * sessions among processes will not be reused
-		      */
-		SSL_CTX_set_session_cache_mode((*d->ctx)[i], 
-				   tls_session_cache ? SSL_SESS_CACHE_SERVER : SSL_SESS_CACHE_OFF);
-		SSL_CTX_set_session_id_context((*d->ctx)[i], 
-					       (unsigned char*)tls_session_id.s, tls_session_id.len);
-	}
-	return 0;
-}
 
 
 
 
 /*
 /*
@@ -448,7 +214,6 @@ static int init_tls_compression(void)
 int init_tls(void)
 int init_tls(void)
 {
 {
 	struct socket_info* si;
 	struct socket_info* si;
-	tls_domain_t* d;
 
 
 #if OPENSSL_VERSION_NUMBER < 0x00907000L
 #if OPENSSL_VERSION_NUMBER < 0x00907000L
 	WARN("You are using an old version of OpenSSL (< 0.9.7). Upgrade!\n");
 	WARN("You are using an old version of OpenSSL (< 0.9.7). Upgrade!\n");
@@ -468,8 +233,6 @@ int init_tls(void)
 	SSL_load_error_strings();
 	SSL_load_error_strings();
 	init_ssl_methods();
 	init_ssl_methods();
 
 
-	if (tls_fix_domains() < 0) return -1;
-
 	     /* Now initialize TLS sockets */
 	     /* Now initialize TLS sockets */
 	for(si = tls_listen; si; si = si->next) {
 	for(si = tls_listen; si; si = si->next) {
 		if (tls_init(si) < 0)  return -1;
 		if (tls_init(si) < 0)  return -1;
@@ -485,66 +248,29 @@ int init_tls(void)
 #endif
 #endif
 	}
 	}
 
 
-	     /* Make sure that all configured domains have a corresponding listeining
-	      * socket
-	      */
-	d = tls_srv_list;
-	while(d) {
-		if (d->ip.len && !find_si(&d->ip, d->port, PROTO_TLS)) {
-			ERR("%s: No listening socket found\n", tls_domain_str(d));
-			return -1;
-		}
-		d = d->next;
-	}
-
 	return 0;
 	return 0;
 }
 }
 
 
 
 
 /*
 /*
- * Second step of TLS initialization
+ * Make sure that all server domains in the configuration have corresponding
+ * listening socket in SER
  */
  */
-int init_tls_child(void)
+int tls_check_sockets(tls_cfg_t* cfg)
 {
 {
-	tls_domain_t* lists[4] = {tls_def_cli, tls_def_srv, tls_cli_list, tls_srv_list};
 	tls_domain_t* d;
 	tls_domain_t* d;
-	int i, j;
 
 
-	for(j = 0; j < 4; j++) {
-		d = lists[j];
-
-		while (d) {
-			*d->ctx = (SSL_CTX**)shm_malloc(sizeof(SSL_CTX*) * process_count);
-			if (!*d->ctx) {
-				ERR("%s: Cannot allocate shared memory\n", tls_domain_str(d));
-				return -1;
-			}
-			memset(*d->ctx, 0, sizeof(SSL_CTX*) * process_count);
-			for(i = 0; i < process_count; i++) {
-				(*d->ctx)[i] = SSL_CTX_new(ssl_methods[d->method - 1]);
-				if ((*d->ctx)[i] == NULL) {
-					ERR("%s: Cannot create SSL context\n", tls_domain_str(d));
-					return -1;
-				}
-			}
-			
-			if (load_cert(d) < 0) return -1;
-			if (load_ca_list(d) < 0) return -1;
-			if (set_cipher_list(d) < 0) return -1;
-			if (set_verification(d) < 0) return -1;
-			if (set_ssl_options(d) < 0) return -1;
-			if (set_session_cache(d) < 0) return -1;
-			d = d->next;
-		}
+	if (!cfg) return 0;
 
 
-		d = lists[j];
-		while (d) {
-			if (load_private_key(d) < 0) return -1;
-			d = d->next;
+	d = cfg->srv_list;
+	while(d) {
+		if (d->ip.len && !find_si(&d->ip, d->port, PROTO_TLS)) {
+			ERR("%s: No listening socket found\n", tls_domain_str(d));
+			return -1;
 		}
 		}
+		d = d->next;
 	}
 	}
-
-        return 0;
+	return 0;
 }
 }
 
 
 
 
@@ -553,6 +279,5 @@ int init_tls_child(void)
  */
  */
 void destroy_tls(void)
 void destroy_tls(void)
 {
 {
-	tls_free_domains();
 	ERR_free_strings();
 	ERR_free_strings();
 }
 }

+ 9 - 7
modules/tls/tls_init.h

@@ -30,7 +30,11 @@
 #ifndef _TLS_INIT_H
 #ifndef _TLS_INIT_H
 #define _TLS_INIT_H
 #define _TLS_INIT_H
 
 
+#include <openssl/ssl.h>
 #include "../../ip_addr.h"
 #include "../../ip_addr.h"
+#include "tls_domain.h"
+
+extern SSL_METHOD* ssl_methods[];
 
 
 
 
 /*
 /*
@@ -39,13 +43,6 @@
 int init_tls(void);
 int init_tls(void);
 
 
 
 
-/*
- * Called from child_init, once the total number of
- * SER processes is known
- */
-int init_tls_child(void);
-
-
 /*
 /*
  * just once before cleanup 
  * just once before cleanup 
  */
  */
@@ -57,5 +54,10 @@ void destroy_tls(void);
  */
  */
 int tls_init(struct socket_info *si);
 int tls_init(struct socket_info *si);
 
 
+/*
+ * Make sure that all server domains in the configuration have corresponding
+ * listening socket in SER
+ */
+int tls_check_sockets(tls_cfg_t* cfg);
 
 
 #endif /* _TLS_INIT_H */
 #endif /* _TLS_INIT_H */

+ 127 - 274
modules/tls/tls_mod.c

@@ -41,6 +41,7 @@
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <arpa/inet.h>
+#include "../../locking.h"
 #include "../../sr_module.h"
 #include "../../sr_module.h"
 #include "../../ip_addr.h"
 #include "../../ip_addr.h"
 #include "../../trim.h"
 #include "../../trim.h"
@@ -51,6 +52,7 @@
 #include "tls_domain.h"
 #include "tls_domain.h"
 #include "tls_select.h"
 #include "tls_select.h"
 #include "tls_config.h"
 #include "tls_config.h"
+#include "tls_rpc.h"
 #include "tls_mod.h"
 #include "tls_mod.h"
 
 
 
 
@@ -60,6 +62,10 @@
  *   daemonize and thus has no console access
  *   daemonize and thus has no console access
  * - forward_tls and t_relay_to_tls should be here
  * - forward_tls and t_relay_to_tls should be here
  * add tls_log
  * add tls_log
+ * - Currently it is not possible to reset certificate in a domain,
+ *   for example if you specify client certificate in the default client
+ *   domain then there is no way to define another client domain which would
+ *   have no client certificate configured
  */
  */
 
 
 
 
@@ -68,26 +74,69 @@
  */
  */
 static int mod_init(void);
 static int mod_init(void);
 static void destroy(void);
 static void destroy(void);
-static int child_init(int rank);
-
-static int set_method      (modparam_t type, char* param);
-static int set_verify_cert (modparam_t type, char* param);
-static int set_verify_depth(modparam_t type, char* param);
-static int set_require_cert(modparam_t type, char* param);
-static int set_pkey_file   (modparam_t type, char* param);
-static int set_ca_list     (modparam_t type, char* param);
-static int set_certificate (modparam_t type, char* param);
-static int set_cipher_list (modparam_t type, char* param);
 
 
 MODULE_VERSION
 MODULE_VERSION
 
 
+/*
+ * Default settings for server domains when using external config file
+ */
+tls_domain_t srv_defaults = {
+	TLS_DOMAIN_DEF | TLS_DOMAIN_SRV,   /* Domain Type */
+	{},               /* IP address */
+	0,                /* Port number */
+	0,                /* SSL ctx */
+	TLS_CERT_FILE,    /* Certificate file */
+	TLS_PKEY_FILE,    /* Private key file */
+	0,                /* Verify certificate */
+	9,                /* Verify depth */
+	TLS_CA_FILE,      /* CA file */
+	0,                /* Require certificate */
+	0,                /* Cipher list */
+	TLS_USE_TLSv1,    /* TLS method */
+	0                 /* next */
+};
+
+
+/*
+ * Default settings for client domains when using external config file
+ */
+tls_domain_t cli_defaults = {
+	TLS_DOMAIN_DEF | TLS_DOMAIN_CLI,   /* Domain Type */
+	{},               /* IP address */
+	0,                /* Port number */
+	0,                /* SSL ctx */
+	0,                /* Certificate file */
+	0,                /* Private key file */
+	0,                /* Verify certificate */
+	9,                /* Verify depth */
+	TLS_CA_FILE,      /* CA file */
+	0,                /* Require certificate */
+	0,                /* Cipher list */
+	TLS_USE_TLSv1,    /* TLS method */
+	0                 /* next */
+};
+
+
+/*
+ * Defaults for client and server domains when using modparams
+ */
+static str tls_method = STR_STATIC_INIT("TLSv1");
+
+
 int tls_handshake_timeout = 120;
 int tls_handshake_timeout = 120;
 int tls_send_timeout = 120;
 int tls_send_timeout = 120;
 int tls_conn_timeout = 600;
 int tls_conn_timeout = 600;
 int tls_log = 3;
 int tls_log = 3;
 int tls_session_cache = 0;
 int tls_session_cache = 0;
 str tls_session_id = STR_STATIC_INIT("ser-tls-0.9.0");
 str tls_session_id = STR_STATIC_INIT("ser-tls-0.9.0");
-char* tls_config = 0;
+str tls_cfg_file = STR_NULL;
+
+
+/* Current TLS configuration */
+tls_cfg_t** tls_cfg = NULL;
+
+/* List lock, used by garbage collector */
+gen_lock_t* tls_cfg_lock = NULL;
 
 
 
 
 /*
 /*
@@ -102,21 +151,21 @@ static cmd_export_t cmds[] = {
  * Exported parameters
  * Exported parameters
  */
  */
 static param_export_t params[] = {
 static param_export_t params[] = {
-	{"method",              PARAM_STRING | PARAM_USE_FUNC, (void*)set_method      },
-	{"verify_certificate",  PARAM_STRING | PARAM_USE_FUNC, (void*)set_verify_cert },
-	{"verify_depth",        PARAM_STRING | PARAM_USE_FUNC, (void*)set_verify_depth},
-	{"require_certificate", PARAM_STRING | PARAM_USE_FUNC, (void*)set_require_cert},
-	{"private_key",         PARAM_STRING | PARAM_USE_FUNC, (void*)set_pkey_file   },
-	{"ca_list",             PARAM_STRING | PARAM_USE_FUNC, (void*)set_ca_list     },
-	{"certificate",         PARAM_STRING | PARAM_USE_FUNC, (void*)set_certificate },
-	{"cipher_list",         PARAM_STRING | PARAM_USE_FUNC, (void*)set_cipher_list },
-	{"handshake_timeout",   PARAM_INT,                     &tls_handshake_timeout },
-	{"send_timeout",        PARAM_INT,                     &tls_send_timeout      },
-	{"connection_timeout",  PARAM_INT,                     &tls_conn_timeout      },
-	{"tls_log",             PARAM_INT,                     &tls_log               },
-	{"session_cache",       PARAM_INT,                     &tls_session_cache     },
-	{"session_id",          PARAM_STR,                     &tls_session_id        },
-	{"config",              PARAM_STRING,                  &tls_config            },
+	{"tls_method",          PARAM_STR,    &tls_method               },
+	{"verify_certificate",  PARAM_INT,    &srv_defaults.verify_cert },
+	{"verify_depth",        PARAM_INT,    &srv_defaults.verify_depth},
+	{"require_certificate", PARAM_INT,    &srv_defaults.require_cert},
+	{"private_key",         PARAM_STRING, &srv_defaults.pkey_file   },
+	{"ca_list",             PARAM_STRING, &srv_defaults.ca_file     },
+	{"certificate",         PARAM_STRING, &srv_defaults.cert_file   },
+	{"cipher_list",         PARAM_STRING, &srv_defaults.cipher_list },
+	{"handshake_timeout",   PARAM_INT,    &tls_handshake_timeout    },
+	{"send_timeout",        PARAM_INT,    &tls_send_timeout         },
+	{"connection_timeout",  PARAM_INT,    &tls_conn_timeout         },
+	{"tls_log",             PARAM_INT,    &tls_log                  },
+	{"session_cache",       PARAM_INT,    &tls_session_cache        },
+	{"session_id",          PARAM_STR,    &tls_session_id           },
+	{"config",              PARAM_STR,    &tls_cfg_file             },
 	{0, 0, 0}
 	{0, 0, 0}
 };
 };
 
 
@@ -127,13 +176,13 @@ static param_export_t params[] = {
 struct module_exports exports = {
 struct module_exports exports = {
 	"tls",
 	"tls",
 	cmds,       /* Exported functions */
 	cmds,       /* Exported functions */
-	0,          /* RPC methods */
+	tls_rpc,    /* RPC methods */
 	params,     /* Exported parameters */
 	params,     /* Exported parameters */
 	mod_init,   /* module initialization function */
 	mod_init,   /* module initialization function */
 	0,          /* response function*/
 	0,          /* response function*/
 	destroy,    /* destroy function */
 	destroy,    /* destroy function */
 	0,          /* cancel function */
 	0,          /* cancel function */
-	child_init  /* per-child init function */
+	0           /* per-child init function */
 };
 };
 
 
 
 
@@ -141,7 +190,7 @@ struct module_exports exports = {
 transport_t tls_transport = {
 transport_t tls_transport = {
 	PROTO_TLS,
 	PROTO_TLS,
 	STR_STATIC_INIT("TLS"),
 	STR_STATIC_INIT("TLS"),
-	TRANSPORT_SECURE | TRANSPORT_DGRAM,
+	TRANSPORT_SECURE | TRANSPORT_STREAM,
 	{ 
 	{ 
 		.tcp = {
 		.tcp = {
 			tls_tcpconn_init,
 			tls_tcpconn_init,
@@ -156,280 +205,84 @@ transport_t tls_transport = {
 };
 };
 
 
 
 
-static int mod_init(void)
-{
-	if (tls_config) {
-		if (tls_load_config(tls_config) < 0) return -1;
-	}
-
-	if (init_tls() < 0) return -1;
-	
-	tls = &tls_transport;
-	register_select_table(tls_sel);
-	return 0;
-}
-
-
-static int child_init(int rank)
-{
-	if (rank == 1 && init_tls_child() < 0) return -1;
-	return 0;
-}
-
-
-static void destroy(void)
-{
-	destroy_tls();
-}
-
-
 /*
 /*
- * Parse TLS domain specifier, the function will modify the input
- * string
+ * Create TLS configuration from modparams
  */
  */
-static int parse_domain(int* type, struct ip_addr* ip, unsigned short* port, char** text, char* val)
+static tls_cfg_t* tls_use_modparams(void)
 {
 {
-	static char buf[1024];
-	static char ip_buf[IP_ADDR_MAX_STR_SIZE];
-	char* fmt, *comma;
-	char backup = 0;
-	str s;
-	int ret;
-
-	*type = 0;
-	s.s = val;
-	s.len = strlen(val);
-	trim_leading(&s);
-	if (s.len >= 1024) {
-		ERR("Input text is too long\n");
-		return -1;
-	}
-
-	if (*s.s == '@') {
-		*type |= TLS_DOMAIN_CLI;
-		s.s++;
-		s.len--;
-	} else {
-		*type |= TLS_DOMAIN_SRV;
-	}
-
-	if (!strchr(s.s, '=')) {
-		DBG("No TLS domain specifier found\n");
-		*text = s.s;
-		*type |= TLS_DOMAIN_DEF;
-		return 0;
-	}
-
-	memset(ip, 0, sizeof(struct ip_addr));
-	if (*s.s == '[') {
-		comma = strchr(s.s, ']');
-		if (comma) {
-			backup = *comma;
-			*comma = ' ';
-		}
-		ip->af = AF_INET6;
-		ip->len = 16;
-		fmt = "\[%s :%hd = %s";
-	} else {
-		comma = strchr(s.s, ':');
-		if (comma) {
-			backup = *comma;
-			*comma = ' ';
-		}
-		ip->af = AF_INET;
-		ip->len = 4;
-		fmt = "%s %hd = %s";
-	}
-
-	ret = sscanf(s.s, fmt, ip_buf, port, buf);
-       	if (comma) *comma = backup;
-	if (ret < 3) {
-		ERR("Error while parsing TLS domain specification: '%s'\n", s.s);
-		return -1;
-	}
+	tls_cfg_t* ret;
 	
 	
-	if (inet_pton(ip->af, ip_buf, ip->u.addr) <= 0) {
-		ERR("Invalid IP address in TLS domain: '%s'\n", ip_buf);
-		return -1;
-	}
+	ret = tls_new_cfg();
+	if (!ret) return;
 
 
-	*text = buf;
-	DBG("Found TLS domain: <%s>:<%d>,<%s>\n", ip_addr2a(ip), *port, *text);
-	return 0;
+	
 }
 }
 
 
 
 
-static tls_domain_t* lookup_domain(char** val, char* param)
+static int mod_init(void)
 {
 {
-	struct ip_addr ip;
-	unsigned short port;
-	tls_domain_t* d;
-	int ret, flags;
-	
-	flags = TLS_DOMAIN_SRV;
+	int method;
 
 
-        ret = parse_domain(&flags, &ip, &port, val, param);
-	if (ret < 0) {
-		ERR("Error while parsing TLS module parameter '%s'\n", param);
-		return 0;
+	     /* Convert tls_method parameter to integer */
+	method = tls_parse_method(&tls_method);
+	if (method < 0) {
+		ERR("Invalid tls_method parameter value\n");
+		return -1;
 	}
 	}
+	srv_defaults.method = method;
 
 
-	d = tls_find_domain(flags, &ip, port);
-	if (!d && !(d = tls_new_domain(flags, &ip, port))) {
-		ERR("Error while creating new TLS domain for '%s'\n", param);
-		return 0;
+	tls_cfg = (tls_cfg_t**)shm_malloc(sizeof(tls_cfg_t*));
+	if (!tls_cfg) {
+		ERR("Not enough shared memory left\n");
+		return -1;
 	}
 	}
-	return d;
-}
+	*tls_cfg = NULL;
 
 
+	tls = &tls_transport;
+	register_select_table(tls_sel);
 
 
-static int set_method(modparam_t type, char* param)
-{
-	tls_domain_t* d;
-	char* val;
-	
-	d = lookup_domain(&val, param);
-	if (!d) return -1;
+	if (init_tls() < 0) return -1;
 	
 	
-	if (!strcasecmp(val, "SSLv2")) {
-		d->method = TLS_USE_SSLv2;
-	} else if (!strcasecmp(val, "SSLv3")) {
-		d->method = TLS_USE_SSLv3;
-	} else if (!strcasecmp(val, "SSLv23")) {
-		d->method = TLS_USE_SSLv23;
-	} else if (!strcasecmp(val, "TLSv1")) {
-		d->method = TLS_USE_TLSv1;
-	} else {
-		ERR("Invalid tls::method parameter value: %s\n", val);
+	tls_cfg_lock = lock_alloc();
+	if (tls_cfg_lock == 0) {
+		ERR("Unable to create TLS configuration lock\n");
 		return -1;
 		return -1;
 	}
 	}
-	return 0;
-}
-
-static int set_verify_cert(modparam_t type, char* param)
-{
-	tls_domain_t* d;
-	char* val;
-
-	d = lookup_domain(&val, param);
-	if (!d) return -1;
-
-	if (!strcasecmp(val, "yes")     || 
-	    !strcasecmp(val, "true")    ||
-	    !strcasecmp(val, "on")      ||
-	    !strcasecmp(val, "enable")  ||
-	    !strcasecmp(val, "enabled") ||
-	    *val == '1') {
-		d->verify_cert = 1;
-		return 0;
-	}
-	
-	if (!strcasecmp(val, "no")       || 
-	    !strcasecmp(val, "false")    ||
-	    !strcasecmp(val, "off")      ||
-	    !strcasecmp(val, "disable")  ||
-	    !strcasecmp(val, "disabled") ||
-	    *val == '0') {
-		d->verify_cert = 0;
-		return 0;
+	if (lock_init(tls_cfg_lock) == 0) {
+		lock_dealloc(tls_cfg_lock);
+		ERR("Unable to initialize TLS configuration lock\n");
+		return -1;
 	}
 	}
-	ERR("Invalid tls::verify_certificate parameter value: '%s'\n", val);
-	return -1;
-}
-
-
-static int set_verify_depth(modparam_t type, char* param)
-{
-	tls_domain_t* d;
-	char* val;
-
-	d = lookup_domain(&val, param);
-	if (!d) return -1;
-
-	d->verify_depth = atoi(val);
-	return 0;
-}
 
 
-
-static int set_require_cert(modparam_t type, char* param)
-{
-	tls_domain_t* d;
-	char* val;
-
-	d = lookup_domain(&val, param);
-	if (!d) return -1;
-
-	if (!strcasecmp(val, "yes")     || 
-	    !strcasecmp(val, "true")    ||
-	    !strcasecmp(val, "on")      ||
-	    !strcasecmp(val, "enable")  ||
-	    !strcasecmp(val, "enabled") ||
-	    *val == '1') {
-		d->require_cert = 1;
-		return 0;
-	}
-	
-	if (!strcasecmp(val, "no")       || 
-	    !strcasecmp(val, "false")    ||
-	    !strcasecmp(val, "off")      ||
-	    !strcasecmp(val, "disable")  ||
-	    !strcasecmp(val, "disabled") ||
-	    *val == '0') {
-		d->require_cert = 0;
-		return 0;
+	if (tls_cfg_file.s) {
+		*tls_cfg = tls_load_config(&tls_cfg_file);
+		if (!(*tls_cfg)) return -1;
+		if (tls_fix_cfg(*tls_cfg, &srv_defaults, &cli_defaults) < 0) return -1;
+	} else {
+		*tls_cfg = tls_new_cfg();
+		if (!(*tls_cfg)) return -1;
+		if (tls_fix_cfg(*tls_cfg, &srv_defaults, &srv_defaults) < 0) return -1;
 	}
 	}
-	ERR("Invalid tls::require_certificate parameter value: '%s'\n", val);
-	return -1;
-}
-
-
-static int set_pkey_file(modparam_t type, char* param)
-{
-	tls_domain_t* d;
-	char* val;
-
-	d = lookup_domain(&val, param);
-	if (!d) return -1;
-	
-	d->pkey_file = val;
-	return 0;
-}
-
 
 
-static int set_ca_list(modparam_t type, char* param)
-{
-	tls_domain_t* d;
-	char* val;
+	if (tls_check_sockets(*tls_cfg) < 0) return -1;
 
 
-	d = lookup_domain(&val, param);
-	if (!d) return -1;
-	
-	d->ca_file = val;
 	return 0;
 	return 0;
 }
 }
 
 
 
 
-static int set_certificate(modparam_t type, char* param)
+static void destroy(void)
 {
 {
-	tls_domain_t* d;
-	char* val;
-
-	d = lookup_domain(&val, param);
-	if (!d) return -1;
-	
-	d->cert_file = val;
-	return 0;
-}
+	tls_cfg_t* ptr;
 
 
+	lock_destroy(tls_cfg_lock);
+	lock_dealloc(tls_cfg_lock);
 
 
-static int set_cipher_list(modparam_t type, char* param)
-{
-	tls_domain_t* d;
-	char* val;
-
-	d = lookup_domain(&val, param);
-	if (!d) return -1;
+	while(*tls_cfg) {
+		ptr = *tls_cfg;
+		*tls_cfg = (*tls_cfg)->next;
+		tls_free_cfg(ptr);
+	}
 
 
-	d->cipher_list = val;
-	return 0;
+	shm_free(tls_cfg);
+	destroy_tls();
 }
 }

+ 11 - 1
modules/tls/tls_mod.h

@@ -34,6 +34,8 @@
 #define _TLS_MOD_H
 #define _TLS_MOD_H
 
 
 #include "../../str.h"
 #include "../../str.h"
+#include "../../locking.h"
+#include "tls_domain.h"
 
 
 extern int tls_handshake_timeout;
 extern int tls_handshake_timeout;
 extern int tls_send_timeout;
 extern int tls_send_timeout;
@@ -41,6 +43,14 @@ extern int tls_conn_timeout;
 extern int tls_log;
 extern int tls_log;
 extern int tls_session_cache;
 extern int tls_session_cache;
 extern str tls_session_id;
 extern str tls_session_id;
-extern char* tls_config;
+
+/* Current TLS configuration */
+extern tls_cfg_t** tls_cfg;
+extern gen_lock_t* tls_cfg_lock;
+
+extern tls_domain_t cli_defaults;
+extern tls_domain_t srv_defaults;
+
+extern str tls_cfg_file;
 
 
 #endif /* _TLS_MOD_H */
 #endif /* _TLS_MOD_H */

+ 84 - 0
modules/tls/tls_rpc.c

@@ -0,0 +1,84 @@
+/*
+ * $Id$
+ *
+ * TLS module interface
+ *
+ * Copyright (C) 2001-2003 FhG FOKUS
+ * Copyright (C) 2004,2005 Free Software Foundation, Inc.
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "../../rpc.h"
+#include "tls_mod.h"
+#include "tls_domain.h"
+#include "tls_config.h"
+#include "tls_util.h"
+#include "tls_rpc.h"
+
+static const char* tls_reload_doc[2] = {
+	"Reload TLS configuration file",
+	0
+};
+
+static void tls_reload(rpc_t* rpc, void* ctx)
+{
+	tls_cfg_t* cfg;
+	
+	if (!tls_cfg_file.s) {
+		rpc->fault(ctx, 500, "No TLS configuration file configured");
+		return;
+	}
+
+	     /* Try to delete old configurations first */
+	collect_garbage();
+
+	cfg = tls_load_config(&tls_cfg_file);
+	if (!cfg) {
+		rpc->fault(ctx, 500, "Error while loading TLS configuration file (consult server log)");
+		return;
+	}
+
+	if (tls_fix_cfg(cfg, &srv_defaults, &cli_defaults) < 0) {
+		rpc->fault(ctx, 500, "Error while fixing TLS configuration (consult server log)");
+		goto error;
+	}
+	if (tls_check_sockets(cfg) < 0) {
+		rpc->fault(ctx, 500, "No server listening socket found for one of TLS domains (consult server log)");
+		goto error;
+	}
+
+	DBG("TLS configuration successfuly loaded");
+	cfg->next = (*tls_cfg);
+	*tls_cfg = cfg;
+	return;
+
+ error:
+	tls_free_cfg(cfg);
+	
+}
+
+rpc_export_t tls_rpc[] = {
+	{"tls.reload", tls_reload, tls_reload_doc, 0},
+	{0, 0, 0, 0}
+};

+ 34 - 0
modules/tls/tls_rpc.h

@@ -0,0 +1,34 @@
+/*
+ * $Id$
+ *
+ * TLS module interface
+ *
+ * Copyright (C) 2001-2003 FhG FOKUS
+ * Copyright (C) 2004,2005 Free Software Foundation, Inc.
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "../../rpc.h"
+
+extern rpc_export_t tls_rpc[];

+ 51 - 17
modules/tls/tls_server.c

@@ -1,4 +1,6 @@
 /*
 /*
+ * $Id$
+ *
  * Copyright (C) 2001-2003 FhG FOKUS
  * Copyright (C) 2001-2003 FhG FOKUS
  * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  * Copyright (C) 2005,2006 iptelorg GmbH
  * Copyright (C) 2005,2006 iptelorg GmbH
@@ -49,28 +51,55 @@
 static int tls_complete_init(struct tcp_connection* c)
 static int tls_complete_init(struct tcp_connection* c)
 {
 {
 	tls_domain_t* dom;
 	tls_domain_t* dom;
+	struct tls_extra_data* data = 0;
+	tls_cfg_t* cfg;
 	SSL* ssl;
 	SSL* ssl;
 
 
+	     /* Get current TLS configuration and increate reference
+	      * count immediately. There is no need to lock the structure
+	      * here, because it does not get deleted immediately. When
+	      * SER reloads TLS configuration it will put the old configuration
+	      * on a garbage queue and delete it later, so we know here that
+	      * the pointer we get from *tls_cfg will be valid for a while, at
+	      * least by the time this function finishes
+	      */
+	cfg = *tls_cfg;
+
+	     /* Increment the reference count in the configuration structure, this
+	      * is to ensure that, while on the garbage queue, the configuration does
+	      * not get deleted if there are still connection referencing its SSL_CTX
+	      */
+	cfg->ref_count++;
+
 	if (c->state == S_CONN_ACCEPT) {
 	if (c->state == S_CONN_ACCEPT) {
-		dom = tls_find_domain(TLS_DOMAIN_SRV, &c->rcv.dst_ip, c->rcv.dst_port);
-		if (!dom) dom = tls_def_srv;
+		dom = tls_lookup_cfg(cfg, TLS_DOMAIN_SRV, &c->rcv.dst_ip, c->rcv.dst_port);
 	} else if (c->state == S_CONN_CONNECT) {
 	} else if (c->state == S_CONN_CONNECT) {
-		dom = tls_find_domain(TLS_DOMAIN_CLI, &c->rcv.dst_ip, c->rcv.dst_port);
-		if (!dom) dom = tls_def_cli;
+		dom = tls_lookup_cfg(cfg, TLS_DOMAIN_CLI, &c->rcv.dst_ip, c->rcv.dst_port);
 	} else {
 	} else {
 		BUG("Invalid connection state (bug in TCP code)\n");
 		BUG("Invalid connection state (bug in TCP code)\n");
 		goto error;
 		goto error;
 	}
 	}
 	DBG("Using TLS domain %s\n", tls_domain_str(dom));
 	DBG("Using TLS domain %s\n", tls_domain_str(dom));
-	ssl = SSL_new((*dom->ctx)[process_no]);
 
 
-	if (ssl == 0) {
+	data = (struct tls_extra_data*)shm_malloc(sizeof(struct tls_extra_data));
+	if (!data) {
+		ERR("Not enough shared memory left\n");
+		goto error;
+	}
+	memset(data, '\0', sizeof(struct tls_extra_data));
+	data->ssl = SSL_new(dom->ctx[process_no]);
+	data->cfg = cfg;
+
+	if (data->ssl == 0) {
 		TLS_ERR("Failed to create SSL structure:");
 		TLS_ERR("Failed to create SSL structure:");
 		goto error;
 		goto error;
 	}
 	}
-	c->extra_data = ssl;
+	c->extra_data = data;
 	return 0;
 	return 0;
+
  error:
  error:
+	cfg->ref_count--;
+	if (data) shm_free(data);
 	c->state = S_CONN_BAD;
 	c->state = S_CONN_BAD;
 	return -1;
 	return -1;
 }
 }
@@ -87,7 +116,7 @@ static int tls_update_fd(struct tcp_connection *c, int fd)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	ssl = (SSL*)c->extra_data;
+	ssl = ((struct tls_extra_data*)c->extra_data)->ssl;
 	if (SSL_set_fd(ssl, fd) != 1) {
 	if (SSL_set_fd(ssl, fd) != 1) {
 		TLS_ERR("tls_update_fd:");
 		TLS_ERR("tls_update_fd:");
 		return -1;
 		return -1;
@@ -230,7 +259,7 @@ static int tls_accept(struct tcp_connection *c, int* error)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	ssl = (SSL *)c->extra_data;
+	ssl = ((struct tls_extra_data*)c->extra_data)->ssl;
 	ret = SSL_accept(ssl);
 	ret = SSL_accept(ssl);
 	if (ret == 1) {
 	if (ret == 1) {
 		DBG("TLS accept successful\n");
 		DBG("TLS accept successful\n");
@@ -322,7 +351,7 @@ static int tls_connect(struct tcp_connection *c, int* error)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	ssl = (SSL *)c->extra_data;
+	ssl = ((struct tls_extra_data*)c->extra_data)->ssl;
 	ret = SSL_connect(ssl);
 	ret = SSL_connect(ssl);
 	if (ret == 1) {
 	if (ret == 1) {
 		DBG("TLS connect successuful\n");
 		DBG("TLS connect successuful\n");
@@ -408,7 +437,7 @@ static int tls_shutdown(struct tcp_connection *c)
 	int ret, err, ssl_err;
 	int ret, err, ssl_err;
 	SSL *ssl;
 	SSL *ssl;
 
 
-	ssl = (SSL*)c->extra_data;
+	ssl = ((struct tls_extra_data*)c->extra_data)->ssl;
 	if (ssl == 0) {
 	if (ssl == 0) {
 		ERR("No SSL data to perform tls_shutdown\n");
 		ERR("No SSL data to perform tls_shutdown\n");
 		return -1;
 		return -1;
@@ -480,7 +509,7 @@ static int tls_write(struct tcp_connection *c, const void *buf, size_t len, int*
 {
 {
 	int ret, err, ssl_err;
 	int ret, err, ssl_err;
 	SSL *ssl;
 	SSL *ssl;
-	ssl = (SSL*)c->extra_data;
+	ssl = ((struct tls_extra_data*)c->extra_data)->ssl;
 
 
 	err = 0;
 	err = 0;
 	ret = SSL_write(ssl, buf, len);
 	ret = SSL_write(ssl, buf, len);
@@ -561,6 +590,7 @@ int tls_tcpconn_init(struct tcp_connection *c, int sock)
  */
  */
 void tls_tcpconn_clean(struct tcp_connection *c)
 void tls_tcpconn_clean(struct tcp_connection *c)
 {
 {
+	struct tls_extra_data* extra;
 	/*
 	/*
 	* runs within global tcp lock 
 	* runs within global tcp lock 
 	*/
 	*/
@@ -569,7 +599,10 @@ void tls_tcpconn_clean(struct tcp_connection *c)
 		abort();
 		abort();
 	}
 	}
 	if (c->extra_data) {
 	if (c->extra_data) {
-		SSL_free((SSL*)c->extra_data);
+		extra = (struct tls_extra_data*)c->extra_data;
+		SSL_free(extra->ssl);
+		extra->cfg->ref_count--;
+		shm_free(c->extra_data);
 		c->extra_data = 0;
 		c->extra_data = 0;
 	}
 	}
 }
 }
@@ -706,7 +739,8 @@ size_t tls_read(struct tcp_connection * c)
 {
 {
 	struct tcp_req* r;
 	struct tcp_req* r;
 	int bytes_free, bytes_read, err, ssl_err;
 	int bytes_free, bytes_read, err, ssl_err;
-	
+	SSL* ssl;
+
 	r = &c->req;
 	r = &c->req;
 	bytes_free = TCP_BUF_SIZE - (int)(r->pos - r->buf);
 	bytes_free = TCP_BUF_SIZE - (int)(r->pos - r->buf);
 	
 	
@@ -726,11 +760,12 @@ size_t tls_read(struct tcp_connection * c)
 		lock_release(&c->write_lock);
 		lock_release(&c->write_lock);
 		return -1;
 		return -1;
 	}
 	}
-	bytes_read = SSL_read((SSL*)c->extra_data, r->pos, bytes_free);
+	ssl = ((struct tls_extra_data*)c->extra_data)->ssl;
+	bytes_read = SSL_read(ssl, r->pos, bytes_free);
 	lock_release(&c->write_lock);
 	lock_release(&c->write_lock);
 	
 	
 	if (bytes_read <= 0) {
 	if (bytes_read <= 0) {
-		err = SSL_get_error((SSL*)c->extra_data, bytes_read);
+		err = SSL_get_error(ssl, bytes_read);
 		switch(err){
 		switch(err){
 		case SSL_ERROR_ZERO_RETURN:
 		case SSL_ERROR_ZERO_RETURN:
 			     /* tls connection has been closed */
 			     /* tls connection has been closed */
@@ -814,4 +849,3 @@ int tls_fix_read_conn(struct tcp_connection *c)
 	}
 	}
 	return ret;
 	return ret;
 }
 }
-

+ 6 - 0
modules/tls/tls_server.h

@@ -30,6 +30,12 @@
 
 
 #include <stdio.h>
 #include <stdio.h>
 #include "../../tcp_conn.h"
 #include "../../tcp_conn.h"
+#include "tls_domain.h"
+
+struct tls_extra_data {
+	tls_cfg_t* cfg; /* Configuration used for this connection */
+	SSL* ssl;       /* SSL context used for the connection */
+};
 
 
 /*
 /*
  * dump ssl error stack 
  * dump ssl error stack 

+ 150 - 0
modules/tls/tls_util.c

@@ -0,0 +1,150 @@
+/*
+ * $Id$
+ *
+ * TLS module select interface
+ *
+ * Copyright (C) 2001-2003 FhG FOKUS
+ * Copyright (C) 2004,2005 Free Software Foundation, Inc.
+ * COpyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include "../../mem/shm_mem.h"
+#include "tls_mod.h"
+#include "tls_util.h"
+
+
+/*
+ * Make a shared memory copy of str string
+ * Return value: -1 on error
+ *                0 on success
+ */
+int shm_str_dup(char** dest, str* val)
+{
+	char* ret;
+
+	if (!val) return 0;
+
+	ret = shm_malloc(val->len + 1);
+	if (!ret) {
+		ERR("No memory left\n");
+		return 1;
+	}
+	memcpy(ret, val->s, val->len);
+	ret[val->len] = '\0';
+	*dest = ret;
+	return 0;
+}
+
+
+/*
+ * Make a shared memory copy of ASCII zero terminated string
+ * Return value: -1 on error
+ *                0 on success
+ */
+int shm_asciiz_dup(char** dest, char* val)
+{
+	char* ret;
+	int len;
+
+	if (!val) return 0;
+
+	len = strlen(val);
+	ret = shm_malloc(len + 1);
+	if (!ret) {
+		ERR("No memory left\n");
+		return -1;
+	}
+	memcpy(ret, val, len + 1);
+	*dest = ret;
+        return 0;
+}
+
+
+/*
+ * Delete old TLS configuration that is not needed anymore
+ */
+void collect_garbage(void)
+{
+	tls_cfg_t* prev, *cur;
+
+	     /* Make sure we do not run two garbage collectors
+	      * at the same time
+	      */
+	lock_get(tls_cfg_lock);
+
+	     /* Skip the current configuration, garbage starts
+	      * with the 2nd element on the list
+	      */
+	prev = *tls_cfg;
+	cur = (*tls_cfg)->next;
+
+	while(cur) {
+		if (cur->ref_count == 0) {
+			     /* Not referenced by any existing connection */
+			prev->next = cur->next;
+			tls_free_cfg(cur);
+		}
+
+		prev = cur;
+		cur = cur->next;
+	}
+
+	lock_release(tls_cfg_lock);
+}
+
+
+/*
+ * Get full path name of file, if the parameter does
+ * not start with / then the value of CFG_DIR will
+ * be used as prefix
+ * The string returned by the function must be
+ * freed using pkg_free
+ */
+char* get_pathname(str* filename)
+{
+	char* res;
+	int len;
+
+	if (filename->s[0] == '/') {
+		res = pkg_malloc(filename->len + 1);
+		if (!res) {
+			ERR("No memory left\n");
+			return 0;
+		}
+		memcpy(res, filename->s, filename->len);
+		res[filename->len] = '\0';
+	} else {
+		len = strlen(CFG_DIR) + filename->len;
+		res = pkg_malloc(len + 1);
+		if (!res) {
+			ERR("No memory left\n");
+			return 0;
+		}
+		memcpy(res, CFG_DIR, sizeof(CFG_DIR) - 1);
+		memcpy(res + sizeof(CFG_DIR) - 1, filename->s, filename->len);
+		res[sizeof(CFG_DIR) - 1 + filename->len] = '\0';
+	}
+	return res;
+}

+ 34 - 2
modules/tls/tls_util.h

@@ -34,6 +34,7 @@
 
 
 #include <openssl/err.h>
 #include <openssl/err.h>
 #include "../../dprint.h"
 #include "../../dprint.h"
+#include "../../str.h"
 #include "tls_domain.h"
 #include "tls_domain.h"
 
 
 
 
@@ -41,8 +42,8 @@
 do {                                                    \
 do {                                                    \
 	long err;                                       \
 	long err;                                       \
         (r) = 0;                                        \
         (r) = 0;                                        \
-	if (tls_def_srv->ctx &&                         \
-	    (*tls_def_srv->ctx)[0]) {                   \
+	if ((*tls_cfg)->srv_default->ctx &&             \
+	    (*tls_cfg)->srv_default->ctx[0]) {          \
 		while((err = ERR_get_error())) {        \
 		while((err = ERR_get_error())) {        \
 			(r) = 1;                        \
 			(r) = 1;                        \
 			ERR("%s%s\n", ((s)) ? (s) : "", \
 			ERR("%s%s\n", ((s)) ? (s) : "", \
@@ -59,5 +60,36 @@ do {                         \
 } while(0)
 } while(0)
 
 
 
 
+/*
+ * Make a shared memory copy of str string
+ * Return value: -1 on error
+ *                0 on success
+ */
+int shm_str_dup(char** dest, str* val);
+
+
+/*
+ * Make a shared memory copy of ASCII zero terminated string
+ * Return value: -1 on error
+ *                0 on success
+ */
+int shm_asciiz_dup(char** dest, char* val);
+
+
+/*
+ * Delete old TLS configuration that is not needed anymore
+ */
+void collect_garbage(void);
+
+
+/*
+ * Get full path name of file, if the parameter does
+ * not start with / then the value of CFG_DIR will
+ * be used as prefix
+ * The string returned by the function must be
+ * freed using pkg_free
+ */
+char* get_pathname(str* filename);
+
 
 
 #endif /* _TLS_UTIL_H */
 #endif /* _TLS_UTIL_H */