diff -U 5 -Nar sendmail-8.13.6.orig/devtools/Site/site.config.m4 sendmail-8.13.6/devtools/Site/site.config.m4
--- sendmail-8.13.6.orig/devtools/Site/site.config.m4	1969-12-31 19:00:00.000000000 -0500
+++ sendmail-8.13.6/devtools/Site/site.config.m4	2006-06-21 11:27:10.000000000 -0400
@@ -0,0 +1,3 @@
+APPENDDEF(`confENVDEF', `-DSUPPORT_DNSSEC=1 -DMILTER')
+define(`confLIBSEARCH', `db 44bsd')
+APPENDDEF(`confLIBS', `-lsres -lval -lcrypto -lpthread')
diff -U 5 -Nar sendmail-8.13.6.orig/doc/op/op.me sendmail-8.13.6/doc/op/op.me
--- sendmail-8.13.6.orig/doc/op/op.me	2005-11-11 21:08:04.000000000 -0500
+++ sendmail-8.13.6/doc/op/op.me	2006-06-21 11:22:56.000000000 -0400
@@ -3497,10 +3497,15 @@
 .q WorkAroundBrokenAAAA
 when faced with a broken nameserver that returns SERVFAIL
 (a temporary failure)
 on T_AAAA (IPv6) lookups
 during hostname canonification.
+Use
+.q RequireDNSSEC
+to require DNSSEC validation of responses to DNS queries in
+sendmail.  If this option is set, a failure in DNSSEC validation
+is treated as a failure in the name lookup.
 Notice: it might be necessary to apply the same (or similar) options to
 .i submit.cf
 too.
 .pp
 Version level 1 configurations (see the section about
diff -U 5 -Nar sendmail-8.13.6.orig/libmilter/sm_gethost.c sendmail-8.13.6/libmilter/sm_gethost.c
--- sendmail-8.13.6.orig/libmilter/sm_gethost.c	2004-08-20 17:12:37.000000000 -0400
+++ sendmail-8.13.6/libmilter/sm_gethost.c	2006-06-21 11:22:56.000000000 -0400
@@ -15,10 +15,47 @@
 #if NETINET || NETINET6
 # include <arpa/inet.h>
 #endif /* NETINET || NETINET6 */
 #include "libmilter.h"
 
+#if SUPPORT_DNSSEC
+# include <validator/validator.h>
+#endif /* SUPPORT_DNSSEC */
+
+/*
+**  MI_VAL_GETHOSTBYNAME -- wrapper for gethostbyname with support for
+**                          DNSSEC validation
+**
+**      Parameters:
+**              name -- a host name, or an IPv4 address in standard dot
+**                      notation, or an IPv6 address in colon (and possibly
+**                      dot) notation.
+**
+**      Returns:
+**              NULL, if there was an error
+**              A non-NULL value of type struct hostent*, if no error occurs
+**
+*/
+
+static struct hostent *
+mi_val_gethostbyname(name)
+        char *name;
+{
+	struct hostent *h;
+#if SUPPORT_DNSSEC
+	int dnssec_status = VAL_INTERNAL_ERROR;
+	h = val_gethostbyname(NULL, name, &dnssec_status);
+	if (RequireDNSSEC && !val_istrusted(dnssec_status)) {
+		h = NULL;
+	}
+#else /* SUPPORT_DNSSEC */
+	h = gethostbyname(name);
+#endif /* SUPPORT_DNSSEC */
+
+	return h;
+}
+
 /*
 **  MI_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
 **
 **	Some operating systems have wierd problems with the gethostbyXXX
 **	routines.  For example, Solaris versions at least through 2.3
@@ -57,17 +94,19 @@
 		/* From RFC2133, section 6.1 */
 		resv6 = bitset(RES_USE_INET6, _res.options);
 		_res.options |= RES_USE_INET6;
 	}
 	SM_SET_H_ERRNO(0);
-	h = gethostbyname(name);
+	h = mi_val_gethostbyname(name);
 	if (family == AF_INET6 && !resv6)
 		_res.options &= ~RES_USE_INET6;
 	*err = h_errno;
 	return h;
 }
+#endif /* NEEDSGETIPNODE && NETINET6 */
 
+#if (NEEDSGETIPNODE && NETINET6) || SUPPORT_DNSSEC
 void
 freehostent(h)
 	struct hostent *h;
 {
 	/*
@@ -75,11 +114,11 @@
 	**  they probably don't have the free routine either.
 	*/
 
 	return;
 }
-#endif /* NEEDSGETIPNODE && NETINET6 */
+#endif /* (NEEDSGETIPNODE && NETINET6) || SUPPORT_DNSSEC */
 
 struct hostent *
 mi_gethostbyname(name, family)
 	char *name;
 	int family;
@@ -108,11 +147,11 @@
 	flags &= ~AI_ADDRCONFIG;
 #  endif /* ADDRCONFIG_IS_BROKEN */
 	h = getipnodebyname(name, family, flags, &err);
 	SM_SET_H_ERRNO(err);
 # else /* NETINET6 */
-	h = gethostbyname(name);
+	h = mi_val_gethostbyname(name);
 # endif /* NETINET6 */
 
 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
 	return h;
 }
diff -U 5 -Nar sendmail-8.13.6.orig/sendmail/conf.c sendmail-8.13.6/sendmail/conf.c
--- sendmail-8.13.6.orig/sendmail/conf.c	2006-02-23 21:21:53.000000000 -0500
+++ sendmail-8.13.6/sendmail/conf.c	2006-06-21 11:22:56.000000000 -0400
@@ -4225,10 +4225,49 @@
 	}
 	return NULL;
 }
 
 #endif /* NEEDSTRSTR */
