1 /*********************************************************************************************************
2 * Software License Agreement (BSD License)                                                               *
3 * Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
4 *													 *
5 * Copyright (c) 2020, WIDE Project and NICT								 *
6 * All rights reserved.											 *
7 * 													 *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are  *
9 * permitted provided that the following conditions are met:						 *
10 * 													 *
11 * * Redistributions of source code must retain the above 						 *
12 *   copyright notice, this list of conditions and the 							 *
13 *   following disclaimer.										 *
14 *    													 *
15 * * Redistributions in binary form must reproduce the above 						 *
16 *   copyright notice, this list of conditions and the 							 *
17 *   following disclaimer in the documentation and/or other						 *
18 *   materials provided with the distribution.								 *
19 * 													 *
20 * * Neither the name of the WIDE Project or NICT nor the 						 *
21 *   names of its contributors may be used to endorse or 						 *
22 *   promote products derived from this software without 						 *
23 *   specific prior written permission of WIDE Project and 						 *
24 *   NICT.												 *
25 * 													 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
34 *********************************************************************************************************/
35 
36 #include "fdcore-internal.h"
37 #include <sys/stat.h>
38 
39 /* Configuration management */
40 
41 #ifndef GNUTLS_DEFAULT_PRIORITY
42 # define GNUTLS_DEFAULT_PRIORITY "NORMAL"
43 #endif /* GNUTLS_DEFAULT_PRIORITY */
44 #ifndef GNUTLS_DEFAULT_DHBITS
45 # define GNUTLS_DEFAULT_DHBITS 1024
46 #endif /* GNUTLS_DEFAULT_DHBITS */
47 
48 /* Initialize the fd_g_config structure to default values -- it should already have been initialized to all-0 */
fd_conf_init()49 int fd_conf_init()
50 {
51 	TRACE_ENTRY();
52 
53 	fd_g_config->cnf_eyec = EYEC_CONFIG;
54 
55 	fd_g_config->cnf_timer_tc = 30;
56 	fd_g_config->cnf_timer_tw = 30;
57 
58 	fd_g_config->cnf_port     = DIAMETER_PORT;
59 	fd_g_config->cnf_port_tls = DIAMETER_SECURE_PORT;
60 	fd_g_config->cnf_sctp_str = 30;
61 	fd_g_config->cnf_thr_srv  = 5;
62 	fd_g_config->cnf_processing_peers_minimum = 0;
63 	fd_g_config->cnf_dispthr  = 4;
64 	fd_g_config->cnf_rtinthr = 1;
65 	fd_g_config->cnf_rtoutthr = 1;
66 	fd_g_config->cnf_qin_limit = 20;
67 	fd_g_config->cnf_qout_limit = 30;
68 	fd_g_config->cnf_qlocal_limit = 25;
69 	fd_list_init(&fd_g_config->cnf_endpoints, NULL);
70 	fd_list_init(&fd_g_config->cnf_apps, NULL);
71 	#ifdef DISABLE_SCTP
72 	fd_g_config->cnf_flags.no_sctp = 1;
73 	#endif /* DISABLE_SCTP */
74 
75 	fd_g_config->cnf_orstateid = (uint32_t) time(NULL);
76 	fd_g_config->cnf_rr_in_answers = 1;
77 
78 	CHECK_FCT( fd_dict_init(&fd_g_config->cnf_dict) );
79 	CHECK_FCT( fd_fifo_new(&fd_g_config->cnf_main_ev, 0) );
80 
81 	/* TLS parameters */
82 	CHECK_GNUTLS_DO( gnutls_certificate_allocate_credentials (&fd_g_config->cnf_sec_data.credentials), return ENOMEM );
83 	CHECK_GNUTLS_DO( gnutls_dh_params_init (&fd_g_config->cnf_sec_data.dh_cache), return ENOMEM );
84 #ifdef GNUTLS_VERSION_300
85 	CHECK_GNUTLS_DO( gnutls_x509_trust_list_init(&fd_g_config->cnf_sec_data.trustlist, 0), return ENOMEM );
86 #endif /* GNUTLS_VERSION_300 */
87 
88 	return 0;
89 }
90 
DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump)91 DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump)
92 {
93 	FD_DUMP_HANDLE_OFFSET();
94 
95 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "freeDiameter configuration:\n"), return NULL);
96 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Default trace level .... : %+d\n", fd_g_debug_lvl), return NULL);
97 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Configuration file ..... : %s\n", fd_g_config->cnf_file), return NULL);
98 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Diameter Identity ...... : %s (l:%zi)\n", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len), return NULL);
99 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Diameter Realm ......... : %s (l:%zi)\n", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len), return NULL);
100 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Tc Timer ............... : %u\n", fd_g_config->cnf_timer_tc), return NULL);
101 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Tw Timer ............... : %u\n", fd_g_config->cnf_timer_tw), return NULL);
102 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local port ............. : %hu\n", fd_g_config->cnf_port), return NULL);
103 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local secure port ...... : %hu\n", fd_g_config->cnf_port_tls), return NULL);
104 	if (fd_g_config->cnf_port_3436) {
105 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local SCTP TLS port .... : %hu\n", fd_g_config->cnf_port_3436), return NULL);
106 	}
107 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str), return NULL);
108 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of clients thr .. : %d\n", fd_g_config->cnf_thr_srv), return NULL);
109 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of app threads .. : %hu\n", fd_g_config->cnf_dispthr), return NULL);
110 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Minimal processing peers : %d\n", fd_g_config->cnf_processing_peers_minimum), return NULL);
111 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of rtin threads . : %hu\n", fd_g_config->cnf_rtinthr), return NULL);
112 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of rtout threads  : %hu\n", fd_g_config->cnf_rtoutthr), return NULL);
113 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Incoming queue limit     : %d\n", fd_g_config->cnf_qin_limit), return NULL);
114 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Outgoing queue limit     : %d\n", fd_g_config->cnf_qout_limit), return NULL);
115 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local queue limit        : %d\n", fd_g_config->cnf_qlocal_limit), return NULL);
116 	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
117 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local endpoints ........ : Default (use all available)\n"), return NULL);
118 	} else {
119 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local endpoints ........ : "), return NULL);
120 		CHECK_MALLOC_DO( fd_ep_dump( FD_DUMP_STD_PARAMS, 0, 0, &fd_g_config->cnf_endpoints ), return NULL);
121 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
122 	}
123 	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_apps)) {
124 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local applications ..... : (none)"), return NULL);
125 	} else {
126 		struct fd_list * li = fd_g_config->cnf_apps.next;
127 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local applications ..... : "), return NULL);
128 		while (li != &fd_g_config->cnf_apps) {
129 			struct fd_app * app = (struct fd_app *)li;
130 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "App: %u,%s%s,Vnd:%u\t",
131 					app->appid,
132 					app->flags.auth ? "Au" : "--",
133 					app->flags.acct ? "Ac" : "--",
134 					app->vndid), return NULL);
135 			li = li->next;
136 		}
137 	}
138 
139 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n  Flags : - IP ........... : %s\n", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled"), return NULL);
140 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - IPv6 ......... : %s\n", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled"), return NULL);
141 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Relay app .... : %s\n", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled"), return NULL);
142 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - TCP .......... : %s\n", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled"), return NULL);
143 	#ifdef DISABLE_SCTP
144 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - SCTP ......... : DISABLED (at compilation)\n"), return NULL);
145 	#else /* DISABLE_SCTP */
146 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - SCTP ......... : %s\n", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled"), return NULL);
147 	#endif /* DISABLE_SCTP */
148 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Pref. proto .. : %s\n", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP"), return NULL);
149 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - TLS method ... : %s\n", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port"), return NULL);
150 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Client bind .. : %s\n", fd_g_config->cnf_flags.no_bind ? "DISABLED" : "Enabled"), return NULL);
151 
152 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  TLS :   - Certificate .. : %s\n", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)"), return NULL);
153 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Private key .. : %s\n", fd_g_config->cnf_sec_data.key_file ?: "(NONE)"), return NULL);
154 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - CA (trust) ... : %s (%d certs)\n", fd_g_config->cnf_sec_data.ca_file ?: "(none)", fd_g_config->cnf_sec_data.ca_file_nr), return NULL);
155 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - CRL .......... : %s\n", fd_g_config->cnf_sec_data.crl_file ?: "(none)"), return NULL);
156 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Priority ..... : %s\n", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')"), return NULL);
157 	if (fd_g_config->cnf_sec_data.dh_file) {
158 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - DH file ...... : %s\n", fd_g_config->cnf_sec_data.dh_file), return NULL);
159 	} else {
160 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - DH bits ...... : %d\n", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS), return NULL);
161 	}
162 
163 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Origin-State-Id ........ : %u", fd_g_config->cnf_orstateid), return NULL);
164 
165 	return *buf;
166 }
167 
168 /* read contents of a file opened in "rb" mode and alloc this data into a gnutls_datum_t (must be freed afterwards) */
fd_conf_stream_to_gnutls_datum(FILE * pemfile,gnutls_datum_t * out)169 int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out)
170 {
171 	size_t alloc = 0;
172 
173 	CHECK_PARAMS( pemfile && out );
174 	memset(out, 0, sizeof(gnutls_datum_t));
175 
176 	do {
177 		uint8_t * realloced = NULL;
178 		size_t read = 0;
179 
180 		if (alloc < out->size + BUFSIZ + 1) {
181 			alloc += alloc / 2 + BUFSIZ + 1;
182 			CHECK_MALLOC_DO( realloced = realloc(out->data, alloc),
183 				{
184 					free(out->data);
185 					return ENOMEM;
186 				} )
187 			out->data = realloced;
188 		}
189 
190 		read = fread( out->data + out->size, 1, alloc - out->size - 1, pemfile );
191 		out->size += read;
192 
193 		if (ferror(pemfile)) {
194 			int err = errno;
195 			TRACE_DEBUG(INFO, "An error occurred while reading file: %s", strerror(err));
196 			return err;
197 		}
198 	} while (!feof(pemfile));
199 
200 	out->data[out->size] = '\0';
201 	return 0;
202 }
203 
204 #ifdef GNUTLS_VERSION_300
205 /* inspired from GnuTLS manual */
fd_conf_print_details_func(gnutls_x509_crt_t cert,gnutls_x509_crt_t issuer,gnutls_x509_crl_t crl,unsigned int verification_output)206 static int fd_conf_print_details_func (gnutls_x509_crt_t cert,
207                     gnutls_x509_crt_t issuer, gnutls_x509_crl_t crl,
208                     unsigned int verification_output)
209 {
210   char name[512];
211   char issuer_name[512];
212   size_t name_size;
213   size_t issuer_name_size;
214 
215   if (!TRACE_BOOL(GNUTLS_DBG_LEVEL))
216 	  return 0;
217 
218   issuer_name_size = sizeof (issuer_name);
219   gnutls_x509_crt_get_issuer_dn (cert, issuer_name, &issuer_name_size);
220 
221   name_size = sizeof (name);
222   gnutls_x509_crt_get_dn (cert, name, &name_size);
223 
224   fd_log_debug("\tSubject: %s", name);
225   fd_log_debug("\tIssuer: %s", issuer_name);
226 
227   if (issuer != NULL)
228     {
229       issuer_name_size = sizeof (issuer_name);
230       gnutls_x509_crt_get_dn (issuer, issuer_name, &issuer_name_size);
231 
232       fd_log_debug("\tVerified against: %s", issuer_name);
233     }
234 
235   if (crl != NULL)
236     {
237       issuer_name_size = sizeof (issuer_name);
238       gnutls_x509_crl_get_issuer_dn (crl, issuer_name, &issuer_name_size);
239 
240       fd_log_debug("\tVerified against CRL of: %s", issuer_name);
241     }
242 
243   fd_log_debug("\tVerification output: %x", verification_output);
244 
245   return 0;
246 }
247 #endif /* GNUTLS_VERSION_300 */
248 
249 #ifndef GNUTLS_VERSION_300
250 GCC_DIAG_OFF("-Wdeprecated-declarations")
251 #endif /* !GNUTLS_VERSION_300 */
252 /* Parse the configuration file (using the yacc parser) */
fd_conf_parse()253 int fd_conf_parse()
254 {
255 	extern FILE * fddin;
256 	const char * orig = NULL;
257 
258 	/* Attempt to find the configuration file */
259 	if (!fd_g_config->cnf_file)
260 		fd_g_config->cnf_file = FD_DEFAULT_CONF_FILENAME;
261 
262 	fddin = fopen(fd_g_config->cnf_file, "r");
263 	if ((fddin == NULL) && (*fd_g_config->cnf_file != '/')) {
264 		char * new_cnf = NULL;
265 		/* We got a relative path, attempt to add the default directory prefix */
266 		orig = fd_g_config->cnf_file;
267 		CHECK_MALLOC( new_cnf = malloc(strlen(orig) + strlen(DEFAULT_CONF_PATH) + 2) ); /* we will not free it, but not important */
268 		sprintf( new_cnf, DEFAULT_CONF_PATH "/%s", orig );
269 		fd_g_config->cnf_file = new_cnf;
270 		fddin = fopen(fd_g_config->cnf_file, "r");
271 	}
272 	if (fddin == NULL) {
273 		int ret = errno;
274 		LOG_F("Unable to open configuration file for reading; tried the following locations: %s%s%s; Error: %s",
275 				  orig ?: "", orig? " and " : "", fd_g_config->cnf_file, strerror(ret));
276 		return ret;
277 	}
278 
279 	/* call yacc parser */
280 	TRACE_DEBUG (FULL, "Parsing configuration file: %s", fd_g_config->cnf_file);
281 	CHECK_FCT(  fddparse(fd_g_config)  );
282 
283 	/* close the file */
284 	fclose(fddin);
285 
286 	/* Check that TLS private key was given */
287 	if (! fd_g_config->cnf_sec_data.key_file) {
288 		/* If TLS is not enabled, we allow empty TLS configuration */
289 		if ((fd_g_config->cnf_port_tls == 0) && (fd_g_config->cnf_flags.tls_alg == 0)) {
290 			LOG_N("TLS is disabled, this is *NOT* a recommended practice! Diameter protocol conveys highly sensitive information on your users.");
291 			fd_g_config->cnf_sec_data.tls_disabled = 1;
292 		} else {
293 			LOG_F( "Missing private key configuration for TLS. Please provide the TLS_cred configuration directive.");
294 			return EINVAL;
295 		}
296 	}
297 
298 	/* Resolve hostname if not provided */
299 	if (fd_g_config->cnf_diamid == NULL) {
300 		char buf[HOST_NAME_MAX + 1];
301 		struct addrinfo hints, *info;
302 		int ret;
303 
304 		/* local host name */
305 		CHECK_SYS(gethostname(buf, sizeof(buf)));
306 
307 		/* get FQDN */
308 		memset(&hints, 0, sizeof hints);
309 		hints.ai_flags = AI_CANONNAME;
310 
311 		ret = getaddrinfo(buf, NULL, &hints, &info);
312 		if (ret != 0) {
313 			TRACE_ERROR( "Error resolving local FQDN : '%s' : %s"
314 					". Please provide Identity in configuration file.",
315 					buf, gai_strerror(ret));
316 			return EINVAL;
317 		}
318 		fd_g_config->cnf_diamid = info->ai_canonname;
319 		CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 1) );
320 		freeaddrinfo(info);
321 	} else {
322 		CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 0) );
323 	}
324 
325 	/* Handle the realm part */
326 	if (fd_g_config->cnf_diamrlm == NULL) {
327 		char * start = NULL;
328 
329 		/* Check the diameter identity is a fqdn */
330 		start = strchr(fd_g_config->cnf_diamid, '.');
331 		if ((start == NULL) || (start[1] == '\0')) {
332 			TRACE_ERROR( "Unable to extract realm from the Identity '%s'."
333 					" Please fix your Identity setting or provide Realm.",
334 					fd_g_config->cnf_diamid);
335 			return EINVAL;
336 		}
337 
338 		fd_g_config->cnf_diamrlm = start + 1;
339 		CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 1) );
340 	} else {
341 		CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 0) );
342 	}
343 
344 	/* Validate some flags */
345 	if (fd_g_config->cnf_flags.no_ip4 && fd_g_config->cnf_flags.no_ip6) {
346 		TRACE_ERROR( "IP and IPv6 cannot be disabled at the same time.");
347 		return EINVAL;
348 	}
349 	if (fd_g_config->cnf_flags.no_tcp && fd_g_config->cnf_flags.no_sctp) {
350 		TRACE_ERROR( "TCP and SCTP cannot be disabled at the same time.");
351 		return EINVAL;
352 	}
353 
354 	/* Validate local endpoints */
355 	fd_g_config->cnf_flags.no_bind = FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints);
356 	if ((!fd_g_config->cnf_flags.no_bind) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) {
357 		struct fd_list * li;
358 		for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {
359 			struct fd_endpoint * ep = (struct fd_endpoint *)li;
360 			if ( (fd_g_config->cnf_flags.no_ip4 && (ep->sa.sa_family == AF_INET))
361 			   ||(fd_g_config->cnf_flags.no_ip6 && (ep->sa.sa_family == AF_INET6)) ) {
362 				char sa_buf[sSA_DUMP_STRLEN];;
363 				li = li->prev;
364 				fd_list_unlink(&ep->chain);
365 				fd_sa_sdump_numeric(sa_buf, &ep->sa);
366 				LOG_N("Info: Removing local address conflicting with the flags no_IP / no_IP6 : %s", sa_buf);
367 				free(ep);
368 			}
369 		}
370 	}
371 
372 	/* Configure TLS default parameters */
373 	if ((!fd_g_config->cnf_sec_data.tls_disabled) && (!fd_g_config->cnf_sec_data.prio_string)) {
374 		const char * err_pos = NULL;
375 		CHECK_GNUTLS_DO( gnutls_priority_init(
376 					&fd_g_config->cnf_sec_data.prio_cache,
377 					GNUTLS_DEFAULT_PRIORITY,
378 					&err_pos),
379 				 { TRACE_ERROR("Error in priority string at position : %s", err_pos); return EINVAL; } );
380 	}
381 
382 	/* Verify that our certificate is valid -- otherwise remote peers will reject it */
383 	if (!fd_g_config->cnf_sec_data.tls_disabled) {
384 		int ret = 0, i;
385 
386 		gnutls_datum_t certfile;
387 
388 		gnutls_x509_crt_t * certs = NULL;
389 		unsigned int cert_max = 0;
390 
391 
392 		/* Read the certificate file */
393 		FILE *stream = fopen (fd_g_config->cnf_sec_data.cert_file, "rb");
394 		if (!stream) {
395 			int err = errno;
396 			TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s", fd_g_config->cnf_sec_data.cert_file, strerror(err));
397 			return err;
398 		}
399 		CHECK_FCT( fd_conf_stream_to_gnutls_datum(stream, &certfile) );
400 		fclose(stream);
401 
402 		/* Import the certificate(s) */
403 		GNUTLS_TRACE( ret = gnutls_x509_crt_list_import(NULL, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) );
404 		if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
405 			CHECK_GNUTLS_DO(ret, return EINVAL);
406 		}
407 
408 		CHECK_MALLOC( certs = calloc(cert_max, sizeof(gnutls_x509_crt_t)) );
409 		CHECK_GNUTLS_DO( gnutls_x509_crt_list_import(certs, &cert_max, &certfile, GNUTLS_X509_FMT_PEM,
410 				#ifdef GNUTLS_VERSION_300
411 				GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED
412 				#else /* GNUTLS_VERSION_300 */
413 				0
414 				#endif /* GNUTLS_VERSION_300 */
415 				),
416 			{
417 				TRACE_ERROR("Failed to import the data from file '%s'", fd_g_config->cnf_sec_data.cert_file);
418 				free(certfile.data);
419 				return EINVAL;
420 			} );
421 		free(certfile.data);
422 
423 		ASSERT(cert_max >= 1);
424 
425 		/* Now, verify the list against the local CA and CRL */
426 
427 		#ifdef GNUTLS_VERSION_300
428 
429 			/* We use the trust list for this purpose */
430 		{
431 			unsigned int output;
432 
433 			gnutls_x509_trust_list_verify_named_crt (
434 						fd_g_config->cnf_sec_data.trustlist,
435 						certs[0],
436 						fd_g_config->cnf_diamid,
437 						fd_g_config->cnf_diamid_len,
438                                 		0,
439                                 		&output,
440 						fd_conf_print_details_func);
441 
442 			/* if this certificate is not explicitly trusted verify against CAs
443 			*/
444 			if (output != 0)
445 			{
446 				gnutls_x509_trust_list_verify_crt (
447 							fd_g_config->cnf_sec_data.trustlist,
448 							certs,
449 							cert_max,
450                                 			0,
451                                 			&output,
452 							fd_conf_print_details_func);
453 			}
454 
455 			if (output & GNUTLS_CERT_INVALID)
456 			{
457 				fd_log_debug("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
458 				if (output & GNUTLS_CERT_SIGNER_NOT_FOUND)
459 					TRACE_ERROR(" - The certificate hasn't got a known issuer. Did you forget to specify TLS_CA ?");
460 				if (output & GNUTLS_CERT_SIGNER_NOT_CA)
461 					TRACE_ERROR(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.");
462 				if (output & GNUTLS_CERT_NOT_ACTIVATED)
463 					TRACE_ERROR(" - The certificate is not yet activated.");
464 				if (output & GNUTLS_CERT_EXPIRED)
465 					TRACE_ERROR(" - The certificate is expired.");
466 				return EINVAL;
467 			}
468 
469 			/* Now check the subject matches our hostname */
470 			if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid))
471 			{
472 				TRACE_ERROR("TLS: The certificate owner does not match the hostname '%s'", fd_g_config->cnf_diamid);
473 				return EINVAL;
474 			}
475 
476 		}
477 
478 
479 		#else /* GNUTLS_VERSION_300 */
480 
481 			/* GnuTLS 2.x way of checking certificates */
482 		{
483 			gnutls_x509_crt_t * CA_list;
484 			int CA_list_length;
485 
486 			gnutls_x509_crl_t * CRL_list;
487 			int CRL_list_length;
488 
489 			unsigned int verify;
490 			time_t now;
491 			GNUTLS_TRACE( gnutls_certificate_get_x509_cas (fd_g_config->cnf_sec_data.credentials, &CA_list, (unsigned int *) &CA_list_length) );
492 			GNUTLS_TRACE( gnutls_certificate_get_x509_crls (fd_g_config->cnf_sec_data.credentials, &CRL_list, (unsigned int *) &CRL_list_length) );
493 			CHECK_GNUTLS_DO( gnutls_x509_crt_list_verify(certs, cert_max, CA_list, CA_list_length, CRL_list, CRL_list_length, 0, &verify),
494 				{
495 					TRACE_ERROR("Failed to verify the local certificate '%s' against local credentials. Please check your certificate is valid.", fd_g_config->cnf_sec_data.cert_file);
496 					return EINVAL;
497 				} );
498 
499 			if (verify) {
500 				fd_log_debug("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
501 				if (verify & GNUTLS_CERT_INVALID)
502 					TRACE_ERROR(" - The certificate is not trusted (unknown CA? expired?)");
503 				if (verify & GNUTLS_CERT_REVOKED)
504 					TRACE_ERROR(" - The certificate has been revoked.");
505 				if (verify & GNUTLS_CERT_SIGNER_NOT_FOUND)
506 					TRACE_ERROR(" - The certificate hasn't got a known issuer.");
507 				if (verify & GNUTLS_CERT_SIGNER_NOT_CA)
508 					TRACE_ERROR(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.");
509 				if (verify & GNUTLS_CERT_INSECURE_ALGORITHM)
510 					TRACE_ERROR(" - The certificate signature uses a weak algorithm.");
511 				return EINVAL;
512 			}
513 
514 			/* Check the local Identity is valid with the certificate */
515 			if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid)) {
516 				TRACE_ERROR("TLS: Local certificate '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
517 				TRACE_ERROR(" - The certificate hostname does not match '%s'", fd_g_config->cnf_diamid);
518 				return EINVAL;
519 			}
520 
521 			/* Check validity of all the certificates in the chain */
522 			now = time(NULL);
523 			for (i = 0; i < cert_max; i++)
524 			{
525 				time_t deadline;
526 
527 				GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(certs[i]) );
528 				if ((deadline != (time_t)-1) && (deadline < now)) {
529 					TRACE_ERROR("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
530 					TRACE_ERROR(" - The certificate %d in the chain is expired", i);
531 					return EINVAL;
532 				}
533 
534 				GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(certs[i]) );
535 				if ((deadline != (time_t)-1) && (deadline > now)) {
536 					TRACE_ERROR("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
537 					TRACE_ERROR(" - The certificate %d in the chain is not yet activated", i);
538 					return EINVAL;
539 				}
540 			}
541 		}
542 		#endif /* GNUTLS_VERSION_300 */
543 
544 		/* Everything checked OK, free the certificate list */
545 		for (i = 0; i < cert_max; i++)
546 		{
547 			GNUTLS_TRACE( gnutls_x509_crt_deinit (certs[i]) );
548 		}
549 		free(certs);
550 
551 		#ifdef GNUTLS_VERSION_300
552 		/* Use certificate verification during the handshake */
553 		gnutls_certificate_set_verify_function (fd_g_config->cnf_sec_data.credentials, fd_tls_verify_credentials_2);
554 		#endif /* GNUTLS_VERSION_300 */
555 
556 	}
557 
558 	/* gnutls_certificate_set_verify_limits -- so far the default values are fine... */
559 
560 	/* DH */
561 	if (!fd_g_config->cnf_sec_data.tls_disabled) {
562 		if (fd_g_config->cnf_sec_data.dh_file) {
563 			gnutls_datum_t dhparams = { NULL, 0 };
564 			size_t alloc = 0;
565 			FILE *stream = fopen (fd_g_config->cnf_sec_data.dh_file, "rb");
566 			if (!stream) {
567 				int err = errno;
568 				TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
569 				return err;
570 			}
571 			do {
572 				uint8_t * realloced = NULL;
573 				size_t read = 0;
574 
575 				if (alloc < dhparams.size + BUFSIZ + 1) {
576 					alloc += alloc / 2 + BUFSIZ + 1;
577 					CHECK_MALLOC_DO( realloced = realloc(dhparams.data, alloc),
578 						{
579 							free(dhparams.data);
580 							return ENOMEM;
581 						} )
582 					dhparams.data = realloced;
583 				}
584 
585 				read = fread( dhparams.data + dhparams.size, 1, alloc - dhparams.size - 1, stream );
586 				dhparams.size += read;
587 
588 				if (ferror(stream)) {
589 					int err = errno;
590 					TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
591 					return err;
592 				}
593 			} while (!feof(stream));
594 			dhparams.data[dhparams.size] = '\0';
595 			fclose(stream);
596 			CHECK_GNUTLS_DO( gnutls_dh_params_import_pkcs3(
597 						fd_g_config->cnf_sec_data.dh_cache,
598 						&dhparams,
599 						GNUTLS_X509_FMT_PEM),
600 						 { TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
601 			free(dhparams.data);
602 
603 		} else {
604 			LOG_D( "Generating fresh Diffie-Hellman parameters of size %d (this takes some time)... ", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS);
605 			CHECK_GNUTLS_DO( gnutls_dh_params_generate2(
606 						fd_g_config->cnf_sec_data.dh_cache,
607 						fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS),
608 						 { TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
609 		}
610 
611 	}
612 
613 	return 0;
614 }
615 #ifndef GNUTLS_VERSION_300
616 GCC_DIAG_ON("-Wdeprecated-declarations")
617 #endif /* !GNUTLS_VERSION_300 */
618 
619 
620 /* Destroy contents of fd_g_config structure */
fd_conf_deinit()621 int fd_conf_deinit()
622 {
623 	TRACE_ENTRY();
624 
625 	if (!fd_g_config)
626 		return 0;
627 
628 	/* Free the TLS parameters */
629 #ifdef GNUTLS_VERSION_300
630 	gnutls_x509_trust_list_deinit(fd_g_config->cnf_sec_data.trustlist, 1);
631 #endif /* GNUTLS_VERSION_300 */
632 	gnutls_priority_deinit(fd_g_config->cnf_sec_data.prio_cache);
633 	gnutls_dh_params_deinit(fd_g_config->cnf_sec_data.dh_cache);
634 	gnutls_certificate_free_credentials(fd_g_config->cnf_sec_data.credentials);
635 
636 	free(fd_g_config->cnf_sec_data.cert_file); fd_g_config->cnf_sec_data.cert_file = NULL;
637 	free(fd_g_config->cnf_sec_data.key_file); fd_g_config->cnf_sec_data.key_file = NULL;
638 	free(fd_g_config->cnf_sec_data.ca_file); fd_g_config->cnf_sec_data.ca_file = NULL;
639 	free(fd_g_config->cnf_sec_data.crl_file); fd_g_config->cnf_sec_data.crl_file = NULL;
640 	free(fd_g_config->cnf_sec_data.prio_string); fd_g_config->cnf_sec_data.prio_string = NULL;
641 	free(fd_g_config->cnf_sec_data.dh_file); fd_g_config->cnf_sec_data.dh_file = NULL;
642 
643 	/* Destroy dictionary */
644 	CHECK_FCT_DO( fd_dict_fini(&fd_g_config->cnf_dict), );
645 
646 	/* Destroy the main event queue */
647 	CHECK_FCT_DO( fd_fifo_del(&fd_g_config->cnf_main_ev), );
648 
649 	/* Destroy the local endpoints and applications */
650 	CHECK_FCT_DO(fd_ep_filter(&fd_g_config->cnf_endpoints, 0 ), );
651 	CHECK_FCT_DO(fd_app_empty(&fd_g_config->cnf_apps ), );
652 
653 	/* Destroy the local identity */
654 	free(fd_g_config->cnf_diamid); fd_g_config->cnf_diamid = NULL;
655 	free(fd_g_config->cnf_diamrlm); fd_g_config->cnf_diamrlm = NULL;
656 
657 	return 0;
658 }
659 
660 
661