diff -U 5 -Nar sendmail-8.14.1.orig/devtools/Site/site.config.m4 sendmail-8.14.1/devtools/Site/site.config.m4 --- sendmail-8.14.1.orig/devtools/Site/site.config.m4 1969-12-31 19:00:00.000000000 -0500 +++ sendmail-8.14.1/devtools/Site/site.config.m4 2008-05-12 10:05:55.000000000 -0400 @@ -0,0 +1,3 @@ +APPENDDEF(`confENVDEF', `-DSUPPORT_DNSSEC=1 -DMILTER') +define(`confLIBSEARCH', `db 44bsd') +APPENDDEF(`confLIBS', `-lsres -lval-threads -lcrypto -lpthread') diff -U 5 -Nar sendmail-8.14.1.orig/libmilter/sm_gethost.c sendmail-8.14.1/libmilter/sm_gethost.c --- sendmail-8.14.1.orig/libmilter/sm_gethost.c 2004-08-20 17:12:37.000000000 -0400 +++ sendmail-8.14.1/libmilter/sm_gethost.c 2008-05-12 10:09:42.000000000 -0400 @@ -15,10 +15,49 @@ #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 + val_status_t dnssec_status = VAL_INTERNAL_ERROR; + h = val_gethostbyname(NULL, name, &dnssec_status); + if (h && !val_istrusted(dnssec_status)) { + h = NULL; + h_errno = NO_DATA; + + } +#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 +96,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) void freehostent(h) struct hostent *h; { /* @@ -75,11 +116,11 @@ ** they probably don't have the free routine either. */ return; } -#endif /* NEEDSGETIPNODE && NETINET6 */ +#endif /* (NEEDSGETIPNODE && NETINET6) */ struct hostent * mi_gethostbyname(name, family) char *name; int family; @@ -108,11 +149,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.14.1.orig/sendmail/conf.c sendmail-8.14.1/sendmail/conf.c --- sendmail-8.14.1.orig/sendmail/conf.c 2007-04-03 17:32:29.000000000 -0400 +++ sendmail-8.14.1/sendmail/conf.c 2008-05-12 10:09:51.000000000 -0400 @@ -4165,10 +4165,51 @@ } 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 + val_status_t dnssec_status = VAL_INTERNAL_ERROR; + h = val_gethostbyname(NULL, name, &dnssec_status); + if (h && !val_istrusted(dnssec_status)) { + h = NULL; + h_errno = NO_DATA; + + } +#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 @@ -4208,11 +4249,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; } @@ -4229,11 +4270,13 @@ SM_SET_H_ERRNO(0); h = gethostbyaddr(addr, len, family); *err = h_errno; return h; } +#endif /* NETINET6 && NEEDSGETIPNODE */ +#if (NETINET6 && NEEDSGETIPNODE) void freehostent(h) struct hostent *h; { /* @@ -4241,11 +4284,11 @@ ** they probably don't have the free routine either. */ return; } -#endif /* NETINET6 && NEEDSGETIPNODE */ +#endif /* (NETINET6 && NEEDSGETIPNODE) */ struct hostent * sm_gethostbyname(name, family) char *name; int family; @@ -4288,11 +4331,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) { @@ -4328,11 +4371,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 */ } } } @@ -4635,13 +4678,13 @@ if (tTd(0, 43)) sm_dprintf("\ta.k.a.: %s (already in $=w)\n", *ha); } } -#if NETINET6 +#if NETINET6 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.14.1.orig/sendmail/domain.c sendmail-8.14.1/sendmail/domain.c --- sendmail-8.14.1.orig/sendmail/domain.c 2006-12-18 20:15:07.000000000 -0500 +++ sendmail-8.14.1/sendmail/domain.c 2008-05-12 10:12:42.000000000 -0400 @@ -22,10 +22,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. @@ -222,11 +225,15 @@ unsigned short pref, type; unsigned short localpref = 256; char *fallbackMX = FallbackMX; bool trycanon = false; unsigned short *prefs; +#if SUPPORT_DNSSEC + int (*resfunc) __P((val_context_t *, const char *, int, int, u_char *, int, val_status_t *)); +#else int (*resfunc) __P((const char *, int, int, u_char *, int)); +#endif unsigned short prefer[MAXMXHOSTS]; int weight[MAXMXHOSTS]; int ttl = 0; extern int res_query(), res_search(); @@ -264,17 +271,50 @@ */ if (!UseNameServer) goto punt; if (HasWildcardMX && ConfigLevel >= 6) +#if SUPPORT_DNSSEC + resfunc = val_res_query; +#else resfunc = res_query; +#endif else +#if SUPPORT_DNSSEC + resfunc = val_res_search; +#else resfunc = res_search; +#endif errno = 0; + +# if SUPPORT_DNSSEC + do { + val_status_t dnssec_status = VAL_INTERNAL_ERROR; + n = (*resfunc)(NULL, host, C_IN, T_MX, (unsigned char *) &answer, + sizeof(answer), &dnssec_status); + if (n >= 0) { + if (val_istrusted(dnssec_status)) + { + if (tTd(8, 2)) + sm_dprintf("getmxrr: DNSSEC validation of MX record of %s succeeded.\n", host); + } + else + { + if (tTd(8, 1)) + sm_dprintf("getmxrr: DNSSEC validation of MX record of %s failed.\n", host); + syserr("Error: DNSSEC validation of MX record of %s failed.\n", host); + h_errno = NO_DATA; + n = -1; + } + } + } 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, errno, h_errno); @@ -518,11 +558,11 @@ *rcode = EX_CONFIG; syserr("MX list for %s points back to %s", host, MyHostName); return -1; } -# if NETINET6 +# if NETINET6 freehostent(h); h = NULL; # endif /* NETINET6 */ } if (strlen(host) >= sizeof(MXHostBuf)) @@ -896,12 +936,60 @@ # endif /* NETINET6 */ qtype == T_A ? "A" : qtype == T_MX ? "MX" : "???"); errno = 0; +# if SUPPORT_DNSSEC + do + { + char dname[MAXDNAME]; + val_status_t dnssec_status = VAL_INTERNAL_ERROR; + + 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_res_query (NULL, dname, C_IN, qtype, (unsigned char *) &answer, + sizeof(answer), &dnssec_status); + + if (ret > 0) { + 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); + + h_errno = NO_DATA; + ret = -1; + + + + + + + + + + + } + } + } 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.14.1.orig/sendmail/sm_resolve.c sendmail-8.14.1/sendmail/sm_resolve.c --- sendmail-8.14.1.orig/sendmail/sm_resolve.c 2006-08-15 19:24:58.000000000 -0400 +++ sendmail-8.14.1/sendmail/sm_resolve.c 2008-05-12 10:15:06.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,41 @@ 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 + { + val_status_t dnssec_status = VAL_INTERNAL_ERROR; + + /* perform DNSSEC validation query */ + len = val_res_search(NULL, domain, rr_class, rr_type, reply, sizeof(reply), &dnssec_status); + + if (len >= 0) { + 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); + h_errno = NO_DATA; + len = -1; + } + } + } 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);