+
+#if SUPPORT_DNSSEC
+# include <validator/validator.h>
+#endif /* SUPPORT_DNSSEC */
+
+/*
+**  SM_VAL_GETHOSTBYNAME -- wrapper for gethostbyname with support for
+**                          DNSSEC validation
+**
+**      Parameters:
+**              name -- a host name, or an IPv4 address in standard dot
+**                      notation, or an IPv6 address in colon (and possibly
+**                      dot) notation.
+**
+**      Returns:
+**              NULL, if there was an error
+**              A non-NULL value of type struct hostent*, if no error occurs
+**
+*/
+
+static struct hostent *
+sm_val_gethostbyname(name)
+        char *name;
+{
+	struct hostent *h;
+
+#if SUPPORT_DNSSEC
+	int dnssec_status = VAL_INTERNAL_ERROR;
+	h = val_gethostbyname(NULL, name, &dnssec_status);
+	if (RequireDNSSEC && !val_istrusted(dnssec_status)) {
+		h = NULL;
+	}
+#else /* SUPPORT_DNSSEC */
+	h = gethostbyname(name);
+#endif /* SUPPORT_DNSSEC */
+
+	return h;
+}
+
 /*
 **  SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
 **
 **	Some operating systems have wierd problems with the gethostbyXXX
 **	routines.  For example, Solaris versions at least through 2.3
@@ -4268,11 +4307,11 @@
 		/* From RFC2133, section 6.1 */
 		resv6 = bitset(RES_USE_INET6, _res.options);
 		_res.options |= RES_USE_INET6;
 	}
 	SM_SET_H_ERRNO(0);
-	h = gethostbyname(name);
+	h = sm_val_gethostbyname(name);
 	if (!resv6)
 		_res.options &= ~RES_USE_INET6;
 	*err = h_errno;
 	return h;
 }
@@ -4289,11 +4328,13 @@
 	SM_SET_H_ERRNO(0);
 	h = gethostbyaddr(addr, len, family);
 	*err = h_errno;
 	return h;
 }
+#endif /* NETINET6 && NEEDSGETIPNODE */
 
