BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / sendmail / src / domain.c
index afdf2de..61570ed 100644 (file)
@@ -1,32 +1,56 @@
 /*
 /*
- * Copyright (c) 1986 Eric P. Allman
+ * Copyright (c) 1986, 1995 Eric P. Allman
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #include "sendmail.h"
 
 #ifndef lint
  */
 
 #include "sendmail.h"
 
 #ifndef lint
-#ifdef NAMED_BIND
-static char sccsid[] = "@(#)domain.c   8.11 (Berkeley) %G% (with name server)";
+#if NAMED_BIND
+static char sccsid[] = "@(#)domain.c   8.47 (Berkeley) 6/20/95 (with name server)";
 #else
 #else
-static char sccsid[] = "@(#)domain.c   8.11 (Berkeley) %G% (without name server)";
+static char sccsid[] = "@(#)domain.c   8.47 (Berkeley) 6/20/95 (without name server)";
 #endif
 #endif /* not lint */
 
 #endif
 #endif /* not lint */
 
-#ifdef NAMED_BIND
+#if NAMED_BIND
 
 #include <errno.h>
 
 #include <errno.h>
-#include <arpa/nameser.h>
 #include <resolv.h>
 #include <resolv.h>
-#include <netdb.h>
 
 typedef union
 {
        HEADER  qb1;
 
 typedef union
 {
        HEADER  qb1;
-       char    qb2[PACKETSZ];
+       u_char  qb2[PACKETSZ];
 } querybuf;
 
 static char    MXHostBuf[MAXMXHOSTS*PACKETSZ];
 } querybuf;
 
 static char    MXHostBuf[MAXMXHOSTS*PACKETSZ];
@@ -43,15 +67,17 @@ static char MXHostBuf[MAXMXHOSTS*PACKETSZ];
 # define NO_DATA       NO_ADDRESS
 #endif
 
 # define NO_DATA       NO_ADDRESS
 #endif
 
-#ifndef HEADERSZ
-# define HEADERSZ      sizeof(HEADER)
+#ifndef HFIXEDSZ
+# define HFIXEDSZ      12      /* sizeof(HEADER) */
 #endif
 
 #endif
 
-/* don't use sizeof because sizeof(long) is different on 64-bit machines */
-#define SHORTSIZE      2       /* size of a short (really, must be 2) */
-#define LONGSIZE       4       /* size of a long (really, must be 4) */
-
 #define MAXCNAMEDEPTH  10      /* maximum depth of CNAME recursion */
 #define MAXCNAMEDEPTH  10      /* maximum depth of CNAME recursion */
+
+#if defined(__RES) && (__RES >= 19940415)
+# define RES_UNC_T     char *
+#else
+# define RES_UNC_T     u_char *
+#endif
 \f/*
 **  GETMXRR -- get MX resource records for a domain
 **
 \f/*
 **  GETMXRR -- get MX resource records for a domain
 **
@@ -70,13 +96,13 @@ static char MXHostBuf[MAXMXHOSTS*PACKETSZ];
 **                     and 1 is returned.
 */
 
 **                     and 1 is returned.
 */
 
