fix memory leak(s) in libiptc. Reverts the previous (wrong) patch.  (Martin Josefsson)
diff --git a/include/libiptc/libiptc.h b/include/libiptc/libiptc.h
index 82745f9..50765d9 100644
--- a/include/libiptc/libiptc.h
+++ b/include/libiptc/libiptc.h
@@ -34,6 +34,9 @@
 /* Take a snapshot of the rules.  Returns NULL on error. */
 iptc_handle_t iptc_init(const char *tablename);
 
+/* Cleanup after iptc_init(). */
+void iptc_free(iptc_handle_t *h);
+
 /* Iterator functions to run through the chains.  Returns NULL at end. */
 const char *iptc_first_chain(iptc_handle_t *handle);
 const char *iptc_next_chain(iptc_handle_t *handle);
diff --git a/ip6tables-restore.c b/ip6tables-restore.c
index 82e1d2b..ecda870 100644
--- a/ip6tables-restore.c
+++ b/ip6tables-restore.c
@@ -7,7 +7,7 @@
  * 	Rusty Russell <rusty@linuxcare.com.au>
  * This code is distributed under the terms of GNU GPL v2
  *
- * $Id: ip6tables-restore.c,v 1.10 2002/08/14 11:40:41 laforge Exp $
+ * $Id: ip6tables-restore.c,v 1.11 2003/03/05 07:46:15 laforge Exp $
  */
 
 #include <getopt.h>
@@ -102,7 +102,7 @@
 
 int main(int argc, char *argv[])
 {
-	ip6tc_handle_t handle;
+	ip6tc_handle_t handle = NULL;
 	char buffer[10240];
 	int c;
 	char curtable[IP6T_TABLE_MAXNAMELEN + 1];
@@ -183,6 +183,9 @@
 			}
 			strncpy(curtable, table, IP6T_TABLE_MAXNAMELEN);
 
+			if (handle)
+				ip6tc_free(&handle);
+
 			handle = create_handle(table, modprobe);
 			if (noflush == 0) {
 				DEBUGP("Cleaning all chains of table '%s'\n",
diff --git a/ip6tables-save.c b/ip6tables-save.c
index b9dbd80..77cc325 100644
--- a/ip6tables-save.c
+++ b/ip6tables-save.c
@@ -305,6 +305,8 @@
 		exit_error(OTHER_PROBLEM, "Binary NYI\n");
 	}
 
+	ip6tc_free(&h);
+
 	return 1;
 }
 
diff --git a/ip6tables.c b/ip6tables.c
index 17bdb4e..d250882 100644
--- a/ip6tables.c
+++ b/ip6tables.c
@@ -1670,6 +1670,7 @@
 	const char *modprobe = NULL;
 	int proto_used = 0;
 	char icmp6p[] = "icmpv6";
+	int no_handle = 0;
 
 	memset(&fw, 0, sizeof(fw));
 
@@ -2147,8 +2148,10 @@
 			   chain, IP6T_FUNCTION_MAXNAMELEN);
 
 	/* only allocate handle if we weren't called with a handle */
-	if (!*handle)
+	if (!*handle) {
 		*handle = ip6tc_init(*table);
+		no_handle = 1;
+	}
 
 	if (!*handle) {
 		/* try to insmod the module if iptc_init failed */
@@ -2293,5 +2296,8 @@
 	if (verbose > 1)
 		dump_entries6(*handle);
 
+	if (no_handle)
+		ip6tc_free(handle);
+
 	return ret;
 }
diff --git a/iptables-restore.c b/iptables-restore.c
index 74f7db3..c1888ce 100644
--- a/iptables-restore.c
+++ b/iptables-restore.c
@@ -4,7 +4,7 @@
  *
  * This code is distributed under the terms of GNU GPL v2
  *
- * $Id: iptables-restore.c,v 1.24 2003/03/03 08:08:37 laforge Exp $
+ * $Id: iptables-restore.c,v 1.25 2003/03/06 11:56:31 laforge Exp $
  */
 
 #include <getopt.h>
@@ -99,7 +99,7 @@
 
 int main(int argc, char *argv[])
 {
-	iptc_handle_t handle;
+	iptc_handle_t handle = NULL;
 	char buffer[10240];
 	int c;
 	char curtable[IPT_TABLE_MAXNAMELEN + 1];
@@ -180,6 +180,9 @@
 			}
 			strncpy(curtable, table, IPT_TABLE_MAXNAMELEN);
 
+			if (handle)
+				iptc_free(&handle);
+
 			handle = create_handle(table, modprobe);
 			if (noflush == 0) {
 				DEBUGP("Cleaning all chains of table '%s'\n",
diff --git a/iptables-save.c b/iptables-save.c
index 74e71ff..90163b5 100644
--- a/iptables-save.c
+++ b/iptables-save.c
@@ -304,6 +304,8 @@
 		exit_error(OTHER_PROBLEM, "Binary NYI\n");
 	}
 
+	iptc_free(&h);
+
 	return 1;
 }
 