+#if (NETINET6 && NEEDSGETIPNODE) || SUPPORT_DNSSEC
 void
 freehostent(h)
 	struct hostent *h;
 {
 	/*
@@ -4301,11 +4342,11 @@
 	**  they probably don't have the free routine either.
 	*/
 
 	return;
 }
-#endif /* NETINET6 && NEEDSGETIPNODE */
+#endif /* (NETINET6 && NEEDSGETIPNODE) || SUPPORT_DNSSEC */
 
 struct hostent *
 sm_gethostbyname(name, family)
 	char *name;
 	int family;
@@ -4348,11 +4389,11 @@
 	flags &= ~AI_ADDRCONFIG;
 #  endif /* ADDRCONFIG_IS_BROKEN */
 	h = getipnodebyname(name, family, flags, &err);
 	SM_SET_H_ERRNO(err);
 # else /* NETINET6 */
-	h = gethostbyname(name);
+	h = sm_val_gethostbyname(name);
 # endif /* NETINET6 */
 
 	save_errno = errno;
 	if (h == NULL)
 	{
@@ -4388,11 +4429,11 @@
 # if NETINET6
 				h = getipnodebyname(hbuf, family, flags, &err);
 				SM_SET_H_ERRNO(err);
 				save_errno = errno;
 # else /* NETINET6 */
-				h = gethostbyname(hbuf);
+				h = sm_val_gethostbyname(hbuf);
 				save_errno = errno;
 # endif /* NETINET6 */
 			}
 		}
 	}
@@ -4694,13 +4735,13 @@
 			if (tTd(0, 43))
 				sm_dprintf("\ta.k.a.: %s (already in $=w)\n",
 					*ha);
 		}
 	}
-#if NETINET6
+#if NETINET6 || SUPPORT_DNSSEC
 	freehostent(hp);
-#endif /* NETINET6 */
+#endif /* NETINET6 || SUPPORT_DNSSEC */
 	return 0;
 }
 /*
 **  LOAD_IF_NAMES -- load interface-specific names into $=w
 **
diff -U 5 -Nar sendmail-8.13.6.orig/sendmail/domain.c sendmail-8.13.6/sendmail/domain.c
--- sendmail-8.13.6.orig/sendmail/domain.c	2005-03-03 19:54:42.000000000 -0500
+++ sendmail-8.13.6/sendmail/domain.c	2006-06-21 11:22:56.000000000 -0400
@@ -21,10 +21,13 @@
 
 #if NAMED_BIND
 
 # include <arpa/inet.h>
 
+# if SUPPORT_DNSSEC
+#  include <validator/validator.h>
+# endif /* SUPPORT_DNSSEC */
 
 /*
 **  The standard udp packet size PACKETSZ (512) is not sufficient for some
 **  nameserver answers containing very many resource records. The resolver
 **  may switch to tcp and retry if it detects udp packet overflow.
@@ -268,12 +271,68 @@
 		resfunc = res_query;
 	else
 		resfunc = res_search;
 
 	errno = 0;
+
+# if SUPPORT_DNSSEC
+	do
+	{
+		char dname[MAXDNAME];
+		int dnssec_status = VAL_INTERNAL_ERROR;
+		struct val_response *resp;
+
+		bzero(dname, MAXDNAME);
+		strncpy(dname, host, MAXDNAME);
+		getcanonname(dname, MAXDNAME, true, NULL);
+
+		/* perform DNSSEC validation query */
+		n = val_query (NULL, dname, C_IN, T_MX, VAL_QUERY_MERGE_RRSETS, &resp);
+
+		if ((n == 0) && (resp != NULL)) {
+			dnssec_status = resp->vr_val_status;
+			n = resp->vr_length;
+
+			if (resp->vr_length > sizeof answer) {
+				n = -(abs(VAL_INTERNAL_ERROR));
+			}
+			else {
+				memcpy((unsigned char *)&answer, resp->vr_response, resp->vr_length);
+			}
+			if(0 != val_free_response(resp)) {
+				n = -(abs(VAL_INTERNAL_ERROR));
+			} 
+
+			if (RequireDNSSEC)
+			{
+				if (val_istrusted(dnssec_status))
+				{
+					if (tTd(8, 2))
+						sm_dprintf("getmxrr: DNSSEC validation of MX record of %s succeeded.\n", dname);
+				}
+				else
+				{
+					if (tTd(8, 1))
+						sm_dprintf("getmxrr: DNSSEC validation of MX record of %s failed.\n", dname);
+					syserr("Error: DNSSEC validation of MX record of %s failed.\n", dname);
+					*rcode = EX_NOHOST;
+					return -1;
+				}
+			}
+		}
+		else {
+			n = -(abs(n));
+			val_free_response(resp);
+		}
+
+
+	} while (0);
+# else 
 	n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
 		       sizeof(answer));