+int
 getmxrr(host, mxhosts, droplocalhost, rcode)
        char *host;
        char **mxhosts;
        bool droplocalhost;
        int *rcode;
 {
 getmxrr(host, mxhosts, droplocalhost, rcode)
        char *host;
        char **mxhosts;
        bool droplocalhost;
        int *rcode;
 {
-       extern int h_errno;
        register u_char *eom, *cp;
        register int i, j, n;
        int nmx = 0;
        register u_char *eom, *cp;
        register int i, j, n;
        int nmx = 0;
@@ -85,26 +111,30 @@ getmxrr(host, mxhosts, droplocalhost, rcode)
        querybuf answer;
        int ancount, qdcount, buflen;
        bool seenlocal = FALSE;
        querybuf answer;
        int ancount, qdcount, buflen;
        bool seenlocal = FALSE;
-       u_short pref, localpref, type;
+       u_short pref, type;
+       u_short localpref = 256;
        char *fallbackMX = FallBackMX;
        static bool firsttime = TRUE;
        char *fallbackMX = FallBackMX;
        static bool firsttime = TRUE;
-       STAB *st;
        bool trycanon = FALSE;
        bool trycanon = FALSE;
+       int (*resfunc)();
+       extern int res_query(), res_search();
        u_short prefer[MAXMXHOSTS];
        int weight[MAXMXHOSTS];
        extern bool getcanonname();
 
        u_short prefer[MAXMXHOSTS];
        int weight[MAXMXHOSTS];
        extern bool getcanonname();
 
+       if (tTd(8, 2))
+               printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost);
+
        if (fallbackMX != NULL)
        {
        if (fallbackMX != NULL)
        {
-               if (firsttime && res_query(FallBackMX, C_IN, T_A,
-                                          (char *) &answer, sizeof answer) < 0)
+               if (firsttime &&
+                   res_query(FallBackMX, C_IN, T_A,
+                             (u_char *) &answer, sizeof answer) < 0)
                {
                        /* this entry is bogus */
                        fallbackMX = FallBackMX = NULL;
                }
                {
                        /* this entry is bogus */
                        fallbackMX = FallBackMX = NULL;
                }
-               else if (droplocalhost &&
-                        (st = stab(fallbackMX, ST_CLASS, ST_FIND)) != NULL &&
-                        bitnset('w', st->s_class))
+               else if (droplocalhost && wordinclass(fallbackMX, 'w'))
                {
                        /* don't use fallback for this pass */
                        fallbackMX = NULL;
                {
                        /* don't use fallback for this pass */
                        fallbackMX = NULL;
@@ -112,12 +142,29 @@ getmxrr(host, mxhosts, droplocalhost, rcode)
                firsttime = FALSE;
        }
 
                firsttime = FALSE;
        }
 
+       *rcode = EX_OK;
+
        /* efficiency hack -- numeric or non-MX lookups */
        if (host[0] == '[')
                goto punt;
 
        /* efficiency hack -- numeric or non-MX lookups */
        if (host[0] == '[')
                goto punt;
 
+       /*
+       **  If we don't have MX records in our host switch, don't
+       **  try for MX records.  Note that this really isn't "right",
+       **  since we might be set up to try NIS first and then DNS;
+       **  if the host is found in NIS we really shouldn't be doing
+       **  MX lookups.  However, that should be a degenerate case.
+       */
+
+       if (!UseNameServer)
+               goto punt;
+       if (HasWildcardMX && ConfigLevel >= 6)
+               resfunc = res_query;
+       else
+               resfunc = res_search;
+
        errno = 0;
        errno = 0;
-       n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer));
+       n = (*resfunc)(host, C_IN, T_MX, (u_char *) &answer, sizeof(answer));
        if (n < 0)
        {
                if (tTd(8, 1))
        if (n < 0)
        {
                if (tTd(8, 1))
@@ -134,24 +181,24 @@ getmxrr(host, mxhosts, droplocalhost, rcode)
                        goto punt;
 
                  case HOST_NOT_FOUND:
                        goto punt;
 
                  case HOST_NOT_FOUND:
-                       /* the host just doesn't exist */
+#if BROKEN_RES_SEARCH
+                 case 0:       /* Ultrix resolver retns failure w/ h_errno=0 */
+#endif
+                       /* host doesn't exist in DNS; might be in /etc/hosts */
                        *rcode = EX_NOHOST;
                        *rcode = EX_NOHOST;
-
-                       if (!UseNameServer)
-                       {
-                               /* might exist in /etc/hosts */
-                               goto punt;
-                       }
-                       break;
+                       goto punt;
 
                  case TRY_AGAIN:
                        /* couldn't connect to the name server */
 
                  case TRY_AGAIN:
                        /* couldn't connect to the name server */
-                       if (!UseNameServer && errno == ECONNREFUSED)
-                               goto punt;
-
                        /* it might come up later; better queue it up */
                        *rcode = EX_TEMPFAIL;
                        break;
                        /* it might come up later; better queue it up */
                        *rcode = EX_TEMPFAIL;
                        break;
+
+                 default:
+                       syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n",
+                               host, h_errno);
+                       *rcode = EX_OSERR;
+                       break;
                }
 
                /* irreconcilable differences */
                }
 
                /* irreconcilable differences */
@@ -160,7 +207,7 @@ getmxrr(host, mxhosts, droplocalhost, rcode)
 
        /* find first satisfactory answer */
        hp = (HEADER *)&answer;
 
        /* find first satisfactory answer */
        hp = (HEADER *)&answer;
