NetBSD Problem Report #49064

From kovert@omniscient.com  Fri Aug  1 22:52:02 2014
Return-Path: <kovert@omniscient.com>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
	by mollari.NetBSD.org (Postfix) with ESMTPS id A1819A8A73
	for <gnats-bugs@gnats.NetBSD.org>; Fri,  1 Aug 2014 22:52:02 +0000 (UTC)
Message-Id: <201408012251.s71Mpjll015712@guinness.omniscient.com>
Date: Fri, 01 Aug 2014 18:51:45 -0400
From: "Todd M. Kover" <kovert@omniscient.com>
Reply-To: kovert@omniscient.com
To: gnats-bugs@gnats.NetBSD.org
Subject: mail/spamass-milter zombie children & ipv6 support
X-Send-Pr-Version: 3.95

>Number:         49064
>Category:       pkg
>Synopsis:       mail/spamass-milter zombie children & ipv6 support
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    gdt
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Aug 01 22:55:00 +0000 2014
>Closed-Date:    Fri Feb 27 15:33:58 +0000 2015
>Last-Modified:  Fri Feb 27 15:33:58 +0000 2015
>Originator:     Todd Kover
>Release:        NetBSD 6.1_STABLE
>Organization:
Omniscient Technologies
>Environment:
System: NetBSD guinness.omniscient.com 6.1_STABLE NetBSD 6.1_STABLE (GENERIC) #1: Thu Jun 26 20:47:09 EDT 2014 kovert@guinness.omniscient.com:/usr/obj/6.0-stable/amd64/usr/src/os/NetBSD-6.0-branch/src/sys/arch/amd64/compile/GENERIC amd64
Architecture: x86_64
Machine: amd64
>Description:
	I combining two unrelated issues to the same port since its a minor
	pkg and I sorted them out together.  I can split if need be.

	Issue 1) A previous fix for a CVE that replaced popen lost the child 
	reaping that pclose has.  This causes sendmail processes to hang 
	around until spamass-milter is closed.

	Issue 2) No Ipv6 support

>How-To-Repeat:
	Issue 1) install port, tie into sendmail, start milter with -x, 
	watch mail come in and sendmail processes hang around

	Issue 2) start spamass milter with an ipv6 addressed passed to -i,
	such as -i 2001:1900:2209:a/64, watch it not start
>Fix:
	patch-ad is just a copy of the FreeBSD ports patch for fixing IPv6.
	Seems to work fine.  This tweaks the same file as patch-aa and
	patch-ab

	patch-ae and patch-af fix the popenv issue and touch the same files
	as patch-aa and patch-ab respectively.  I separated them in the
	interest of making it easier to patch.

	Thanks,
	-Todd

---<snip>-- patch-ad start ---<snip>---

This came from FreeBSD

diff -ur orig/spamass-milter.cpp spamass-milter.cpp
--- spamass-milter.cpp	2010-01-31 11:35:47.000000000 +0000
+++ spamass-milter.cpp	2008-01-09 01:20:38.000000000 +0000
@@ -88,6 +88,7 @@
 #include "subst_poll.h"
 #endif
 #include <errno.h>
+#include <netdb.h>

 // C++ includes
 #include <cstdio>
@@ -721,12 +722,19 @@
 	sctx = (struct context *)malloc(sizeof(*sctx));
 	if (!hostaddr)
 	{
+		static struct sockaddr_in localhost;
+		
 		/* not a socket; probably a local user calling sendmail directly */
 		/* set to 127.0.0.1 */
-		sctx->connect_ip.s_addr = htonl(INADDR_LOOPBACK);
+		strcpy(sctx->connect_ip, "127.0.0.1");
+		localhost.sin_family = AF_INET;
+		localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+		hostaddr = (struct sockaddr*) &localhost;
 	} else
 	{
-		sctx->connect_ip = ((struct sockaddr_in *) hostaddr)->sin_addr;
+		getnameinfo(hostaddr, sizeof(struct sockaddr_in6),
+		            sctx->connect_ip, 63, NULL, 0, NI_NUMERICHOST);
+		debug(D_FUNC, "Remote address: %s", sctx->connect_ip);
 	}
 	sctx->assassin = NULL;
 	sctx->helo = NULL;
@@ -740,10 +748,12 @@
 	}
 	/* debug(D_ALWAYS, "ZZZ set private context to %p", sctx); */