+# endif /* SUPPORT_DNSSEC */
+
 	if (n < 0)
 	{
 		if (tTd(8, 1))
 			sm_dprintf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n",
 				host == NULL ? "<NULL>" : host, errno, h_errno);
@@ -517,14 +576,14 @@
 				*rcode = EX_CONFIG;
 				syserr("MX list for %s points back to %s",
 				       host, MyHostName);
 				return -1;
 			}
-# if NETINET6
+# if NETINET6 || SUPPORT_DNSSEC
 			freehostent(h);
 			hp = NULL;
-# endif /* NETINET6 */
+# endif /* NETINET6 || SUPPORT_DNSSEC */
 		}
 		if (strlen(host) >= sizeof MXHostBuf)
 		{
 			*rcode = EX_CONFIG;
 			syserr("Host name %s too long",
@@ -895,12 +954,77 @@
 # endif /* NETINET6 */
 				qtype == T_A ? "A" :
 				qtype == T_MX ? "MX" :
 				"???");
 		errno = 0;
+# if SUPPORT_DNSSEC
+		do
+		{
+			char dname[MAXDNAME];
+			int dnssec_status = VAL_INTERNAL_ERROR;
+			struct val_response *resp;
+	
+			bzero(dname, MAXDNAME);
+			memcpy(dname, host, strlen(host));
+			memcpy(dname + strlen(host), ".", 1);
+			memcpy(dname + strlen(host) + 1, *dp, strlen(*dp));
+			
+			if (tTd(8, 5))
+				sm_dprintf("dns_getcanonname(938): performing dnssec validation query.\n");
+
+			/* perform DNSSEC validation query */
+			ret = val_query (NULL, dname, C_IN, qtype, VAL_QUERY_MERGE_RRSETS, &resp);
+
+			if ((ret == 0) && (resp != NULL)) {
+				dnssec_status = resp->vr_val_status;
+				ret = resp->vr_length;
+			
+				if (resp->vr_length > sizeof answer) {
+					ret = -(abs(VAL_INTERNAL_ERROR));
+				}
+				else {
+					memcpy((unsigned char *)&answer, resp->vr_response, resp->vr_length);
+				}
+				if(0 != val_free_response(resp)) {
+					ret = -(abs(VAL_INTERNAL_ERROR));
+				} 
+	
+				if (RequireDNSSEC)
+				{
+					if (val_istrusted(dnssec_status))
+					{
+						if (tTd(8, 2))
+							sm_dprintf("DNSSEC validation of %s succeeded.\n", dname);
+					}
+					else
+					{
+						if (tTd(8, 7))
+							sm_dprintf("\tNO: errno=%d, h_errno=%d\n",
+								   errno, h_errno);
+				    
+						if (tTd(8, 5))
+							sm_dprintf("DNSSEC validation of %s (%s) failed.\n", dname,
+#  if NETINET6
+							   qtype == T_AAAA ? "AAAA" :
+#  endif /* NETINET6 */
+							   qtype == T_A ? "A" :
+							   qtype == T_MX ? "MX" :
+							   "???");
+						goto nexttype;
+					}
+				}
+			}
+			else {
+				ret = -(abs(ret));
+				val_free_response(resp);
+			}
+		} while (0);
+# else /* SUPPORT_DNSSEC */
 		ret = res_querydomain(host, *dp, C_IN, qtype,
 				      answer.qb2, sizeof(answer.qb2));
+# endif /* SUPPORT_DNSSEC */
+
 		if (ret <= 0)
 		{
 			int save_errno = errno;
 
 			if (tTd(8, 7))
diff -U 5 -Nar sendmail-8.13.6.orig/sendmail/readcf.c sendmail-8.13.6/sendmail/readcf.c
--- sendmail-8.13.6.orig/sendmail/readcf.c	2006-03-02 14:17:09.000000000 -0500
+++ sendmail-8.13.6/sendmail/readcf.c	2006-06-21 11:22:56.000000000 -0400
@@ -2600,10 +2600,18 @@
 			if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0)
 			{
 				WorkAroundBrokenAAAA = !clearmode;
 				continue;
 			}
+# if SUPPORT_DNSSEC
+			if (sm_strcasecmp(q, "RequireDNSSEC") == 0)
+			{
+				RequireDNSSEC = !clearmode;
+				continue;
+			}
+# endif /* SUPPORT_DNSSEC */
+
 			for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
 			{
 				if (sm_strcasecmp(q, rfp->rf_name) == 0)
 					break;
 			}
@@ -2613,12 +2621,17 @@
 				_res.options &= ~rfp->rf_bits;
 			else
 				_res.options |= rfp->rf_bits;
 		}
 		if (tTd(8, 2))