-       cp = (u_char *)&answer + HEADERSZ;
+       cp = (u_char *)&answer + HFIXEDSZ;
        eom = (u_char *)&answer + n;
        for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
                if ((n = dn_skipname(cp, eom)) < 0)
        eom = (u_char *)&answer + n;
        for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
                if ((n = dn_skipname(cp, eom)) < 0)
@@ -171,11 +218,11 @@ getmxrr(host, mxhosts, droplocalhost, rcode)
        while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
        {
                if ((n = dn_expand((u_char *)&answer,
        while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
        {
                if ((n = dn_expand((u_char *)&answer,
-                   eom, cp, (u_char *)bp, buflen)) < 0)
+                   eom, cp, (RES_UNC_T) bp, buflen)) < 0)
                        break;
                cp += n;
                GETSHORT(type, cp);
                        break;
                cp += n;
                GETSHORT(type, cp);
-               cp += SHORTSIZE + LONGSIZE;
+               cp += INT16SZ + INT32SZ;
                GETSHORT(n, cp);
                if (type != T_MX)
                {
                GETSHORT(n, cp);
                if (type != T_MX)
                {
@@ -187,20 +234,19 @@ getmxrr(host, mxhosts, droplocalhost, rcode)
                }
                GETSHORT(pref, cp);
                if ((n = dn_expand((u_char *)&answer, eom, cp,
                }
                GETSHORT(pref, cp);
                if ((n = dn_expand((u_char *)&answer, eom, cp,
-                                  (u_char *)bp, buflen)) < 0)
+                                  (RES_UNC_T) bp, buflen)) < 0)
                        break;
                cp += n;
                        break;
                cp += n;
-               if (droplocalhost &&
-                   (st = stab(bp, ST_CLASS, ST_FIND)) != NULL &&
-                   bitnset('w', st->s_class))
+               if (droplocalhost && wordinclass(bp, 'w'))
                {
                {
+                       if (tTd(8, 3))
+                               printf("found localhost (%s) in MX list, pref=%d\n",
+                                       bp, pref);
                        if (!seenlocal || pref < localpref)
                                localpref = pref;
                        seenlocal = TRUE;
                        continue;
                }
                        if (!seenlocal || pref < localpref)
                                localpref = pref;
                        seenlocal = TRUE;
                        continue;
                }
-               if (fallbackMX != NULL && strcasecmp(bp, fallbackMX) == 0)
-                       fallbackMX = NULL;
                weight[nmx] = mxrand(bp);
                prefer[nmx] = pref;
                mxhosts[nmx++] = bp;
                weight[nmx] = mxrand(bp);
                prefer[nmx] = pref;
                mxhosts[nmx++] = bp;
@@ -248,7 +294,7 @@ getmxrr(host, mxhosts, droplocalhost, rcode)
        {
 punt:
                if (seenlocal &&
        {
 punt:
                if (seenlocal &&
-                   (!TryNullMXList || gethostbyname(host) == NULL))
+                   (!TryNullMXList || sm_gethostbyname(host) == NULL))
                {
                        /*
                        **  If we have deleted all MX entries, this is
                {
                        /*
                        **  If we have deleted all MX entries, this is
@@ -263,6 +309,8 @@ punt:
                        */
 
                        *rcode = EX_CONFIG;
                        */
 
                        *rcode = EX_CONFIG;
+                       syserr("MX list for %s points back to %s",
+                               host, MyHostName);
                        return -1;
                }
                strcpy(MXHostBuf, host);
                        return -1;
                }
                strcpy(MXHostBuf, host);
@@ -285,35 +333,22 @@ punt:
                                }
                        }
                }
                                }
                        }
                }
-               n = strlen(MXHostBuf);
-               bp = &MXHostBuf[n];
-               buflen = sizeof MXHostBuf - n - 1;
                if (trycanon &&
                    getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE))
                {
                if (trycanon &&
                    getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE))
                {
+                       bp = &MXHostBuf[strlen(MXHostBuf)];
                        if (bp[-1] != '.')
                        {
                                *bp++ = '.';
                                *bp = '\0';
                        if (bp[-1] != '.')
                        {
                                *bp++ = '.';
                                *bp = '\0';
-                               buflen--;
                        }
                        }
+                       nmx = 1;
                }
                }
-               bp++;
-               nmx = 1;
        }
 
        /* if we have a default lowest preference, include that */
        }
 
        /* if we have a default lowest preference, include that */