-	if (ip_in_networklist(sctx->connect_ip, &ignorenets))
+	//debug(D_FUNC, "sctx->connect_ip: `%d'", sctx->connect_ip.sin_family);
+
+	if (ip_in_networklist(hostaddr, &ignorenets))
 	{
 		debug(D_NET, "%s is in our ignore list - accepting message",
-		    inet_ntoa(sctx->connect_ip));
+		      sctx->connect_ip);
 		debug(D_FUNC, "mlfi_connect: exit ignore");
 		return SMFIS_ACCEPT;
 	}
@@ -815,7 +825,7 @@
       return SMFIS_TEMPFAIL;
     };

-  assassin->set_connectip(string(inet_ntoa(sctx->connect_ip)));
+  assassin->set_connectip(string(sctx->connect_ip));

   // Store a pointer to the assassin object in our context struct
   sctx->assassin = assassin;
@@ -2089,69 +2099,119 @@
 	{
 		char *tnet = strsep(&token, "/");
 		char *tmask = token;
-		struct in_addr net, mask;
+		struct in_addr net;
+		struct in6_addr net6;

 		if (list->num_nets % 10 == 0)
-			list->nets = (struct net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10));
+			list->nets = (union net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10));

-		if (!inet_aton(tnet, &net))
+		if (inet_pton(AF_INET, tnet, &net))
 		{
-			fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
-			exit(1);
-		}
+			struct in_addr mask;
+			
+			if (tmask)
+			{
+				if (strchr(tmask, '.') == NULL)
+				{
+					/* CIDR */
+					unsigned int bits;
+					int ret;
+					ret = sscanf(tmask, "%u", &bits);
+					if (ret != 1 || bits > 32)
+					{
+						fprintf(stderr,"%s: bad CIDR value", tmask);
+						exit(1);
+					}
+					mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff);
+				} else if (!inet_pton(AF_INET6, tmask, &mask))
+				{
+					fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask);
+					exit(1);
+				}
+			} else
+				mask.s_addr = 0xffffffff;
+
+			{
+				char *snet = strdup(inet_ntoa(net));
+				debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
+				free(snet);
+			}

-		if (tmask)
+			net.s_addr = net.s_addr & mask.s_addr;
+			list->nets[list->num_nets].net4.af = AF_INET;
+			list->nets[list->num_nets].net4.network = net;
+			list->nets[list->num_nets].net4.netmask = mask;
+			list->num_nets++;
+		} else if (inet_pton(AF_INET6, tnet, &net6))
 		{
-			if (strchr(tmask, '.') == NULL)
+			int mask;
+			
+			if (tmask)
 			{
-				/* CIDR */
-				unsigned int bits;
-				int ret;
-				ret = sscanf(tmask, "%u", &bits);
-				if (ret != 1 || bits > 32)
+				if (sscanf(tmask, "%d", &mask) != 1 || mask > 128)
 				{
 					fprintf(stderr,"%s: bad CIDR value", tmask);
 					exit(1);
 				}
-				mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff);
-			} else if (!inet_aton(tmask, &mask))
-			{
-				fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask);
-				exit(1);
-			}
+			} else
+				mask = 128;
+			
+			list->nets[list->num_nets].net6.af = AF_INET6;
+			list->nets[list->num_nets].net6.network = net6;
+			list->nets[list->num_nets].net6.netmask = mask;
+			list->num_nets++;
 		} else
-			mask.s_addr = 0xffffffff;
-
 		{
-			char *snet = strdup(inet_ntoa(net));
-			debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
-			free(snet);
+			fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
+			exit(1);
 		}

-		net.s_addr = net.s_addr & mask.s_addr;
-		list->nets[list->num_nets].network = net;
-		list->nets[list->num_nets].netmask = mask;
-		list->num_nets++;
 	}
 	free(string);
 }