+# if SUPPORT_DNSSEC
+			sm_dprintf("_res.options = %x, RequireDNSSEC = %d, HasWildcardMX = %d\n",
+				   (unsigned int) _res.options, RequireDNSSEC, HasWildcardMX);
+# else
 			sm_dprintf("_res.options = %x, HasWildcardMX = %d\n",
 				   (unsigned int) _res.options, HasWildcardMX);
+# endif /* SUPPORT_DNSSEC */
 #else /* NAMED_BIND */
 		usrerr("name server (I option) specified but BIND not compiled in");
 #endif /* NAMED_BIND */
 		break;
 
diff -U 5 -Nar sendmail-8.13.6.orig/sendmail/sendmail.h sendmail-8.13.6/sendmail/sendmail.h
--- sendmail-8.13.6.orig/sendmail/sendmail.h	2006-02-27 12:49:09.000000000 -0500
+++ sendmail-8.13.6/sendmail/sendmail.h	2006-06-21 11:22:56.000000000 -0400
@@ -2152,10 +2152,13 @@
 EXTERN bool	ColonOkInAddr;	/* single colon legal in address */
 #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_)
 EXTERN bool	ConfigFileRead;	/* configuration file has been read */
 #endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */
 EXTERN bool	DisConnected;	/* running with OutChannel redirect to transcript file */
+#if SUPPORT_DNSSEC
+EXTERN bool     RequireDNSSEC;  /* perform DNSSEC validation of DNS queries */
+#endif /* SUPPORT_DNSSEC */
 EXTERN bool	DontExpandCnames;	/* do not $[...$] expand CNAMEs */
 EXTERN bool	DontInitGroups;	/* avoid initgroups() because of NIS cost */
 EXTERN bool	DontLockReadFiles;	/* don't read lock support files */
 EXTERN bool	DontPruneRoutes;	/* don't prune source routes */
 EXTERN bool	ForkQueueRuns;	/* fork for each job when running the queue */
@@ -2489,13 +2492,13 @@
 extern char	*find_character __P((char *, int));
 extern int	finduser __P((char *, bool *, SM_MBDB_T *));
 extern void	finis __P((bool, bool, volatile int));
 extern void	fixcrlf __P((char *, bool));
 extern long	freediskspace __P((char *, long *));