-       if (fallbackMX != NULL && !seenlocal && strlen(fallbackMX) < buflen)
-       {
-               strcpy(bp, fallbackMX);
-               mxhosts[nmx++] = bp;
-               bp += strlen(bp);
-               if (bp[-1] != '.')
-               {
-                       *bp++ = '.';
-                       *bp = '\0';
-               }
-       }
+       if (fallbackMX != NULL && !seenlocal)
+               mxhosts[nmx++] = fallbackMX;
 
        return (nmx);
 }
 
        return (nmx);
 }
@@ -335,6 +370,7 @@ punt:
 **             none.
 */
 
 **             none.
 */
 
+int
 mxrand(host)
        register char *host;
 {
 mxrand(host)
        register char *host;
 {
@@ -358,7 +394,7 @@ mxrand(host)
 
                if (isascii(c) && isupper(c))
                        c = tolower(c);
 
                if (isascii(c) && isupper(c))
                        c = tolower(c);
-               hfunc = ((hfunc << 1) + c) % 2003;
+               hfunc = ((hfunc << 1) ^ c) % 2003;
        }
 
        hfunc &= 0xff;
        }
 
        hfunc &= 0xff;
@@ -368,7 +404,36 @@ mxrand(host)
        return hfunc;
 }
 \f/*
        return hfunc;
 }
 \f/*
-**  GETCANONNAME -- get the canonical name for named host
+**  BESTMX -- find the best MX for a name
+**
+**     This is really a hack, but I don't see any obvious way
+**     to generalize it at the moment.
+*/
+
+char *
+bestmx_map_lookup(map, name, av, statp)
+       MAP *map;
+       char *name;
+       char **av;
+       int *statp;
+{
+       int nmx;
+       auto int rcode;
+       int saveopts = _res.options;
+       char *mxhosts[MAXMXHOSTS + 1];
+
+       _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
+       nmx = getmxrr(name, mxhosts, FALSE, &rcode);
+       _res.options = saveopts;
+       if (nmx <= 0)
+               return NULL;
+       if (bitset(MF_MATCHONLY, map->map_mflags))
+               return map_rewrite(map, name, strlen(name), NULL);
+       else
+               return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
+}
+\f/*
+**  DNS_GETCANONNAME -- get the canonical name for named host using DNS
 **
 **     This algorithm tries to be smart about wildcard MX records.
 **     This is hard to do because DNS doesn't tell is if we matched
 **
 **     This algorithm tries to be smart about wildcard MX records.
 **     This is hard to do because DNS doesn't tell is if we matched
@@ -390,6 +455,7 @@ mxrand(host)
 **                     This is a value-result parameter.
 **             hbsize -- the size of the host buffer.
 **             trymx -- if set, try MX records as well as A and CNAME.
 **                     This is a value-result parameter.
 **             hbsize -- the size of the host buffer.
 **             trymx -- if set, try MX records as well as A and CNAME.
+**             statp -- pointer to place to store status.
 **
 **     Returns:
 **             TRUE -- if the host matched.
 **
 **     Returns:
 **             TRUE -- if the host matched.
@@ -397,12 +463,12 @@ mxrand(host)
 */
 
 bool
 */
 
 bool
-getcanonname(host, hbsize, trymx)
+dns_getcanonname(host, hbsize, trymx, statp)
        char *host;
        int hbsize;
        bool trymx;
        char *host;
        int hbsize;
        bool trymx;