-int ip_in_networklist(struct in_addr ip, struct networklist *list)
+int ip_in_networklist(struct sockaddr *addr, struct networklist *list)
 {
 	int i;

 	if (list->num_nets == 0)
 		return 0;
-		
-	debug(D_NET, "Checking %s against:", inet_ntoa(ip));
+	
+	//debug(D_NET, "Checking %s against:", inet_ntoa(ip));
 	for (i = 0; i < list->num_nets; i++)
 	{
-		debug(D_NET, "%s", inet_ntoa(list->nets[i].network));
-		debug(D_NET, "/%s", inet_ntoa(list->nets[i].netmask));
-		if ((ip.s_addr & list->nets[i].netmask.s_addr) == list->nets[i].network.s_addr)
-        {
-        	debug(D_NET, "Hit!");
-			return 1;
+		if (list->nets[i].net.af == AF_INET && addr->sa_family == AF_INET)
+		{
+			struct in_addr ip = ((struct sockaddr_in *)addr)->sin_addr;
+			
+			debug(D_NET, "%s", inet_ntoa(list->nets[i].net4.network));
+			debug(D_NET, "/%s", inet_ntoa(list->nets[i].net4.netmask));
+			if ((ip.s_addr & list->nets[i].net4.netmask.s_addr) == list->nets[i].net4.network.s_addr)
+			{
+				debug(D_NET, "Hit!");
+				return 1;
+			}
+		} else if (list->nets[i].net.af == AF_INET6 && addr->sa_family == AF_INET6)
+		{
+			u_int8_t *ip = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr;
+			int mask, j;
+			
+			mask = list->nets[i].net6.netmask;
+			for (j = 0; j < 16 && mask > 0; j++, mask -= 8)
+			{
+				unsigned char bytemask;
+				
+				bytemask = (mask < 8) ? ~((1L << (8 - mask)) - 1) : 0xff;
+				
+				if ((ip[j] & bytemask) != (list->nets[i].net6.network.s6_addr[j] & bytemask))
+					break;
+			}
+			
+			if (mask <= 0)
+			{
+				debug(D_NET, "Hit!");
+				return 1;
+			}
 		}
 	}

diff -ur orig/spamass-milter.h spamass-milter.h
--- spamass-milter.h	2006-03-23 22:07:55.000000000 +0000
+++ spamass-milter.h	2008-01-01 23:55:44.000000000 +0000
@@ -56,16 +56,30 @@
 extern struct smfiDesc smfilter;

 /* struct describing a single network */
-struct net
+union net
 {
-	struct in_addr network;
-	struct in_addr netmask;
+	struct
+	{
+		uint8_t af;
+	} net;
+	struct
+	{
+		uint8_t af;
+		struct in_addr network;
+		struct in_addr netmask;
+	} net4;
+	struct
+	{
+		uint8_t af;
+		struct in6_addr network;
+		int netmask; /* Just the number of bits for IPv6 */
+	} net6;
 };

 /* an array of networks */
 struct networklist
 {
-	struct net *nets;
+	union net *nets;
 	int num_nets;
 };

@@ -165,7 +179,7 @@
 /* Private data structure to carry per-client data between calls */
 struct context
 {
-	struct in_addr connect_ip;	// remote IP address
+	char connect_ip[64];	// remote IP address
 	char *helo;
 	SpamAssassin *assassin; // pointer to the SA object if we're processing a message
 };
@@ -182,7 +196,7 @@
 int cmp_nocase_partial(const string&, const string&);
 void closeall(int fd);
 void parse_networklist(char *string, struct networklist *list);
-int ip_in_networklist(struct in_addr ip, struct networklist *list);
+int ip_in_networklist(struct sockaddr *addr, struct networklist *list);
 void parse_debuglevel(char* string);
 char *strlwr(char *str);
 void warnmacro(char *macro, char *scope);
---<snip>-- patch-ad end ---<snip>---

---<snip>-- patch-ae start ---<snip>---
--- spamass-milter.cpp	2014-08-01 09:03:23.000000000 -0400
+++ spamass-milter.cpp	2014-08-01 09:02:19.000000000 -0400
@@ -464,13 +464,14 @@
 			   the only way to do it. */
 			char *popen_argv[3];
 			FILE *p;
+			pid_t pid;

 			popen_argv[0] = SENDMAIL;
 			popen_argv[1] = spambucket;
 			popen_argv[2] = NULL;

 			debug(D_COPY, "calling %s %s", SENDMAIL, spambucket);
-			p = popenv(popen_argv, "w");
+			p = popenv(popen_argv, "w", &pid);
 			if (!p)
 			{
 				debug(D_COPY, "popenv failed(%s).  Will not send a copy to spambucket", strerror(errno));
@@ -479,6 +480,7 @@
 				// Send message provided by SpamAssassin
 				fwrite(assassin->d().c_str(), assassin->d().size(), 1, p);
 				fclose(p); p = NULL;
+				waitpid(pid, NULL, 0);
 			}
 		}
 		return SMFIS_REJECT;
@@ -824,9 +826,11 @@
 		popen_argv[2] = envrcpt[0];
 		popen_argv[3] = NULL;

+		pid_t pid;
+
 		debug(D_RCPT, "calling %s -bv %s", SENDMAIL, envrcpt[0]);

-		p = popenv(popen_argv, "r");
+		p = popenv(popen_argv, "r", &pid);
 		if (!p)
 		{
 			debug(D_RCPT, "popenv failed(%s).  Will not expand aliases", strerror(errno));
@@ -855,6 +859,7 @@
 				}
 			}
 			fclose(p); p = NULL;
