--- spamass-milter-0.3.1/spamass-milter.cpp.orig	2010-03-10 13:40:30.499678052 +0000
+++ spamass-milter-0.3.1/spamass-milter.cpp	2010-03-10 16:11:59.744302400 +0000
@@ -882,75 +882,107 @@
 	struct context *sctx = (struct context*)smfi_getpriv(ctx);
 	SpamAssassin* assassin = sctx->assassin;
 	FILE *p;
-#if defined(__FreeBSD__)
-	int rv;
-#endif
 
 	debug(D_FUNC, "mlfi_envrcpt: enter");
 
 	if (flag_expand)
 	{
-		/* open a pipe to sendmail so we can do address expansion */
+		/*
+		 * open a pipe to sendmail so we can do address expansion
+		 *
+		 * avoid calling popen() since envrcpt[0] isn't trusted
+		 */
 
+		pid_t pid, w;
+		int pv[2], status;
 		char buf[1024];
-		char *fmt="%s -bv \"%s\" 2>&1";
-
-#if defined(HAVE_SNPRINTF)
-		snprintf(buf, sizeof(buf)-1, fmt, SENDMAIL, envrcpt[0]);
-#else
-		/* XXX possible buffer overflow here */
-		sprintf(buf, fmt, SENDMAIL, envrcpt[0]);
-#endif
 
-		debug(D_RCPT, "calling %s", buf);
-
-#if defined(__FreeBSD__) /* popen bug - see PR bin/50770 */
-		rv = pthread_mutex_lock(&popen_mutex);
-		if (rv)
-		{
-			debug(D_ALWAYS, "Could not lock popen mutex: %s", strerror(rv));
-			abort();
-		}		
-#endif
+		debug(D_RCPT, "calling %s -bv \"%s\"", SENDMAIL, envrcpt[0]);
 
-		p = popen(buf, "r");
-		if (!p)
+		if (pipe(pv) < 0)
 		{
-			debug(D_RCPT, "popen failed(%s).  Will not expand aliases", strerror(errno));
+			debug(D_RCPT, "pipe failed(%s).  Will not expand aliases", strerror(errno));
 			assassin->expandedrcpt.push_back(envrcpt[0]);
 		} else
 		{
-			while (fgets(buf, sizeof(buf), p) != NULL)
+			pid = fork();
+			if (pid == 0)
 			{
-				int i = strlen(buf);
-				/* strip trailing EOLs */
-				while (i > 0 && buf[i - 1] <= ' ')
-					i--;
-				buf[i] = '\0';
-				debug(D_RCPT, "sendmail output: %s", buf);
-				/*	From a quick scan of the sendmail source, a valid email
-					address gets printed via either
-					    "deliverable: mailer %s, host %s, user %s"
-					or  "deliverable: mailer %s, user %s"
-				*/
-				if (strstr(buf, "... deliverable: mailer "))
+				close(1);
+				close(pv[0]);
+				dup2(pv[1], 1);
+				close(pv[1]);
+				execl(SENDMAIL, "sendmail", "-bv", envrcpt[0], NULL);
+				debug(D_RCPT, "execl sendmail failed(%s).  Cannot expand aliases", strerror(errno));
+				_exit(errno ? errno : 1);
+			}
+			if (pid == -1)
+			{
+				debug(D_RCPT, "fork failed(%s).  Cannot expand aliases", strerror(errno));
+				close(pv[0]);
+				close(pv[1]);
+				assassin->expandedrcpt.push_back(envrcpt[0]);
+			} else
+			{
+				close(pv[1]);
+				p = fdopen(pv[0], "r");
+				if (p == NULL)
 				{
-					char *p=strstr(buf,", user ");
-					/* anything after ", user " is the email address */
-					debug(D_RCPT, "user: %s", p+7);
-					assassin->expandedrcpt.push_back(p+7);
+					debug(D_RCPT, "fdopen failed(%s).  Cannot expand aliases", strerror(errno));
+					close(pv[0]);
+					assassin->expandedrcpt.push_back(envrcpt[0]);
+				} else
+				{
+					while (fgets(buf, sizeof(buf), p) != NULL)
+					{
+						int i = strlen(buf);
+						/* strip trailing EOLs */
+						while (i > 0 && buf[i - 1] <= ' ')
+							i--;
+						buf[i] = '\0';
+						debug(D_RCPT, "sendmail output: %s", buf);
+						/*	From a quick scan of the sendmail source, a valid email
+							address gets printed via either
+							    "deliverable: mailer %s, host %s, user %s"
+							or  "deliverable: mailer %s, user %s"
+						*/
+						if (strstr(buf, "... deliverable: mailer "))
+						{
+							char *p=strstr(buf,", user ");
+							/* anything after ", user " is the email address */
+							debug(D_RCPT, "user: %s", p+7);
+							assassin->expandedrcpt.push_back(p+7);
+						}
+					}
+					fclose(p);
+					p = NULL;
+
+					status = -1;
+					do {
+						w = wait(&status);
+					} while ((w != pid) && (w != -1));
+
+					if (w == -1)
+					{
+						status = -1;
+					} else
+					{
+						status = WEXITSTATUS(status);
+					}
+
+					switch (status)
+					{
+						case EX_NOUSER:
+						case EX_OK:
+							break;
+						default:
+							debug(D_RCPT, "Can't execute '%s' to expand '%s' (error %d)\n",
+								SENDMAIL, envrcpt[0], WEXITSTATUS(status));
+							assassin->expandedrcpt.push_back(envrcpt[0]);
+					}
 				}
 			}
-			pclose(p); p = NULL;
 		}
-#if defined(__FreeBSD__)
-		rv = pthread_mutex_unlock(&popen_mutex);
-		if (rv)
-		{
-			debug(D_ALWAYS, "Could not unlock popen mutex: %s", strerror(rv));
-			abort();
-		}		
-#endif
 	} else
 	{
 		assassin->expandedrcpt.push_back(envrcpt[0]);