+       int *statp;
 {
 {
-       extern int h_errno;
        register u_char *eom, *ap;
        register char *cp;
        register int n; 
        register u_char *eom, *ap;
        register char *cp;
        register int n; 
@@ -415,7 +481,7 @@ getcanonname(host, hbsize, trymx)
        char **dp;
        char *mxmatch;
        bool amatch;
        char **dp;
        char *mxmatch;
        bool amatch;
-       bool gotmx;
+       bool gotmx = FALSE;
        int qtype;
        int loopcnt;
        char *xp;
        int qtype;
        int loopcnt;
        char *xp;
@@ -424,10 +490,13 @@ getcanonname(host, hbsize, trymx)
        extern char *gethostalias();
 
        if (tTd(8, 2))
        extern char *gethostalias();
 
        if (tTd(8, 2))
-               printf("getcanonname(%s)\n", host);
+               printf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
 
        if ((_res.options & RES_INIT) == 0 && res_init() == -1)
 
        if ((_res.options & RES_INIT) == 0 && res_init() == -1)
-               return (FALSE);
+       {
+               *statp = EX_UNAVAILABLE;
+               return FALSE;
+       }
 
        /*
        **  Initialize domain search list.  If there is at least one
 
        /*
        **  Initialize domain search list.  If there is at least one
@@ -441,7 +510,7 @@ getcanonname(host, hbsize, trymx)
 
        loopcnt = 0;
 cnameloop:
 
        loopcnt = 0;
 cnameloop:
-       for (cp = host, n = 0; *cp; cp++)
+       for (cp = host, n = 0; *cp != '\0'; cp++)
                if (*cp == '.')
                        n++;
 
                if (*cp == '.')
                        n++;
 
@@ -471,8 +540,16 @@ cnameloop:
        {
                *dp++ = _res.defdname;
        }
        {
                *dp++ = _res.defdname;
        }
+       else if (*cp == '.')
+       {
+               *cp = '\0';
+       }
        *dp = NULL;
 
        *dp = NULL;
 
+       /* if we have a wildcard MX and no dots, try MX anyhow */
+       if (n == 0)
+               trymx = TRUE;
+
        /*
        **  Now run through the search list for the name in question.
        */
        /*
        **  Now run through the search list for the name in question.
        */
@@ -485,11 +562,12 @@ cnameloop:
                if (qtype == T_ANY)
                        gotmx = FALSE;
                if (tTd(8, 5))
                if (qtype == T_ANY)
                        gotmx = FALSE;
                if (tTd(8, 5))
-                       printf("getcanonname: trying %s.%s (%s)\n", host, *dp,
+                       printf("dns_getcanonname: trying %s.%s (%s)\n",
+                               host, *dp,
                                qtype == T_ANY ? "ANY" : qtype == T_A ? "A" :
                                qtype == T_MX ? "MX" : "???");
                ret = res_querydomain(host, *dp, C_IN, qtype,
                                qtype == T_ANY ? "ANY" : qtype == T_A ? "A" :
                                qtype == T_MX ? "MX" : "???");
                ret = res_querydomain(host, *dp, C_IN, qtype,
-                                     &answer, sizeof(answer));
+                                     answer.qb2, sizeof(answer.qb2));
                if (ret <= 0)
                {
                        if (tTd(8, 7))
                if (ret <= 0)
                {
                        if (tTd(8, 7))
@@ -500,6 +578,7 @@ cnameloop:
                        {
                                /* the name server seems to be down */
                                h_errno = TRY_AGAIN;
                        {
                                /* the name server seems to be down */
                                h_errno = TRY_AGAIN;
+                               *statp = EX_TEMPFAIL;
                                return FALSE;
                        }
 
                                return FALSE;
                        }
 
@@ -518,13 +597,7 @@ cnameloop:
                                }
                        }
 
                                }
                        }
 
-                       if (mxmatch != NULL)
-                       {
-                               /* we matched before -- use that one */
-                               break;
-                       }
-
-                       /* otherwise, try the next name */
+                       /* try the next name */
                        dp++;
                        qtype = T_ANY;
                        continue;
                        dp++;
                        qtype = T_ANY;
                        continue;
@@ -539,7 +612,7 @@ cnameloop:
                */
 
                hp = (HEADER *) &answer;
                */
 
                hp = (HEADER *) &answer;
-               ap = (u_char *) &answer + HEADERSZ;
+               ap = (u_char *) &answer + HFIXEDSZ;
                eom = (u_char *) &answer + ret;
 
                /* skip question part of response -- we know what we asked */
                eom = (u_char *) &answer + ret;
 
                /* skip question part of response -- we know what we asked */
@@ -550,6 +623,7 @@ cnameloop:
                                if (tTd(8, 20))
                                        printf("qdcount failure (%d)\n",
                                                ntohs(hp->qdcount));
                                if (tTd(8, 20))
                                        printf("qdcount failure (%d)\n",
                                                ntohs(hp->qdcount));
+                               *statp = EX_SOFTWARE;
                                return FALSE;           /* ???XXX??? */
                        }
                }
                                return FALSE;           /* ???XXX??? */
                        }
                }