+			waitpid(pid, NULL, 0);
 		}
 	} else
 	{
@@ -2113,11 +2118,12 @@
    for simplicity, and always reads stdout and stderr in "r" mode.  Call
    fclose to close the FILE.
 */
-FILE *popenv(char *const argv[], const char *type)
+FILE *popenv(char *const argv[], const char *type, pid_t *pid)
 {
 	FILE *iop;
 	int pdes[2];
 	int save_errno;
+	pid_t kidpid;
 	if ((*type != 'r' && *type != 'w') || type[1])
 	{
 		errno = EINVAL;
@@ -2125,7 +2131,7 @@
 	}
 	if (pipe(pdes) < 0)
 		return (NULL);
-	switch (fork()) {
+	switch ( (kidpid = fork()) ) {

 	case -1:			/* Error. */
 		save_errno = errno;
@@ -2171,6 +2177,13 @@
 		(void)close(pdes[0]);
 	}

+	/*
+	 * so caller can reap children and not leave zombies
+	 */
+	if(kidpid) {
+		*pid = kidpid;
+	}
+
 	return (iop);
 }

---<snip>-- patch-ae end ---<snip>---

---<snip>-- patch-af start ---<snip>---
--- spamass-milter.h	2014-08-01 09:03:23.000000000 -0400
+++ spamass-milter.h	2014-08-01 09:02:32.000000000 -0400
@@ -186,6 +186,6 @@
 void parse_debuglevel(char* string);
 char *strlwr(char *str);
 void warnmacro(char *macro, char *scope);
-FILE *popenv(char *const argv[], const char *type);
+FILE *popenv(char *const argv[], const char *type, pid_t *pid);

 #endif
---<snip>-- patch-af end ---<snip>---


------- =_aaaaaaaaaa0
Content-Type: text/plain; name="patch-ad"; charset="us-ascii"
Content-ID: <62332.1406933442.2@guinness.omniscient.com>

This came from FreeBSD

diff -ur orig/spamass-milter.cpp spamass-milter.cpp
--- spamass-milter.cpp	2010-01-31 11:35:47.000000000 +0000
+++ spamass-milter.cpp	2008-01-09 01:20:38.000000000 +0000
@@ -88,6 +88,7 @@
 #include "subst_poll.h"
 #endif
 #include <errno.h>
+#include <netdb.h>

 // C++ includes
 #include <cstdio>
@@ -721,12 +722,19 @@
 	sctx = (struct context *)malloc(sizeof(*sctx));
 	if (!hostaddr)
 	{
+		static struct sockaddr_in localhost;
+		
 		/* not a socket; probably a local user calling sendmail directly */
 		/* set to 127.0.0.1 */
-		sctx->connect_ip.s_addr = htonl(INADDR_LOOPBACK);
+		strcpy(sctx->connect_ip, "127.0.0.1");
+		localhost.sin_family = AF_INET;
+		localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+		hostaddr = (struct sockaddr*) &localhost;
 	} else
 	{
-		sctx->connect_ip = ((struct sockaddr_in *) hostaddr)->sin_addr;
+		getnameinfo(hostaddr, sizeof(struct sockaddr_in6),
+		            sctx->connect_ip, 63, NULL, 0, NI_NUMERICHOST);
+		debug(D_FUNC, "Remote address: %s", sctx->connect_ip);
 	}
 	sctx->assassin = NULL;
 	sctx->helo = NULL;
@@ -740,10 +748,12 @@
 	}
 	/* debug(D_ALWAYS, "ZZZ set private context to %p", sctx); */

-	if (ip_in_networklist(sctx->connect_ip, &ignorenets))
+	//debug(D_FUNC, "sctx->connect_ip: `%d'", sctx->connect_ip.sin_family);
+
+	if (ip_in_networklist(hostaddr, &ignorenets))
 	{
 		debug(D_NET, "%s is in our ignore list - accepting message",
-		    inet_ntoa(sctx->connect_ip));
+		      sctx->connect_ip);
 		debug(D_FUNC, "mlfi_connect: exit ignore");
 		return SMFIS_ACCEPT;
 	}