diff --git a/iptables.c b/iptables.c
index a3bcc78..d181578 100644
--- a/iptables.c
+++ b/iptables.c
@@ -1668,6 +1668,7 @@
 	char *protocol = NULL;
 	const char *modprobe = NULL;
 	int proto_used = 0;
+	int no_handle = 0;
 
 	memset(&fw, 0, sizeof(fw));
 
@@ -2148,8 +2149,10 @@
 			   chain, IPT_FUNCTION_MAXNAMELEN);
 
 	/* only allocate handle if we weren't called with a handle */
-	if (!*handle)
+	if (!*handle) {
 		*handle = iptc_init(*table);
+		no_handle = 1;
+	}
 
 	if (!*handle) {
 		/* try to insmod the module if iptc_init failed */
@@ -2294,5 +2297,8 @@
 	if (verbose > 1)
 		dump_entries(*handle);
 
+	if (no_handle)
+		iptc_free(handle);
+
 	return ret;
 }
diff --git a/libiptc/libip4tc.c b/libiptc/libip4tc.c
index e15df90..e012c08 100644
--- a/libiptc/libip4tc.c
+++ b/libiptc/libip4tc.c
@@ -91,6 +91,7 @@
 #define TC_SET_POLICY		iptc_set_policy
 #define TC_GET_RAW_SOCKET	iptc_get_raw_socket
 #define TC_INIT			iptc_init
+#define TC_FREE			iptc_free
 #define TC_COMMIT		iptc_commit
 #define TC_STRERROR		iptc_strerror
 
diff --git a/libiptc/libip6tc.c b/libiptc/libip6tc.c
index 7a88efd..84e139c 100644
--- a/libiptc/libip6tc.c
+++ b/libiptc/libip6tc.c
@@ -86,6 +86,7 @@
 #define TC_SET_POLICY		ip6tc_set_policy
 #define TC_GET_RAW_SOCKET	ip6tc_get_raw_socket
 #define TC_INIT			ip6tc_init
+#define TC_FREE			ip6tc_free
 #define TC_COMMIT		ip6tc_commit
 #define TC_STRERROR		ip6tc_strerror
 
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index 55b708b..fa73563 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -1,4 +1,4 @@
-/* Library which manipulates firewall rules.  Version $Revision: 1.35 $ */
+/* Library which manipulates firewall rules.  Version $Revision: 1.36 $ */
 
 /* Architecture of firewall rules is as follows:
  *
@@ -237,22 +237,26 @@
 	if (sockfd != -1)
 		close(sockfd);
 
+	if (strlen(tablename) >= TABLE_MAXNAMELEN) {
+		errno = EINVAL;
+		return NULL;
+	}
+	
 	sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
 	if (sockfd < 0)
 		return NULL;
 
 	s = sizeof(info);
-	if (strlen(tablename) >= TABLE_MAXNAMELEN) {
-		errno = EINVAL;
-		return NULL;
-	}
+
 	strcpy(info.name, tablename);
 	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
 		return NULL;
 
 	if ((h = alloc_handle(info.name, info.size, info.num_entries))
-	    == NULL)
+	    == NULL) {
+		close(sockfd);
 		return NULL;
+	}
 
 /* Too hard --RR */
 #if 0
@@ -284,6 +288,7 @@
 
 	if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries,
 		       &tmp) < 0) {
+		close(sockfd);
 		free(h);
 		return NULL;
 	}
@@ -292,6 +297,16 @@
 	return h;
 }
 
+void
+TC_FREE(TC_HANDLE_T *h)
+{
+	close(sockfd);
+	if ((*h)->cache_chain_heads)
+		free((*h)->cache_chain_heads);
+	free(*h);
+	*h = NULL;
+}
+
 static inline int
 print_match(const STRUCT_ENTRY_MATCH *m)
 {
@@ -504,10 +519,8 @@
 	(*handle)->cache_chain_iteration++;
 
 	if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads
-	    == (*handle)->cache_num_chains) {
-		free((*handle)->cache_chain_heads);
+	    == (*handle)->cache_num_chains)
 		return NULL;
-	}
 
 	return (*handle)->cache_chain_iteration->name;
 }
@@ -1584,11 +1597,13 @@
 	STRUCT_REPLACE *repl;
 	STRUCT_COUNTERS_INFO *newcounters;
 	unsigned int i;
-	size_t counterlen
-		= sizeof(STRUCT_COUNTERS_INFO)
-		+ sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
+	size_t counterlen;
 
 	CHECK(*handle);
+
+	counterlen = sizeof(STRUCT_COUNTERS_INFO)
+			+ sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
+
 #if 0
 	TC_DUMP_ENTRIES(*handle);
 #endif
@@ -1715,10 +1730,7 @@
 	free(newcounters);
 
  finished:
-	if ((*handle)->cache_chain_heads)
-		free((*handle)->cache_chain_heads);
-	free(*handle);
-	*handle = NULL;
+	TC_FREE(handle);
 	return 1;
 }