@@ -558,18 +632,18 @@ cnameloop:
                for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; ap += n)
                {
                        n = dn_expand((u_char *) &answer, eom, ap,
                for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; ap += n)
                {
                        n = dn_expand((u_char *) &answer, eom, ap,
-                                     (u_char *) nbuf, sizeof nbuf);
+                                     (RES_UNC_T) nbuf, sizeof nbuf);
                        if (n < 0)
                                break;
                        ap += n;
                        GETSHORT(type, ap);
                        if (n < 0)
                                break;
                        ap += n;
                        GETSHORT(type, ap);
-                       ap += SHORTSIZE + LONGSIZE;
+                       ap += INT16SZ + INT32SZ;
                        GETSHORT(n, ap);
                        switch (type)
                        {
                          case T_MX:
                                gotmx = TRUE;
                        GETSHORT(n, ap);
                        switch (type)
                        {
                          case T_MX:
                                gotmx = TRUE;
-                               if (**dp != '\0')
+                               if (**dp != '\0' || !HasWildcardMX)
                                {
                                        /* got a match -- save that info */
                                        if (trymx && mxmatch == NULL)
                                {
                                        /* got a match -- save that info */
                                        if (trymx && mxmatch == NULL)
@@ -588,16 +662,34 @@ cnameloop:
                                continue;
 
                          case T_CNAME:
                                continue;
 
                          case T_CNAME:
+                               if (DontExpandCnames)
+                               {
+                                       /* got CNAME -- guaranteed canonical */
+                                       amatch = TRUE;
+                                       break;
+                               }
+
                                if (loopcnt++ > MAXCNAMEDEPTH)
                                {
                                if (loopcnt++ > MAXCNAMEDEPTH)
                                {
-                                       syserr("DNS failure: CNAME loop for %s",
+                                       /*XXX should notify postmaster XXX*/
+                                       message("DNS failure: CNAME loop for %s",
                                                host);
                                                host);
-                                       continue;
+                                       if (CurEnv->e_message == NULL)
+                                       {
+                                               char ebuf[MAXLINE];
+
+                                               sprintf(ebuf, "Deferred: DNS failure: CNAME loop for %s",
+                                                       host);
+                                               CurEnv->e_message = newstr(ebuf);
+                                       }
+                                       h_errno = NO_RECOVERY;
+                                       *statp = EX_CONFIG;
+                                       return FALSE;
                                }
 
                                /* value points at name */
                                if ((ret = dn_expand((u_char *)&answer,
                                }
 
                                /* value points at name */
                                if ((ret = dn_expand((u_char *)&answer,
-                                   eom, ap, (u_char *)nbuf, sizeof(nbuf))) < 0)
+                                   eom, ap, (RES_UNC_T) nbuf, sizeof(nbuf))) < 0)
                                        break;
                                (void)strncpy(host, nbuf, hbsize); /* XXX */
                                host[hbsize - 1] = '\0';
                                        break;
                                (void)strncpy(host, nbuf, hbsize); /* XXX */
                                host[hbsize - 1] = '\0';
@@ -641,7 +733,10 @@ cnameloop:
        }
 
        if (mxmatch == NULL)
        }
 
        if (mxmatch == NULL)
+       {
+               *statp = EX_NOHOST;
                return FALSE;
                return FALSE;
+       }
 
        /* create matching name and return */
        (void) sprintf(nbuf, "%.*s%s%.*s", MAXDNAME, host,
 
        /* create matching name and return */
        (void) sprintf(nbuf, "%.*s%s%.*s", MAXDNAME, host,
@@ -649,6 +744,7 @@ cnameloop:
                        MAXDNAME, mxmatch);
        strncpy(host, nbuf, hbsize);
        host[hbsize - 1] = '\0';
                        MAXDNAME, mxmatch);
        strncpy(host, nbuf, hbsize);
        host[hbsize - 1] = '\0';
+       *statp = EX_OK;
        return TRUE;
 }
 
        return TRUE;
 }
 
@@ -659,12 +755,13 @@ gethostalias(host)
 {
        char *fname;
        FILE *fp;
 {
        char *fname;
        FILE *fp;
-       register char *p;
+       register char *p = NULL;
        char buf[MAXLINE];
        static char hbuf[MAXDNAME];
 
        fname = getenv("HOSTALIASES");
        char buf[MAXLINE];
        static char hbuf[MAXDNAME];
 
        fname = getenv("HOSTALIASES");
-       if (fname == NULL || (fp = fopen(fname, "r")) == NULL)
+       if (fname == NULL ||
+           (fp = safefopen(fname, O_RDONLY, 0, SFF_REGONLY)) == NULL)
                return NULL;
        while (fgets(buf, sizeof buf, fp) != NULL)
        {
                return NULL;
        while (fgets(buf, sizeof buf, fp) != NULL)
        {
@@ -699,152 +796,4 @@ gethostalias(host)
        return hbuf;
 }
 
        return hbuf;
 }
 
-\f/*
-**  MAILB_LOOKUP -- do DNS mailbox lookup
-*/
-
-#ifdef DNS_MAILB
-
-mailb_lookup(addr)
-       char *addr;
-{
-       /*
-       **  Convert addr to DNS form (user.host).
-       */
-
-       /* figure out how much space it needs */
-       atp = strchr(addr, '@');
-       if (atp == NULL)
-               atp = &addr(strlen(addr));
-       i = strlen(addr);
-       for (p = addr; (p = strchr(p, '.')) != NULL; p++)
-       {
-               if (p > atp)
-                       break;
-               i++;
-       }
-       if (i < sizeof abuf)
-               bufp = abuf;
-       else
-               bufp = xalloc(i + 1);
-
-       lhsmode = TRUE;
-       for (p = addr, q = bufp; (c = *p++) != '\0'; )
-       {
-               if (c == '.' && lhsmode)
-                       *q++ = '\\';
-               if (c == '@')
-                       lhsmode = FALSE;
-               *q++ = c;
-       }
-       *q = '\0';
-
-       /*
-       **  Now do a MAILB lookup.
-       */
-
-retry:
-       if (res_query(bufp, C_IN, T_MAILB, (char *) &answer, sizeof answer < 0)
-       {
-               /* no match -- just continue as usual */
-               return FALSE;
-       }
-
-       /* find first satisfactory answer */
-       hp = (HEADER *)&answer;
-       ap = (u_char *)&answer + sizeof(HEADER);
-       eom = (u_char *)&answer + n;
-       for (qdcount = ntohs(hp->qdcount); qdcount--; ap += n + QFIXEDSZ)
-               if ((n = dn_skipname(ap, eom)) < 0)
-                       return FALSE;
-       for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; ap += n)
-       {
-               n = dn_expand((u_char *)&answer, eom, ap, (u_char *)bp, buflen);
-               if (n < 0)
-                       break;
-               ap += n;
-               GETSHORT(type, ap);
-               ap += SHORTSIZE + LONGSIZE;
-               GETSHORT(n, ap);
-               switch (type)
-               {
-                 case T_MR:
-                       /* rename: try again */
-                       i = dn_expand((u_char *) &answer, eom, ap,
-                                       (u_char) abuf, sizeof abuf);
-                       if (i < 0)
-                               break;
-                       if (bufp != abuf)
-                       {
-                               free(bufp);
-                               bufp = abuf;
-                       }
-                       goto retry;
-
-                 case T_MB:
-                       i = dn_expand((u_char *) &answer, eom, ap,
-                                       (u_char) hbuf, sizeof hbuf);
-                       if (i < 0)
-                               break;
-
-                       /* hbuf now has the host to deliver to */
-                       break;
-
-                 case T_MG:
-                       i = dn_expand((u_char *) &answer, eom, ap,
-                                       (u_char) gbuf, sizeof gbuf);
-                       if (i < 0)
-                               break;
-                       AliasLevel++;
-                       naddrs += sendtolist(ubuf, a, sendq, e);
-                       AliasLevel--;
-                       break;
-
-                 case T_MINFO:
-                       /* bleach */
-                       XXX;
-               }
-
-
-
-               if (type != T_MX)
-               {
-                       if (tTd(8, 8) || _res.options & RES_DEBUG)
-                               printf("unexpected answer type %d, size %d\n",
-                                   type, n);
-                       cp += n;
-                       continue;
-               }
-               GETSHORT(pref, cp);
-               if ((n = dn_expand((u_char *)&answer, eom, cp,
-                                  (u_char *)bp, buflen)) < 0)
-                       break;
-               cp += n;
-
-
-#endif /* DNS_MAILB */
-
-#else /* not NAMED_BIND */
-
-#include <netdb.h>
-
-bool
-getcanonname(host, hbsize, trymx)
-       char *host;
-       int hbsize;
-       bool trymx;
-{
-       struct hostent *hp;
-
-       hp = gethostbyname(host);
-       if (hp == NULL)
-               return (FALSE);
-
-       if (strlen(hp->h_name) >= hbsize)
-               return (FALSE);
-
-       (void) strcpy(host, hp->h_name);
-       return (TRUE);
-}
-
-#endif /* not NAMED_BIND */
+#endif /* NAMED_BIND */