@@ -815,7 +825,7 @@
       return SMFIS_TEMPFAIL;
     };

-  assassin->set_connectip(string(inet_ntoa(sctx->connect_ip)));
+  assassin->set_connectip(string(sctx->connect_ip));

   // Store a pointer to the assassin object in our context struct
   sctx->assassin = assassin;
@@ -2089,69 +2099,119 @@
 	{
 		char *tnet = strsep(&token, "/");
 		char *tmask = token;
-		struct in_addr net, mask;
+		struct in_addr net;
+		struct in6_addr net6;

 		if (list->num_nets % 10 == 0)
-			list->nets = (struct net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10));
+			list->nets = (union net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10));

-		if (!inet_aton(tnet, &net))
+		if (inet_pton(AF_INET, tnet, &net))
 		{
-			fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
-			exit(1);
-		}
+			struct in_addr mask;
+			
+			if (tmask)
+			{
+				if (strchr(tmask, '.') == NULL)
+				{
+					/* CIDR */
+					unsigned int bits;
+					int ret;
+					ret = sscanf(tmask, "%u", &bits);
+					if (ret != 1 || bits > 32)
+					{
+						fprintf(stderr,"%s: bad CIDR value", tmask);
+						exit(1);
+					}
+					mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff);
+				} else if (!inet_pton(AF_INET6, tmask, &mask))
+				{
+					fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask);
+					exit(1);
+				}
+			} else
+				mask.s_addr = 0xffffffff;
+
+			{
+				char *snet = strdup(inet_ntoa(net));
+				debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
+				free(snet);
+			}

-		if (tmask)
+			net.s_addr = net.s_addr & mask.s_addr;
+			list->nets[list->num_nets].net4.af = AF_INET;
+			list->nets[list->num_nets].net4.network = net;
+			list->nets[list->num_nets].net4.netmask = mask;
+			list->num_nets++;
+		} else if (inet_pton(AF_INET6, tnet, &net6))
 		{
-			if (strchr(tmask, '.') == NULL)
+			int mask;
+			
+			if (tmask)
 			{
-				/* CIDR */
-				unsigned int bits;
-				int ret;
-				ret = sscanf(tmask, "%u", &bits);
-				if (ret != 1 || bits > 32)
+				if (sscanf(tmask, "%d", &mask) != 1 || mask > 128)
 				{
 					fprintf(stderr,"%s: bad CIDR value", tmask);
 					exit(1);
 				}
-				mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff);
-			} else if (!inet_aton(tmask, &mask))
-			{
-				fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask);
-				exit(1);
-			}
+			} else
+				mask = 128;
+			
+			list->nets[list->num_nets].net6.af = AF_INET6;
+			list->nets[list->num_nets].net6.network = net6;
+			list->nets[list->num_nets].net6.netmask = mask;
+			list->num_nets++;
 		} else
-			mask.s_addr = 0xffffffff;
-
 		{
-			char *snet = strdup(inet_ntoa(net));
-			debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
-			free(snet);
+			fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
+			exit(1);
 		}

-		net.s_addr = net.s_addr & mask.s_addr;
-		list->nets[list->num_nets].network = net;
-		list->nets[list->num_nets].netmask = mask;
-		list->num_nets++;
 	}
 	free(string);
 }