-#if NETINET6 && NEEDSGETIPNODE
+#if (NETINET6 && NEEDSGETIPNODE) || SUPPORT_DNSSEC
 extern void	freehostent __P((struct hostent *));
-#endif /* NETINET6 && NEEDSGETIPNODE */
+#endif /* (NETINET6 && NEEDSGETIPNODE) || SUPPORT_DNSSEC */
 extern char	*get_column __P((char *, int, int, char *, int));
 extern char	*getauthinfo __P((int, bool *));
 extern int	getdtsize __P((void));
 extern int	getla __P((void));
 extern char	*getmodifiers __P((char *, BITMAP256));
diff -U 5 -Nar sendmail-8.13.6.orig/sendmail/sm_resolve.c sendmail-8.13.6/sendmail/sm_resolve.c
--- sendmail-8.13.6.orig/sendmail/sm_resolve.c	2004-08-04 17:17:57.000000000 -0400
+++ sendmail-8.13.6/sendmail/sm_resolve.c	2006-06-21 11:22:56.000000000 -0400
@@ -68,10 +68,14 @@
 	{	"AFSDB",	T_AFSDB		},
 	{	"SRV",		T_SRV		},
 	{	NULL,		0		}
 };
 
+#  if SUPPORT_DNSSEC
+#   include <validator/validator.h>
+#  endif /* SUPPORT_DNSSEC */
+
 static DNS_REPLY_T *parse_dns_reply __P((unsigned char *, int));
 
 /*
 **  DNS_STRING_TO_TYPE -- convert resource record name into type
 **
@@ -407,11 +411,66 @@
 		save_retry = _res.retry;
 		_res.retry = retry;
 	}
 	errno = 0;
 	SM_SET_H_ERRNO(0);
+
+#  if SUPPORT_DNSSEC
+	if (tTd(8, 16))
+		sm_dprintf("dns_lookup_int(%s, %d, %s): ",
+			   domain, rr_class, dns_type_to_string(rr_type));
+	do
+	{
+		char dname[MAXDNAME];
+		struct val_response *resp;
+		int dnssec_status = VAL_INTERNAL_ERROR;
+
+		bzero(dname, MAXDNAME);
+		strncpy(dname, domain, MAXDNAME);
+		getcanonname(dname, MAXDNAME, true, NULL);
+
+		/* perform DNSSEC validation query */
+		len = val_query(NULL, dname, rr_class, rr_type, VAL_QUERY_MERGE_RRSETS, &resp);
+
+		if ((len == 0) && (resp != NULL)) {
+			dnssec_status = resp->vr_val_status;
+			len = resp->vr_length;
+
+			if (resp->vr_length > sizeof reply) {
+				len = -(abs(VAL_INTERNAL_ERROR));
+			}
+			else {
+				memcpy(reply, resp->vr_response, resp->vr_length); 
+			}
+			if (0 != val_free_response(resp)) {
+				len = -(abs(VAL_INTERNAL_ERROR));
+			}
+
+			if (RequireDNSSEC)
+			{
+				if (val_istrusted(dnssec_status))
+				{
+					if (tTd(8, 2))
+						sm_dprintf("\t\tdnssec validation of %s succeeded.\n", domain);
+				}
+				else
+				{
+					if (tTd(8, 1))
+						sm_dprintf("\t\tdnssec validation of %s failed.\n", domain);
+					return NULL;
+				}
+			}
+		}
+		else {
+			len = -(abs(len));
+			val_free_response(resp);
+		}
+	} while (0);
+#  else
 	len = res_search(domain, rr_class, rr_type, reply, sizeof reply);
+#  endif /* SUPPORT_DNSSEC */
+
 	if (tTd(8, 16))
 	{
 		_res.options = old_options;
 		sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n",
 			   domain, rr_class, dns_type_to_string(rr_type), len);
