BUG/MINOR: ssl: Fix fd leak on error path when a TLS ticket keys file is parsed

When an error occurred in the function bind_parse_tls_ticket_keys(), during the
configuration parsing, the opened file is not always closed. To fix the bug, all
errors are catched at the same place, where all ressources are released.

This patch fixes the bug #325. It must be backported as far as 1.7.

(cherry picked from commit e566f3db11e781572382e9bfff088a26dcdb75c5)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index b1961f3..a37ab6d 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -8311,15 +8311,15 @@
 static int bind_parse_tls_ticket_keys(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 #if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
-	FILE *f;
+	FILE *f = NULL;
 	int i = 0;
 	char thisline[LINESIZE];
-	struct tls_keys_ref *keys_ref;
+	struct tls_keys_ref *keys_ref = NULL;
 
 	if (!*args[cur_arg + 1]) {
 		if (err)
 			memprintf(err, "'%s' : missing TLS ticket keys file path", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
+		goto fail;
 	}
 
 	keys_ref = tlskeys_ref_lookup(args[cur_arg + 1]);
@@ -8329,36 +8329,31 @@
 		return 0;
 	}
 
-	keys_ref = malloc(sizeof(*keys_ref));
+	keys_ref = calloc(1, sizeof(*keys_ref));
 	if (!keys_ref) {
 		if (err)
 			 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
-		return ERR_ALERT | ERR_FATAL;
+		goto fail;
 	}
 
 	keys_ref->tlskeys = malloc(TLS_TICKETS_NO * sizeof(union tls_sess_key));
 	if (!keys_ref->tlskeys) {
-		free(keys_ref);
 		if (err)
 			 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
-		return ERR_ALERT | ERR_FATAL;
+		goto fail;
 	}
 
 	if ((f = fopen(args[cur_arg + 1], "r")) == NULL) {
-		free(keys_ref->tlskeys);
-		free(keys_ref);
 		if (err)
 			memprintf(err, "'%s' : unable to load ssl tickets keys file", args[cur_arg+1]);
-		return ERR_ALERT | ERR_FATAL;
+		goto fail;
 	}
 
 	keys_ref->filename = strdup(args[cur_arg + 1]);
 	if (!keys_ref->filename) {
-		free(keys_ref->tlskeys);
-		free(keys_ref);
 		if (err)
 			 memprintf(err, "'%s' : allocation error", args[cur_arg+1]);
-		return ERR_ALERT | ERR_FATAL;
+		goto fail;
 	}
 
 	keys_ref->key_size_bits = 0;
@@ -8375,13 +8370,9 @@
 
 		dec_size = base64dec(thisline, len, (char *) (keys_ref->tlskeys + i % TLS_TICKETS_NO), sizeof(union tls_sess_key));
 		if (dec_size < 0) {
-			free(keys_ref->filename);
-			free(keys_ref->tlskeys);
-			free(keys_ref);
 			if (err)
 				memprintf(err, "'%s' : unable to decode base64 key on line %d", args[cur_arg+1], i + 1);
-			fclose(f);
-			return ERR_ALERT | ERR_FATAL;
+			goto fail;
 		}
 		else if (!keys_ref->key_size_bits && (dec_size == sizeof(struct tls_sess_key_128))) {
 			keys_ref->key_size_bits = 128;
@@ -8392,25 +8383,17 @@
 		else if (((dec_size != sizeof(struct tls_sess_key_128)) && (dec_size != sizeof(struct tls_sess_key_256)))
 			 || ((dec_size == sizeof(struct tls_sess_key_128) && (keys_ref->key_size_bits != 128)))
 			 || ((dec_size == sizeof(struct tls_sess_key_256) && (keys_ref->key_size_bits != 256)))) {
-			free(keys_ref->filename);
-			free(keys_ref->tlskeys);
-			free(keys_ref);
 			if (err)
 				memprintf(err, "'%s' : wrong sized key on line %d", args[cur_arg+1], i + 1);
-			fclose(f);
-			return ERR_ALERT | ERR_FATAL;
+			goto fail;
 		}
 		i++;
 	}
 
 	if (i < TLS_TICKETS_NO) {
-		free(keys_ref->filename);
-		free(keys_ref->tlskeys);
-		free(keys_ref);
 		if (err)
 			memprintf(err, "'%s' : please supply at least %d keys in the tls-tickets-file", args[cur_arg+1], TLS_TICKETS_NO);
-		fclose(f);
-		return ERR_ALERT | ERR_FATAL;
+		goto fail;
 	}
 
 	fclose(f);
@@ -8426,6 +8409,17 @@
 	LIST_ADD(&tlskeys_reference, &keys_ref->list);
 
 	return 0;
+
+  fail:
+	if (f)
+		fclose(f);
+	if (keys_ref) {
+		free(keys_ref->filename);
+		free(keys_ref->tlskeys);
+		free(keys_ref);
+	}
+	return ERR_ALERT | ERR_FATAL;
+
 #else
 	if (err)
 		memprintf(err, "'%s' : TLS ticket callback extension not supported", args[cur_arg]);