-int ip_in_networklist(struct in_addr ip, struct networklist *list)
+int ip_in_networklist(struct sockaddr *addr, struct networklist *list)
 {
 	int i;

 	if (list->num_nets == 0)
 		return 0;
-		
-	debug(D_NET, "Checking %s against:", inet_ntoa(ip));
+	
+	//debug(D_NET, "Checking %s against:", inet_ntoa(ip));
 	for (i = 0; i < list->num_nets; i++)
 	{
-		debug(D_NET, "%s", inet_ntoa(list->nets[i].network));
-		debug(D_NET, "/%s", inet_ntoa(list->nets[i].netmask));
-		if ((ip.s_addr & list->nets[i].netmask.s_addr) == list->nets[i].network.s_addr)
-        {
-        	debug(D_NET, "Hit!");
-			return 1;
+		if (list->nets[i].net.af == AF_INET && addr->sa_family == AF_INET)
+		{
+			struct in_addr ip = ((struct sockaddr_in *)addr)->sin_addr;
+			
+			debug(D_NET, "%s", inet_ntoa(list->nets[i].net4.network));
+			debug(D_NET, "/%s", inet_ntoa(list->nets[i].net4.netmask));
+			if ((ip.s_addr & list->nets[i].net4.netmask.s_addr) == list->nets[i].net4.network.s_addr)
+			{
+				debug(D_NET, "Hit!");
+				return 1;
+			}
+		} else if (list->nets[i].net.af == AF_INET6 && addr->sa_family == AF_INET6)
+		{
+			u_int8_t *ip = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr;
+			int mask, j;
+			
+			mask = list->nets[i].net6.netmask;
+			for (j = 0; j < 16 && mask > 0; j++, mask -= 8)
+			{
+				unsigned char bytemask;
+				
+				bytemask = (mask < 8) ? ~((1L << (8 - mask)) - 1) : 0xff;
+				
+				if ((ip[j] & bytemask) != (list->nets[i].net6.network.s6_addr[j] & bytemask))
+					break;
+			}
+			
+			if (mask <= 0)
+			{
+				debug(D_NET, "Hit!");
+				return 1;
+			}
 		}
 	}

diff -ur orig/spamass-milter.h spamass-milter.h
--- spamass-milter.h	2006-03-23 22:07:55.000000000 +0000
+++ spamass-milter.h	2008-01-01 23:55:44.000000000 +0000
@@ -56,16 +56,30 @@
 extern struct smfiDesc smfilter;

 /* struct describing a single network */
-struct net
+union net
 {
-	struct in_addr network;
-	struct in_addr netmask;
+	struct
+	{
+		uint8_t af;
+	} net;
+	struct
+	{
+		uint8_t af;
+		struct in_addr network;
+		struct in_addr netmask;
+	} net4;
+	struct
+	{
+		uint8_t af;
+		struct in6_addr network;
+		int netmask; /* Just the number of bits for IPv6 */
+	} net6;
 };

 /* an array of networks */
 struct networklist
 {
-	struct net *nets;
+	union net *nets;
 	int num_nets;
 };

@@ -165,7 +179,7 @@
 /* Private data structure to carry per-client data between calls */
 struct context
 {
-	struct in_addr connect_ip;	// remote IP address
+	char connect_ip[64];	// remote IP address
 	char *helo;
 	SpamAssassin *assassin; // pointer to the SA object if we're processing a message
 };
@@ -182,7 +196,7 @@
 int cmp_nocase_partial(const string&, const string&);
 void closeall(int fd);
 void parse_networklist(char *string, struct networklist *list);
-int ip_in_networklist(struct in_addr ip, struct networklist *list);
+int ip_in_networklist(struct sockaddr *addr, struct networklist *list);
 void parse_debuglevel(char* string);
 char *strlwr(char *str);
 void warnmacro(char *macro, char *scope);

------- =_aaaaaaaaaa0
Content-Type: text/plain; name="patch-ae"; charset="us-ascii"
Content-ID: <62332.1406933442.3@guinness.omniscient.com>

--- spamass-milter.cpp	2014-08-01 09:03:23.000000000 -0400
+++ spamass-milter.cpp	2014-08-01 09:02:19.000000000 -0400
@@ -464,13 +464,14 @@
 			   the only way to do it. */
 			char *popen_argv[3];
 			FILE *p;
+			pid_t pid;

 			popen_argv[0] = SENDMAIL;
 			popen_argv[1] = spambucket;
 			popen_argv[2] = NULL;

 			debug(D_COPY, "calling %s %s", SENDMAIL, spambucket);
-			p = popenv(popen_argv, "w");
+			p = popenv(popen_argv, "w", &pid);
 			if (!p)
 			{
 				debug(D_COPY, "popenv failed(%s).  Will not send a copy to spambucket", strerror(errno));
@@ -479,6 +480,7 @@
 				// Send message provided by SpamAssassin
 				fwrite(assassin->d().c_str(), assassin->d().size(), 1, p);
 				fclose(p); p = NULL;
+				waitpid(pid, NULL, 0);
 			}
 		}
 		return SMFIS_REJECT;
@@ -824,9 +826,11 @@
 		popen_argv[2] = envrcpt[0];
 		popen_argv[3] = NULL;

+		pid_t pid;
+
 		debug(D_RCPT, "calling %s -bv %s", SENDMAIL, envrcpt[0]);

-		p = popenv(popen_argv, "r");
+		p = popenv(popen_argv, "r", &pid);
 		if (!p)
 		{
 			debug(D_RCPT, "popenv failed(%s).  Will not expand aliases", strerror(errno));
@@ -855,6 +859,7 @@
 				}
 			}
 			fclose(p); p = NULL;
+			waitpid(pid, NULL, 0);
 		}
 	} else
 	{
@@ -2113,11 +2118,12 @@
    for simplicity, and always reads stdout and stderr in "r" mode.  Call
    fclose to close the FILE.
 */
-FILE *popenv(char *const argv[], const char *type)
+FILE *popenv(char *const argv[], const char *type, pid_t *pid)
 {
 	FILE *iop;
 	int pdes[2];
 	int save_errno;
+	pid_t kidpid;
 	if ((*type != 'r' && *type != 'w') || type[1])
 	{
 		errno = EINVAL;
@@ -2125,7 +2131,7 @@
 	}
 	if (pipe(pdes) < 0)
 		return (NULL);
-	switch (fork()) {
+	switch ( (kidpid = fork()) ) {

 	case -1:			/* Error. */
 		save_errno = errno;
@@ -2171,6 +2177,13 @@
 		(void)close(pdes[0]);
 	}

+	/*
+	 * so caller can reap children and not leave zombies
+	 */
+	if(kidpid) {
+		*pid = kidpid;
+	}
+
 	return (iop);
 }


------- =_aaaaaaaaaa0
Content-Type: text/plain; name="patch-af"; charset="us-ascii"
Content-ID: <62332.1406933442.4@guinness.omniscient.com>

--- spamass-milter.h	2014-08-01 09:03:23.000000000 -0400
+++ spamass-milter.h	2014-08-01 09:02:32.000000000 -0400
@@ -186,6 +186,6 @@
 void parse_debuglevel(char* string);
 char *strlwr(char *str);
 void warnmacro(char *macro, char *scope);
-FILE *popenv(char *const argv[], const char *type);
+FILE *popenv(char *const argv[], const char *type, pid_t *pid);

 #endif

------- =_aaaaaaaaaa0--

>Release-Note:

>Audit-Trail:

Responsible-Changed-From-To: pkg-manager->gdt
Responsible-Changed-By: wiz@NetBSD.org
Responsible-Changed-When: Fri, 01 Aug 2014 23:50:20 +0000
Responsible-Changed-Why:
Over to maintainer.


From: "Todd M. Kover" <kovert@omniscient.com>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: pkg/49064: mail/spamass-milter zombie children & ipv6 support
Date: Wed, 10 Sep 2014 21:10:43 -0400

 spamass-milt 0.4.0 was released and that includes this and all the other
 netbsd patches.

State-Changed-From-To: open->feedback
State-Changed-By: gdt@NetBSD.org
State-Changed-When: Mon, 02 Feb 2015 15:04:19 +0000
State-Changed-Why:
spamass-milter is updated to 0.4.0.
Please let me know if there are any further issues; I will close this
PR next time I remember that's after 7 days from now.


State-Changed-From-To: feedback->closed
State-Changed-By: gdt@NetBSD.org
State-Changed-When: Fri, 27 Feb 2015 15:33:58 +0000
State-Changed-Why:
problem resolved, and in feebdack for >7 days.


>Unformatted:
 ------- =_aaaaaaaaaa0
 Content-Type: text/plain; charset="us-ascii"
 Content-ID: <62332.1406933442.1@guinness.omniscient.com>

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.