BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / sendmail / src / daemon.c
index 32fdb2a..f16ef27 100644 (file)
@@ -1,34 +1,62 @@
 /*
 /*
- * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1983, 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 <errno.h>
 #include "sendmail.h"
  */
 
 #include <errno.h>
 #include "sendmail.h"
-# include <sys/mx.h>
 
 #ifndef lint
 #ifdef DAEMON
 
 #ifndef lint
 #ifdef DAEMON
-static char sccsid[] = "@(#)daemon.c   8.24 (Berkeley) %G% (with daemon mode)";
+static char sccsid[] = "@(#)daemon.c   8.105 (Berkeley) 6/20/95 (with daemon mode)";
 #else
 #else
-static char sccsid[] = "@(#)daemon.c   8.24 (Berkeley) %G% (without daemon mode)";
+static char sccsid[] = "@(#)daemon.c   8.105 (Berkeley) 6/20/95 (without daemon mode)";
 #endif
 #endif /* not lint */
 
 #ifdef DAEMON
 
 #endif
 #endif /* not lint */
 
 #ifdef DAEMON
 
-# include <netdb.h>
-# include <sys/time.h>
 # include <arpa/inet.h>
 
 # include <arpa/inet.h>
 
-#ifdef NAMED_BIND
-# include <arpa/nameser.h>
+#if NAMED_BIND
 # include <resolv.h>
 #endif
 
 # include <resolv.h>
 #endif
 
+#if IP_SRCROUTE
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# include <netinet/ip_var.h>
+#endif
+
 /*
 **  DAEMON.C -- routines to use when running as a daemon.
 **
 /*
 **  DAEMON.C -- routines to use when running as a daemon.
 **
@@ -58,8 +86,6 @@ static char sccsid[] = "@(#)daemon.c  8.24 (Berkeley) %G% (without daemon mode)";
 **     host_map_lookup(map, hbuf, avp, pstat)
 **             Convert the entry in hbuf into a canonical form.
 */
 **     host_map_lookup(map, hbuf, avp, pstat)
 **             Convert the entry in hbuf into a canonical form.
 */
-
-static FILE    *MailPort;      /* port that mail comes in on */
 \f/*
 **  GETREQUESTS -- open mail IPC port and get requests.
 **
 \f/*
 **  GETREQUESTS -- open mail IPC port and get requests.
 **
@@ -84,14 +110,16 @@ int                ListenQueueSize = 10;           /* size of listen queue */
 int            TcpRcvBufferSize = 0;           /* size of TCP receive buffer */
 int            TcpSndBufferSize = 0;           /* size of TCP send buffer */
 
 int            TcpRcvBufferSize = 0;           /* size of TCP receive buffer */
 int            TcpSndBufferSize = 0;           /* size of TCP send buffer */
 
+void
 getrequests()
 {
        int t;
 getrequests()
 {
        int t;
-       register struct servent *sp;
-       int on = 1;
        bool refusingconnections = TRUE;
        FILE *pidf;
        int socksize;
        bool refusingconnections = TRUE;
        FILE *pidf;
        int socksize;
+#if XDEBUG
+       bool j_has_dot;
+#endif
        extern void reapchild();
 
        /*
        extern void reapchild();
 
        /*
@@ -104,13 +132,16 @@ getrequests()
                DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
        if (DaemonAddr.sin.sin_port == 0)
        {
                DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
        if (DaemonAddr.sin.sin_port == 0)
        {
+               register struct servent *sp;
+
                sp = getservbyname("smtp", "tcp");
                if (sp == NULL)
                {
                        syserr("554 service \"smtp\" unknown");
                sp = getservbyname("smtp", "tcp");
                if (sp == NULL)
                {
                        syserr("554 service \"smtp\" unknown");
-                       goto severe;
+                       DaemonAddr.sin.sin_port = htons(25);
                }
                }
-               DaemonAddr.sin.sin_port = sp->s_port;
+               else
+                       DaemonAddr.sin.sin_port = sp->s_port;
        }
 
        /*
        }
 
        /*
@@ -121,90 +152,467 @@ getrequests()
                printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
 
        /* get a socket for the SMTP connection */
                printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
 
        /* get a socket for the SMTP connection */
-       DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
-       if (DaemonSocket < 0)
+       socksize = opendaemonsocket(TRUE);
+
+       (void) setsignal(SIGCHLD, reapchild);
+
+       /* write the pid to the log file for posterity */
+       pidf = fopen(PidFile, "w");
+       if (pidf != NULL)
        {
        {
-               /* probably another daemon already */
-               syserr("getrequests: can't create socket");
-         severe:
-# ifdef LOG
-               if (LogLevel > 0)
-# endif /* LOG */
-               finis();
-       }
+               extern char *CommandLineArgs;
 
 
-       /* turn on network debugging? */
-       if (tTd(15, 101))
-               (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
+               /* write the process id on line 1 */
+               fprintf(pidf, "%d\n", getpid());
 
 
-       (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
-       (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on);
+               /* line 2 contains all command line flags */
+               fprintf(pidf, "%s\n", CommandLineArgs);
 
 
-#ifdef SO_RCVBUF
-       if (TcpRcvBufferSize > 0)
+               /* flush and close */
+               fclose(pidf);
+       }
+
+#if XDEBUG
        {
        {
-               if (setsockopt(DaemonSocket, SOL_SOCKET, SO_RCVBUF,
-                              (char *) &TcpRcvBufferSize,
-                              sizeof(TcpRcvBufferSize)) < 0)
-                       syserr("getrequests: setsockopt(SO_RCVBUF)");
+               char jbuf[MAXHOSTNAMELEN];
+
+               expand("\201j", jbuf, sizeof jbuf, CurEnv);
+               j_has_dot = strchr(jbuf, '.') != NULL;
        }
 #endif
 
        }
 #endif
 
-       switch (DaemonAddr.sa.sa_family)
+       if (tTd(15, 1))
+               printf("getrequests: %d\n", DaemonSocket);
+
+       for (;;)
        {
        {
-# ifdef NETINET
-         case AF_INET:
-               socksize = sizeof DaemonAddr.sin;
-               break;
-# endif
+               register int pid;
+               auto int lotherend;
+               extern bool refuseconnections();
+               extern int getla();
+
+               /* see if we are rejecting connections */
+               CurrentLA = getla();
+               if (refuseconnections())
+               {
+                       if (DaemonSocket >= 0)
+                       {
+                               /* close socket so peer will fail quickly */
+                               (void) close(DaemonSocket);
+                               DaemonSocket = -1;
+                       }
+                       refusingconnections = TRUE;
+                       sleep(15);
+                       continue;
+               }
 
 
-# ifdef NETISO
-         case AF_ISO:
-               socksize = sizeof DaemonAddr.siso;
-               break;
-# endif
+               /* arrange to (re)open the socket if necessary */
+               if (refusingconnections)
+               {
+                       (void) opendaemonsocket(FALSE);
+                       refusingconnections = FALSE;
+               }
 
 
-         default:
-               socksize = sizeof DaemonAddr;
-               break;
+#if XDEBUG
+               /* check for disaster */
+               {
+                       char jbuf[MAXHOSTNAMELEN];
+
+                       expand("\201j", jbuf, sizeof jbuf, CurEnv);
+                       if (!wordinclass(jbuf, 'w'))
+                       {
+                               dumpstate("daemon lost $j");
+                               syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog");
+                               abort();
+                       }
+                       else if (j_has_dot && strchr(jbuf, '.') == NULL)
+                       {
+                               dumpstate("daemon $j lost dot");
+                               syslog(LOG_ALERT, "daemon process $j lost dot; see syslog");
+                               abort();
+                       }
+               }
+#endif
+
+               /* wait for a connection */
+               setproctitle("accepting connections");
+               do
+               {
+                       errno = 0;
+                       lotherend = socksize;
+                       t = accept(DaemonSocket,
+                           (struct sockaddr *)&RealHostAddr, &lotherend);
+               } while (t < 0 && errno == EINTR);
+               if (t < 0)
+               {
+                       syserr("getrequests: accept");
+
+                       /* arrange to re-open the socket next time around */
+                       (void) close(DaemonSocket);
+                       DaemonSocket = -1;
+                       sleep(5);
+                       continue;
+               }
+
+               /*
+               **  Create a subprocess to process the mail.
+               */
+
+               if (tTd(15, 2))
+                       printf("getrequests: forking (fd = %d)\n", t);
+
+               pid = fork();
+               if (pid < 0)
+               {
+                       syserr("daemon: cannot fork");
+                       sleep(10);
+                       (void) close(t);
+                       continue;
+               }
+
+               if (pid == 0)
+               {
+                       char *p;
+                       extern char *hostnamebyanyaddr();
+                       extern void intsig();
+
+                       /*
+                       **  CHILD -- return to caller.
+                       **      Collect verified idea of sending host.
+                       **      Verify calling user id if possible here.
+                       */
+
+                       (void) setsignal(SIGCHLD, SIG_DFL);
+                       (void) setsignal(SIGHUP, intsig);
+                       (void) close(DaemonSocket);
+                       DisConnected = FALSE;
+
+                       setproctitle("startup with %s",
+                               anynet_ntoa(&RealHostAddr));
+
+                       /* determine host name */
+                       p = hostnamebyanyaddr(&RealHostAddr);
+                       if (strlen(p) > MAXNAME)
+                               p[MAXNAME] = '\0';
+                       RealHostName = newstr(p);
+                       setproctitle("startup with %s", p);
+
+                       if ((InChannel = fdopen(t, "r")) == NULL ||
+                           (t = dup(t)) < 0 ||
+                           (OutChannel = fdopen(t, "w")) == NULL)
+                       {
+                               syserr("cannot open SMTP server channel, fd=%d", t);
+                               exit(0);
+                       }
+
+                       /* should we check for illegal connection here? XXX */
+#ifdef XLA
+                       if (!xla_host_ok(RealHostName))
+                       {
+                               message("421 Too many SMTP sessions for this host");
+                               exit(0);
+                       }
+#endif
+
+                       if (tTd(15, 2))
+                               printf("getreq: returning\n");
+                       return;
+               }
+
+               CurChildren++;
+
+               /* close the port so that others will hang (for a while) */
+               (void) close(t);
        }
        }
+       /*NOTREACHED*/
+}
+\f/*
+**  OPENDAEMONSOCKET -- open the SMTP socket
+**
+**     Deals with setting all appropriate options.  DaemonAddr must
+**     be set up in advance.
+**
+**     Parameters:
+**             firsttime -- set if this is the initial open.
+**
+**     Returns:
+**             Size in bytes of the daemon socket addr.
+**
+**     Side Effects:
+**             Leaves DaemonSocket set to the open socket.
+**             Exits if the socket cannot be created.
+*/
+
+#define MAXOPENTRIES   10      /* maximum number of tries to open connection */
 
 
-       if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0)
+int
+opendaemonsocket(firsttime)
+       bool firsttime;
+{
+       int on = 1;
+       int socksize = 0;
+       int ntries = 0;
+       int saveerrno;
+
+       if (tTd(15, 2))
+               printf("opendaemonsocket()\n");
+
+       do
        {
        {
-               syserr("getrequests: cannot bind");
+               if (ntries > 0)
+                       sleep(5);
+               if (firsttime || DaemonSocket < 0)
+               {
+                       DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
+                       if (DaemonSocket < 0)
+                       {
+                               /* probably another daemon already */
+                               saveerrno = errno;
+                               syserr("opendaemonsocket: can't create server SMTP socket");
+                         severe:
+# ifdef LOG
+                               if (LogLevel > 0)
+                                       syslog(LOG_ALERT, "problem creating SMTP socket");
+# endif /* LOG */
+                               DaemonSocket = -1;
+                               continue;
+                       }
+
+                       /* turn on network debugging? */
+                       if (tTd(15, 101))
+                               (void) setsockopt(DaemonSocket, SOL_SOCKET,
+                                                 SO_DEBUG, (char *)&on,
+                                                 sizeof on);
+
+                       (void) setsockopt(DaemonSocket, SOL_SOCKET,
+                                         SO_REUSEADDR, (char *)&on, sizeof on);
+                       (void) setsockopt(DaemonSocket, SOL_SOCKET,
+                                         SO_KEEPALIVE, (char *)&on, sizeof on);
+
+#ifdef SO_RCVBUF
+                       if (TcpRcvBufferSize > 0)
+                       {
+                               if (setsockopt(DaemonSocket, SOL_SOCKET,
+                                              SO_RCVBUF,
+                                              (char *) &TcpRcvBufferSize,
+                                              sizeof(TcpRcvBufferSize)) < 0)
+                                       syserr("getrequests: setsockopt(SO_RCVBUF)");
+                       }
+#endif
+
+                       switch (DaemonAddr.sa.sa_family)
+                       {
+# if NETINET
+                         case AF_INET:
+                               socksize = sizeof DaemonAddr.sin;
+                               break;
+# endif
+
+# if NETISO
+                         case AF_ISO:
+                               socksize = sizeof DaemonAddr.siso;
+                               break;
+# endif
+
+                         default:
+                               socksize = sizeof DaemonAddr;
+                               break;
+                       }
+
+                       if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0)
+                       {
+                               saveerrno = errno;
+                               syserr("getrequests: cannot bind");
+                               (void) close(DaemonSocket);
+                               goto severe;
+                       }
+               }
+               if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0)
+               {
+                       saveerrno = errno;
+                       syserr("getrequests: cannot listen");
+                       (void) close(DaemonSocket);
+                       goto severe;
+               }
+               return socksize;
+       } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
+       syserr("!opendaemonsocket: server SMTP socket wedged: exiting");
+       finis();
+}
+\f/*
+**  CLRDAEMON -- reset the daemon connection
+**
+**     Parameters:
+**             none.
+**
+**     Returns:
+**             none.
+**
+**     Side Effects:
+**             releases any resources used by the passive daemon.
+*/
+
+void
+clrdaemon()
+{
+       if (DaemonSocket >= 0)
                (void) close(DaemonSocket);
                (void) close(DaemonSocket);
-               goto severe;
-       }
+       DaemonSocket = -1;
+}
+\f/*
+**  SETDAEMONOPTIONS -- set options for running the daemon
+**
+**     Parameters:
+**             p -- the options line.
+**
+**     Returns:
+**             none.
+*/
 
 
-       (void) setsignal(SIGCHLD, reapchild);
+void
+setdaemonoptions(p)
+       register char *p;
+{
+       if (DaemonAddr.sa.sa_family == AF_UNSPEC)
+               DaemonAddr.sa.sa_family = AF_INET;
 
 
-       /* write the pid to the log file for posterity */
-       pidf = fopen(PidFile, "w");
-       if (pidf != NULL)
+       while (p != NULL)
        {
        {
-               extern char *CommandLineArgs;
+               register char *f;
+               register char *v;
 
 
-               /* write the process id on line 1 */
-               fprintf(pidf, "%d\n", getpid());
+               while (isascii(*p) && isspace(*p))
+                       p++;
+               if (*p == '\0')
+                       break;
+               f = p;
+               p = strchr(p, ',');
+               if (p != NULL)
+                       *p++ = '\0';
+               v = strchr(f, '=');
+               if (v == NULL)
+                       continue;
+               while (isascii(*++v) && isspace(*v))
+                       continue;
+               if (isascii(*f) && isupper(*f))
+                       *f = tolower(*f);
 
 
-               /* line 2 contains all command line flags */
-               fprintf(pidf, "%s\n", CommandLineArgs);
+               switch (*f)
+               {
+                 case 'F':             /* address family */
+                       if (isascii(*v) && isdigit(*v))
+                               DaemonAddr.sa.sa_family = atoi(v);
+#if NETINET
+                       else if (strcasecmp(v, "inet") == 0)
+                               DaemonAddr.sa.sa_family = AF_INET;
+#endif
+#if NETISO
+                       else if (strcasecmp(v, "iso") == 0)
+                               DaemonAddr.sa.sa_family = AF_ISO;
+#endif
+#if NETNS
+                       else if (strcasecmp(v, "ns") == 0)
+                               DaemonAddr.sa.sa_family = AF_NS;
+#endif
+#if NETX25
+                       else if (strcasecmp(v, "x.25") == 0)
+                               DaemonAddr.sa.sa_family = AF_CCITT;
+#endif
+                       else
+                               syserr("554 Unknown address family %s in Family=option", v);
+                       break;
 
 
-               /* flush and close */
-               fclose(pidf);
-       }
+                 case 'A':             /* address */
+                       switch (DaemonAddr.sa.sa_family)
+                       {
+#if NETINET
+                         case AF_INET:
+                               if (isascii(*v) && isdigit(*v))
+                                       DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v));
+                               else
+                               {
+                                       register struct netent *np;
 
 
+                                       np = getnetbyname(v);
+                                       if (np == NULL)
+                                               syserr("554 network \"%s\" unknown", v);
+                                       else
+                                               DaemonAddr.sin.sin_addr.s_addr = np->n_net;
+                               }
+                               break;
+#endif
 
 
-       if (tTd(15, 1))
-               printf("getrequests: %d\n", DaemonSocket);
+                         default:
+                               syserr("554 Address= option unsupported for family %d",
+                                       DaemonAddr.sa.sa_family);
+                               break;
+                       }
+                       break;
+
+                 case 'P':             /* port */
+                       switch (DaemonAddr.sa.sa_family)
+                       {
+                               short port;
+
+#if NETINET
+                         case AF_INET:
+                               if (isascii(*v) && isdigit(*v))
+                                       DaemonAddr.sin.sin_port = htons(atoi(v));
+                               else
+                               {
+                                       register struct servent *sp;
+
+                                       sp = getservbyname(v, "tcp");
+                                       if (sp == NULL)
+                                               syserr("554 service \"%s\" unknown", v);
+                                       else
+                                               DaemonAddr.sin.sin_port = sp->s_port;
+                               }
+                               break;
+#endif
+
+#if NETISO
+                         case AF_ISO:
+                               /* assume two byte transport selector */
+                               if (isascii(*v) && isdigit(*v))
+                                       port = htons(atoi(v));
+                               else
+                               {
+                                       register struct servent *sp;
+
+                                       sp = getservbyname(v, "tcp");
+                                       if (sp == NULL)
+                                               syserr("554 service \"%s\" unknown", v);
+                                       else
+                                               port = sp->s_port;
+                               }
+                               bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
+                               break;
+#endif
+
+                         default:
+                               syserr("554 Port= option unsupported for family %d",
+                                       DaemonAddr.sa.sa_family);
+                               break;
+                       }
+                       break;
+
+                 case 'L':             /* listen queue size */
+                       ListenQueueSize = atoi(v);
+                       break;
+
+                 case 'S':             /* send buffer size */
+                       TcpSndBufferSize = atoi(v);
+                       break;
 
 
-       struct wh wbuf;
+                 case 'R':             /* receive buffer size */
+                       TcpRcvBufferSize = atoi(v);
+                       break;
 
 
-       wbuf.index = index;
-       wbuf.count = 0;
-       wbuf.ccount = cnt;
-       wbuf.data = buf;
-       write(MailPort, &wbuf, sizeof wbuf);
+                 default:
+                       syserr("554 DaemonPortOptions parameter \"%s\" unknown", f);
+               }
+       }
 }
 \f/*
 **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
 }
 \f/*
 **  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
@@ -234,21 +642,20 @@ makeconnection(host, port, mci, usesecureport)
        register MCI *mci;
        bool usesecureport;
 {
        register MCI *mci;
        bool usesecureport;
 {
-       register int i, s;
+       register int i = 0;
+       register int s;
        register struct hostent *hp = (struct hostent *)NULL;
        SOCKADDR addr;
        int sav_errno;
        int addrlen;
        register struct hostent *hp = (struct hostent *)NULL;
        SOCKADDR addr;
        int sav_errno;
        int addrlen;
-#ifdef NAMED_BIND
-       extern int h_errno;
-#endif
+       bool firstconnect;
 
        /*
        **  Set up the address for the mailer.
        **      Accept "[a.b.c.d]" syntax for host name.
        */
 
 
        /*
        **  Set up the address for the mailer.
        **      Accept "[a.b.c.d]" syntax for host name.
        */
 
-#ifdef NAMED_BIND
+#if NAMED_BIND
        h_errno = 0;
 #endif
        errno = 0;
        h_errno = 0;
 #endif
        errno = 0;
@@ -264,13 +671,27 @@ makeconnection(host, port, mci, usesecureport)
                if (p != NULL)
                {
                        *p = '\0';
                if (p != NULL)
                {
                        *p = '\0';
-#ifdef NETINET
+#if NETINET
                        hid = inet_addr(&host[1]);
                        if (hid == -1)
 #endif
                        {
                                /* try it as a host name (avoid MX lookup) */
                        hid = inet_addr(&host[1]);
                        if (hid == -1)
 #endif
                        {
                                /* try it as a host name (avoid MX lookup) */
-                               hp = gethostbyname(&host[1]);
+                               hp = sm_gethostbyname(&host[1]);
+                               if (hp == NULL && p[-1] == '.')
+                               {
+#if NAMED_BIND
+                                       int oldopts = _res.options;
+
+                                       _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
+#endif
+                                       p[-1] = '\0';
+                                       hp = sm_gethostbyname(&host[1]);
+                                       p[-1] = '.';
+#if NAMED_BIND
+                                       _res.options = oldopts;
+#endif
+                               }
                                *p = ']';
                                goto gothostent;
                        }
                                *p = ']';
                                goto gothostent;
                        }
@@ -279,37 +700,55 @@ makeconnection(host, port, mci, usesecureport)
                if (p == NULL)
                {
                        usrerr("553 Invalid numeric domain spec \"%s\"", host);
                if (p == NULL)
                {
                        usrerr("553 Invalid numeric domain spec \"%s\"", host);
+                       mci->mci_status = "5.1.2";
                        return (EX_NOHOST);
                }
                        return (EX_NOHOST);
                }
-#ifdef NETINET
+#if NETINET
                addr.sin.sin_family = AF_INET;          /*XXX*/
                addr.sin.sin_addr.s_addr = hid;
 #endif
        }
        else
        {
                addr.sin.sin_family = AF_INET;          /*XXX*/
                addr.sin.sin_addr.s_addr = hid;
 #endif
        }
        else
        {
-               hp = gethostbyname(host);
+               register char *p = &host[strlen(host) - 1];
+
+               hp = sm_gethostbyname(host);
+               if (hp == NULL && *p == '.')
+               {
+#if NAMED_BIND
+                       int oldopts = _res.options;
+
+                       _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
+#endif
+                       *p = '\0';
+                       hp = sm_gethostbyname(host);
+                       *p = '.';
+#if NAMED_BIND
+                       _res.options = oldopts;
+#endif
+               }
 gothostent:
                if (hp == NULL)
                {
 gothostent:
                if (hp == NULL)
                {
-#ifdef NAMED_BIND
-                       if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
-                               return (EX_TEMPFAIL);
-
-                       /* if name server is specified, assume temp fail */
-                       if (errno == ECONNREFUSED && UseNameServer)
+#if NAMED_BIND
+                       /* check for name server timeouts */
+                       if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
+                           (errno == ECONNREFUSED && UseNameServer))
+                       {
+                               mci->mci_status = "4.4.3";
                                return (EX_TEMPFAIL);
                                return (EX_TEMPFAIL);
+                       }
 #endif
                        return (EX_NOHOST);
                }
                addr.sa.sa_family = hp->h_addrtype;
                switch (hp->h_addrtype)
                {
 #endif
                        return (EX_NOHOST);
                }
                addr.sa.sa_family = hp->h_addrtype;
                switch (hp->h_addrtype)
                {
-#ifdef NETINET
+#if NETINET
                  case AF_INET:
                        bcopy(hp->h_addr,
                                &addr.sin.sin_addr,
                  case AF_INET:
                        bcopy(hp->h_addr,
                                &addr.sin.sin_addr,
-                               hp->h_length);
+                               INADDRSZ);
                        break;
 #endif
 
                        break;
 #endif
 
@@ -326,30 +765,32 @@ gothostent:
        **  Determine the port number.
        */
 
        **  Determine the port number.
        */
 
-       if (port != 0)
-               port = htons(port);
-       else
+       if (port == 0)
        {
                register struct servent *sp = getservbyname("smtp", "tcp");
 
                if (sp == NULL)
                {
        {
                register struct servent *sp = getservbyname("smtp", "tcp");
 
                if (sp == NULL)
                {
-                       syserr("554 makeconnection: service \"smtp\" unknown");
-                       return (EX_OSERR);
+#ifdef LOG
+                       if (LogLevel > 2)
+                               syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown");
+#endif
+                       port = htons(25);
                }
                }
-               port = sp->s_port;
+               else
+                       port = sp->s_port;
        }
 
        switch (addr.sa.sa_family)
        {
        }
 
        switch (addr.sa.sa_family)
        {
-#ifdef NETINET
+#if NETINET
          case AF_INET:
                addr.sin.sin_port = port;
                addrlen = sizeof (struct sockaddr_in);
                break;
 #endif
 
          case AF_INET:
                addr.sin.sin_port = port;
                addrlen = sizeof (struct sockaddr_in);
                break;
 #endif
 
-#ifdef NETISO
+#if NETISO
          case AF_ISO:
                /* assume two byte transport selector */
                bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
          case AF_ISO:
                /* assume two byte transport selector */
                bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
@@ -372,6 +813,7 @@ gothostent:
                return EX_TEMPFAIL;
 #endif
 
                return EX_TEMPFAIL;
 #endif
 
+       firstconnect = TRUE;
        for (;;)
        {
                if (tTd(16, 1))
        for (;;)
        {
                if (tTd(16, 1))
@@ -394,7 +836,7 @@ gothostent:
                if (s < 0)
                {
                        sav_errno = errno;
                if (s < 0)
                {
                        sav_errno = errno;
-                       syserr("makeconnection: no socket");
+                       syserr("makeconnection: cannot create socket");
                        goto failure;
                }
 
                        goto failure;
                }
 
@@ -415,7 +857,7 @@ gothostent:
                if (tTd(16, 101))
                {
                        int on = 1;
                if (tTd(16, 101))
                {
                        int on = 1;
-                       (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG,
+                       (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
                                          (char *)&on, sizeof on);
                }
                if (CurEnv->e_xfp != NULL)
                                          (char *)&on, sizeof on);
                }
                if (CurEnv->e_xfp != NULL)
@@ -424,21 +866,32 @@ gothostent:
                if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
                        break;
 
                if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
                        break;
 
+               /* if running demand-dialed connection, try again */
+               if (DialDelay > 0 && firstconnect)
+               {
+                       if (tTd(16, 1))
+                               printf("Connect failed (%s); trying again...\n",
+                                       errstring(sav_errno));
+                       firstconnect = FALSE;
+                       sleep(DialDelay);
+                       continue;
+               }
+
                /* couldn't connect.... figure out why */
                sav_errno = errno;
                (void) close(s);
                /* couldn't connect.... figure out why */
                sav_errno = errno;
                (void) close(s);
-               if (hp && hp->h_addr_list[i])
+               if (hp != NULL && hp->h_addr_list[i])
                {
                        if (tTd(16, 1))
                                printf("Connect failed (%s); trying new address....\n",
                                        errstring(sav_errno));
                        switch (addr.sa.sa_family)
                        {
                {
                        if (tTd(16, 1))
                                printf("Connect failed (%s); trying new address....\n",
                                        errstring(sav_errno));
                        switch (addr.sa.sa_family)
                        {
-#ifdef NETINET
+#if NETINET
                          case AF_INET:
                                bcopy(hp->h_addr_list[i++],
                                      &addr.sin.sin_addr,
                          case AF_INET:
                                bcopy(hp->h_addr_list[i++],
                                      &addr.sin.sin_addr,
-                                     hp->h_length);
+                                     INADDRSZ);
                                break;
 #endif
 
                                break;
 #endif
 
@@ -490,42 +943,65 @@ gothostent:
 **             Adds numeric codes to $=w.
 */
 
 **             Adds numeric codes to $=w.
 */
 
-char **
+struct hostent *
 myhostname(hostbuf, size)
        char hostbuf[];
        int size;
 {
        register struct hostent *hp;
 myhostname(hostbuf, size)
        char hostbuf[];
        int size;
 {
        register struct hostent *hp;
-       extern struct hostent *gethostbyname();
+       extern bool getcanonname();
 
        if (gethostname(hostbuf, size) < 0)
        {
                (void) strcpy(hostbuf, "localhost");
        }
 
        if (gethostname(hostbuf, size) < 0)
        {
                (void) strcpy(hostbuf, "localhost");
        }
-       hp = gethostbyname(hostbuf);
-       if (hp != NULL)
+       hp = sm_gethostbyname(hostbuf);
+       if (hp == NULL)
+               return NULL;
+       if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
        {
                (void) strncpy(hostbuf, hp->h_name, size - 1);
                hostbuf[size - 1] = '\0';
        {
                (void) strncpy(hostbuf, hp->h_name, size - 1);
                hostbuf[size - 1] = '\0';
+       }
 
 
-               if (hp->h_addrtype == AF_INET && hp->h_length == 4)
-               {
-                       register int i;
+       /*
+       **  If there is still no dot in the name, try looking for a
+       **  dotted alias.
+       */
 
 
-                       for (i = 0; hp->h_addr_list[i] != NULL; i++)
-                       {
-                               char ipbuf[100];
+       if (strchr(hostbuf, '.') == NULL)
+       {
+               char **ha;
 
 
-                               sprintf(ipbuf, "[%s]",
-                                       inet_ntoa(*((struct in_addr *) hp->h_addr_list[i])));
-                               setclass('w', ipbuf);
+               for (ha = hp->h_aliases; *ha != NULL; ha++)
+               {
+                       if (strchr(*ha, '.') != NULL)
+                       {
+                               (void) strncpy(hostbuf, *ha, size - 1);
+                               hostbuf[size - 1] = '\0';
+                               break;
                        }
                }
                        }
                }
+       }
 
 
-               return (hp->h_aliases);
+       /*
+       **  If _still_ no dot, wait for a while and try again -- it is
+       **  possible that some service is starting up.  This can result
+       **  in excessive delays if the system is badly configured, but
+       **  there really isn't a way around that, particularly given that
+       **  the config file hasn't been read at this point.
+       **  All in all, a bit of a mess.
+       */
+
+       if (strchr(hostbuf, '.') == NULL &&
+           !getcanonname(hostbuf, size, TRUE))
+       {
+               message("My unqualifed host name (%s) unknown; sleeping for retry",
+                       hostbuf);
+               sleep(60);
+               (void) getcanonname(hostbuf, size, TRUE);
        }
        }
-       else
-               return (NULL);
+       return (hp);
 }
 \f/*
 **  GETAUTHINFO -- get the real host name asociated with a file descriptor
 }
 \f/*
 **  GETAUTHINFO -- get the real host name asociated with a file descriptor
@@ -537,60 +1013,54 @@ myhostname(hostbuf, size)
 **
 **     Returns:
 **             The user@host information associated with this descriptor.
 **
 **     Returns:
 **             The user@host information associated with this descriptor.
-**
-**     Side Effects:
-**             Sets RealHostName to the name of the host at the other end.
 */
 
 */
 
-#ifdef IDENTPROTO
-
 static jmp_buf CtxAuthTimeout;
 
 static jmp_buf CtxAuthTimeout;
 
-static
+static void
 authtimeout()
 {
        longjmp(CtxAuthTimeout, 1);
 }
 
 authtimeout()
 {
        longjmp(CtxAuthTimeout, 1);
 }
 
-#endif
-
 char *
 getauthinfo(fd)
        int fd;
 {
 char *
 getauthinfo(fd)
        int fd;
 {
-       SOCKADDR fa;
        int falen;
        register char *p;
        int falen;
        register char *p;
-#ifdef IDENTPROTO
        SOCKADDR la;
        int lalen;
        register struct servent *sp;
        int s;
        int i;
        EVENT *ev;
        SOCKADDR la;
        int lalen;
        register struct servent *sp;
        int s;
        int i;
        EVENT *ev;
-#endif
+       int nleft;
+       char ibuf[MAXNAME + 1];
        static char hbuf[MAXNAME * 2 + 2];
        extern char *hostnamebyanyaddr();
        static char hbuf[MAXNAME * 2 + 2];
        extern char *hostnamebyanyaddr();
-       extern char RealUserName[];                     /* main.c */
 
 
-       falen = sizeof fa;
-       if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0 ||
-           fa.sa.sa_family == 0)
+       falen = sizeof RealHostAddr;
+       if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 ||
+           falen <= 0 || RealHostAddr.sa.sa_family == 0)
        {
        {
-               RealHostName = "localhost";
                (void) sprintf(hbuf, "%s@localhost", RealUserName);
                if (tTd(9, 1))
                        printf("getauthinfo: %s\n", hbuf);
                return hbuf;
        }
 
                (void) sprintf(hbuf, "%s@localhost", RealUserName);
                if (tTd(9, 1))
                        printf("getauthinfo: %s\n", hbuf);
                return hbuf;
        }
 
-       p = hostnamebyanyaddr(&fa);
-       RealHostName = newstr(p);
-       RealHostAddr = fa;
+       if (RealHostName == NULL)
+       {
+               /* translate that to a host name */
+               RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
+       }
+
+       if (TimeOuts.to_ident == 0)
+               goto noident;
 
 
-#ifdef IDENTPROTO
        lalen = sizeof la;
        lalen = sizeof la;
-       if (fa.sa.sa_family != AF_INET ||
+       if (RealHostAddr.sa.sa_family != AF_INET ||
            getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
            la.sa.sa_family != AF_INET)
        {
            getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
            la.sa.sa_family != AF_INET)
        {
@@ -599,8 +1069,8 @@ getauthinfo(fd)
        }
 
        /* create ident query */
        }
 
        /* create ident query */
-       (void) sprintf(hbuf, "%d,%d\r\n",
-               ntohs(fa.sin.sin_port), ntohs(la.sin.sin_port));
+       (void) sprintf(ibuf, "%d,%d\r\n",
+               ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
 
        /* create local address */
        la.sin.sin_port = 0;
 
        /* create local address */
        la.sin.sin_port = 0;
@@ -608,9 +1078,9 @@ getauthinfo(fd)
        /* create foreign address */
        sp = getservbyname("auth", "tcp");
        if (sp != NULL)
        /* create foreign address */
        sp = getservbyname("auth", "tcp");
        if (sp != NULL)
-               fa.sin.sin_port = sp->s_port;
+               RealHostAddr.sin.sin_port = sp->s_port;
        else
        else
-               fa.sin.sin_port = htons(113);
+               RealHostAddr.sin.sin_port = htons(113);
 
        s = -1;
        if (setjmp(CtxAuthTimeout) != 0)
 
        s = -1;
        if (setjmp(CtxAuthTimeout) != 0)
@@ -631,36 +1101,40 @@ getauthinfo(fd)
                goto noident;
        }
        if (bind(s, &la.sa, sizeof la.sin) < 0 ||
                goto noident;
        }
        if (bind(s, &la.sa, sizeof la.sin) < 0 ||
-           connect(s, &fa.sa, sizeof fa.sin) < 0)
+           connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0)
        {
        {
-closeident:
-               (void) close(s);
-               clrevent(ev);
-               goto noident;
+               goto closeident;
        }
 
        if (tTd(9, 10))
        }
 
        if (tTd(9, 10))
-               printf("getauthinfo: sent %s", hbuf);
+               printf("getauthinfo: sent %s", ibuf);
 
        /* send query */
 
        /* send query */
-       if (write(s, hbuf, strlen(hbuf)) < 0)
+       if (write(s, ibuf, strlen(ibuf)) < 0)
                goto closeident;
 
        /* get result */
                goto closeident;
 
        /* get result */
-       i = read(s, hbuf, sizeof hbuf);
+       p = &ibuf[0];
+       nleft = sizeof ibuf - 1;
+       while ((i = read(s, p, nleft)) > 0)
+       {
+               p += i;
+               nleft -= i;
+       }
        (void) close(s);
        clrevent(ev);
        (void) close(s);
        clrevent(ev);
-       if (i <= 0)
+       if (i < 0 || p == &ibuf[0])
                goto noident;
                goto noident;
-       if (hbuf[--i] == '\n' && hbuf[--i] == '\r')
-               i--;
-       hbuf[++i] = '\0';
+
+       if (*--p == '\n' && *--p == '\r')
+               p--;
+       *++p = '\0';
 
        if (tTd(9, 3))
 
        if (tTd(9, 3))
-               printf("getauthinfo:  got %s\n", hbuf);
+               printf("getauthinfo:  got %s\n", ibuf);
 
        /* parse result */
 
        /* parse result */
-       p = strchr(hbuf, ':');
+       p = strchr(ibuf, ':');
        if (p == NULL)
        {
                /* malformed response */
        if (p == NULL)
        {
                /* malformed response */
@@ -683,6 +1157,14 @@ closeident:
        }
 
        /* p now points to the OSTYPE field */
        }
 
        /* p now points to the OSTYPE field */
+       while (isascii(*p) && isspace(*p))
+               p++;
+       if (strncasecmp(p, "other", 5) == 0 &&
+           (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0'))
+       {
+               /* not useful information */
+               goto noident;
+       }
        p = strchr(p, ':');
        if (p == NULL)
        {
        p = strchr(p, ':');
        if (p == NULL)
        {
@@ -694,21 +1176,112 @@ closeident:
        while (isascii(*++p) && isspace(*p))
                continue;
 
        while (isascii(*++p) && isspace(*p))
                continue;
 
-       /* p now points to the authenticated name */
-       (void) sprintf(hbuf, "%s@%s", p, RealHostName);
-       goto finish;
+       /* p now points to the authenticated name -- copy carefully */
+       cleanstrcpy(hbuf, p, MAXNAME);
+       i = strlen(hbuf);
+       hbuf[i++] = '@';
+       strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName);
+       goto postident;
 
 
-#endif /* IDENTPROTO */
+closeident:
+       (void) close(s);
+       clrevent(ev);
 
 noident:
 
 noident:
+       if (RealHostName == NULL)
+       {
+               if (tTd(9, 1))
+                       printf("getauthinfo: NULL\n");
+               return NULL;
+       }
        (void) strcpy(hbuf, RealHostName);
 
        (void) strcpy(hbuf, RealHostName);
 
-finish:
-       if (RealHostName[0] != '[')
+postident:
+#if IP_SRCROUTE
+       /*
+       **  Extract IP source routing information.
+       **
+       **      Format of output for a connection from site a through b
+       **      through c to d:
+       **              loose:      @site-c@site-b:site-a
+       **              strict:    !@site-c@site-b:site-a
+       **
+       **      o - pointer within ipopt_list structure.
+       **      q - pointer within ls/ss rr route data
+       **      p - pointer to hbuf
+       */
+
+       if (RealHostAddr.sa.sa_family == AF_INET)
+       {
+               int ipoptlen, j;
+               u_char *q;
+               u_char *o;
+               struct in_addr addr;
+               struct ipoption ipopt;
+
+               ipoptlen = sizeof ipopt;
+               if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
+                              (char *) &ipopt, &ipoptlen) < 0)
+                       goto noipsr;
+               if (ipoptlen == 0)
+                       goto noipsr;
+               o = (u_char *) ipopt.ipopt_list;
+               while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
+               {
+                       switch (*o)
+                       {
+                         case IPOPT_EOL: 
+                               o = NULL;
+                               break;
+
+                         case IPOPT_NOP:
+                               o++;
+                               break;
+
+                         case IPOPT_SSRR:
+                         case IPOPT_LSRR:
+                               p = &hbuf[strlen(hbuf)];
+                               sprintf(p, " [%s@%s",
+                                   *o == IPOPT_SSRR ? "!" : "",
+                                   inet_ntoa(ipopt.ipopt_dst));
+                               p += strlen(p);
+
+                               /* o[1] is option length */
+                               j = *++o / sizeof(struct in_addr) - 1;
+
+                               /* q skips length and router pointer to data */
+                               q = o + 2;
+                               for ( ; j >= 0; j--)
+                               {
+                                       memcpy(&addr, q, sizeof(addr));
+                                       sprintf(p, "%c%s",
+                                                    j ? '@' : ':',
+                                                    inet_ntoa(addr));
+                                       p += strlen(p);
+                                       q += sizeof(struct in_addr); 
+                               }
+                               o += *o;
+                               break;
+
+                         default:
+                               /* Skip over option */
+                               o += o[1];
+                               break;
+                       }
+               }
+               strcat(hbuf,"]");
+               goto postipsr;
+       }
+#endif
+
+noipsr:
+       if (RealHostName != NULL && RealHostName[0] != '[')
        {
                p = &hbuf[strlen(hbuf)];
                (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr));
        }
        {
                p = &hbuf[strlen(hbuf)];
                (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr));
        }
+
+postipsr:
        if (tTd(9, 1))
                printf("getauthinfo: %s\n", hbuf);
        return hbuf;
        if (tTd(9, 1))
                printf("getauthinfo: %s\n", hbuf);
        return hbuf;
@@ -742,14 +1315,10 @@ host_map_lookup(map, name, av, statp)
        int *statp;
 {
        register struct hostent *hp;
        int *statp;
 {
        register struct hostent *hp;
-       u_long in_addr;
+       struct in_addr in_addr;
        char *cp;
        char *cp;
-       int i;
        register STAB *s;
        register STAB *s;
-       char *timeoutmsg = "Recipient domain nameserver timed out";
-       char hbuf[MAXNAME];
-       extern struct hostent *gethostbyaddr();
-       extern int h_errno;
+       char hbuf[MAXNAME + 1];
 
        /*
        **  See if we have already looked up this name.  If so, just
 
        /*
        **  See if we have already looked up this name.  If so, just
@@ -761,12 +1330,21 @@ host_map_lookup(map, name, av, statp)
        {
                if (tTd(9, 1))
                        printf("host_map_lookup(%s) => CACHE %s\n",
        {
                if (tTd(9, 1))
                        printf("host_map_lookup(%s) => CACHE %s\n",
-                               name, s->s_namecanon.nc_cname);
+                              name,
+                              s->s_namecanon.nc_cname == NULL
+                                       ? "NULL"
+                                       : s->s_namecanon.nc_cname);
                errno = s->s_namecanon.nc_errno;
                errno = s->s_namecanon.nc_errno;
+#if NAMED_BIND
                h_errno = s->s_namecanon.nc_herrno;
                h_errno = s->s_namecanon.nc_herrno;
+#endif
                *statp = s->s_namecanon.nc_stat;
                *statp = s->s_namecanon.nc_stat;
-               if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL)
-                       CurEnv->e_message = newstr(timeoutmsg);
+               if (*statp == EX_TEMPFAIL)
+               {
+                       CurEnv->e_status = "4.4.3";
+                       usrerr("451 %s: Name server timeout",
+                               shortenstring(name, 33));
+               }
                return s->s_namecanon.nc_cname;
        }
 
                return s->s_namecanon.nc_cname;
        }
 
@@ -784,8 +1362,14 @@ host_map_lookup(map, name, av, statp)
                if (tTd(9, 1))
                        printf("host_map_lookup(%s) => ", name);
                s->s_namecanon.nc_flags |= NCF_VALID;           /* will be soon */
                if (tTd(9, 1))
                        printf("host_map_lookup(%s) => ", name);
                s->s_namecanon.nc_flags |= NCF_VALID;           /* will be soon */
-               (void) strcpy(hbuf, name);
-               if (getcanonname(hbuf, sizeof hbuf - 1, TRUE))
+               if (strlen(name) < sizeof hbuf)
+                       (void) strcpy(hbuf, name);
+               else
+               {
+                       bcopy(name, hbuf, sizeof hbuf - 1);
+                       hbuf[sizeof hbuf - 1] = '\0';
+               }
+               if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
                {
                        if (tTd(9, 1))
                                printf("%s\n", hbuf);
                {
                        if (tTd(9, 1))
                                printf("%s\n", hbuf);
@@ -797,23 +1381,25 @@ host_map_lookup(map, name, av, statp)
                {
                        register struct hostent *hp;
 
                {
                        register struct hostent *hp;
 
-                       if (tTd(9, 1))
-                               printf("FAIL (%d)\n", h_errno);
                        s->s_namecanon.nc_errno = errno;
                        s->s_namecanon.nc_errno = errno;
+#if NAMED_BIND
                        s->s_namecanon.nc_herrno = h_errno;
                        s->s_namecanon.nc_herrno = h_errno;
+                       if (tTd(9, 1))
+                               printf("FAIL (%d)\n", h_errno);
                        switch (h_errno)
                        {
                          case TRY_AGAIN:
                                if (UseNameServer)
                                {
                        switch (h_errno)
                        {
                          case TRY_AGAIN:
                                if (UseNameServer)
                                {
-                                       message(timeoutmsg);
-                                       if (CurEnv->e_message == NULL)
-                                               CurEnv->e_message = newstr(timeoutmsg);
+                                       CurEnv->e_status = "4.4.3";
+                                       usrerr("451 %s: Name server timeout",
+                                               shortenstring(name, 33));
                                }
                                *statp = EX_TEMPFAIL;
                                break;
 
                          case HOST_NOT_FOUND:
                                }
                                *statp = EX_TEMPFAIL;
                                break;
 
                          case HOST_NOT_FOUND:
+                         case NO_DATA:
                                *statp = EX_NOHOST;
                                break;
 
                                *statp = EX_NOHOST;
                                break;
 
@@ -825,15 +1411,21 @@ host_map_lookup(map, name, av, statp)
                                *statp = EX_UNAVAILABLE;
                                break;
                        }
                                *statp = EX_UNAVAILABLE;
                                break;
                        }
+#else
+                       if (tTd(9, 1))
+                               printf("FAIL\n");
+                       *statp = EX_NOHOST;
+#endif
                        s->s_namecanon.nc_stat = *statp;
                        s->s_namecanon.nc_stat = *statp;
-                       if (*statp != EX_TEMPFAIL || UseNameServer)
+                       if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) ||
+                           UseNameServer)
                                return NULL;
 
                        /*
                        **  Try to look it up in /etc/hosts
                        */
 
                                return NULL;
 
                        /*
                        **  Try to look it up in /etc/hosts
                        */
 
-                       hp = gethostbyname(name);
+                       hp = sm_gethostbyname(name);
                        if (hp == NULL)
                        {
                                /* no dice there either */
                        if (hp == NULL)
                        {
                                /* no dice there either */
@@ -850,12 +1442,14 @@ host_map_lookup(map, name, av, statp)
        if ((cp = strchr(name, ']')) == NULL)
                return (NULL);
        *cp = '\0';
        if ((cp = strchr(name, ']')) == NULL)
                return (NULL);
        *cp = '\0';
-       in_addr = inet_addr(&name[1]);
+       in_addr.s_addr = inet_addr(&name[1]);
 
        /* nope -- ask the name server */
 
        /* nope -- ask the name server */
-       hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
+       hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET);
        s->s_namecanon.nc_errno = errno;
        s->s_namecanon.nc_errno = errno;
+#if NAMED_BIND
        s->s_namecanon.nc_herrno = h_errno;
        s->s_namecanon.nc_herrno = h_errno;
+#endif
        s->s_namecanon.nc_flags |= NCF_VALID;           /* will be soon */
        if (hp == NULL)
        {
        s->s_namecanon.nc_flags |= NCF_VALID;           /* will be soon */
        if (hp == NULL)
        {
@@ -879,6 +1473,10 @@ host_map_lookup(map, name, av, statp)
 **             A printable version of that sockaddr.
 */
 
 **             A printable version of that sockaddr.
 */
 
+#if NETLINK
+# include <net/if_dl.h>
+#endif
+
 char *
 anynet_ntoa(sap)
        register SOCKADDR *sap;
 char *
 anynet_ntoa(sap)
        register SOCKADDR *sap;
@@ -896,8 +1494,7 @@ anynet_ntoa(sap)
 
        switch (sap->sa.sa_family)
        {
 
        switch (sap->sa.sa_family)
        {
-#ifdef MAYBENEXTRELEASE                /*** UNTESTED *** UNTESTED *** UNTESTED ***/
-#ifdef NETUNIX
+#if NETUNIX
          case AF_UNIX:
                if (sap->sunix.sun_path[0] != '\0')
                        sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path);
          case AF_UNIX:
                if (sap->sunix.sun_path[0] != '\0')
                        sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path);
@@ -905,16 +1502,22 @@ anynet_ntoa(sap)
                        sprintf(buf, "[UNIX: localhost]");
                return buf;
 #endif
                        sprintf(buf, "[UNIX: localhost]");
                return buf;
 #endif
-#endif
 
 
-#ifdef NETINET
+#if NETINET
          case AF_INET:
          case AF_INET:
-               return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
+               return inet_ntoa(sap->sin.sin_addr);
 #endif
 
 #endif
 
+#if NETLINK
+         case AF_LINK:
+               sprintf(buf, "[LINK: %s]",
+                       link_ntoa((struct sockaddr_dl *) &sap->sa));
+               return buf;
+#endif
          default:
          default:
-               /* this case is only to ensure syntactic correctness */
-               break;
+               /* this case is needed when nothing is #defined */
+               /* in order to keep the switch syntactically correct */
+               break;
        }
 
        /* unknown family -- just dump bytes */
        }
 
        /* unknown family -- just dump bytes */
@@ -949,7 +1552,7 @@ hostnamebyanyaddr(sap)
        register struct hostent *hp;
        int saveretry;
 
        register struct hostent *hp;
        int saveretry;
 
-#ifdef NAMED_BIND
+#if NAMED_BIND
        /* shorten name server timeout to avoid higher level timeouts */
        saveretry = _res.retry;
        _res.retry = 3;
        /* shorten name server timeout to avoid higher level timeouts */
        saveretry = _res.retry;
        _res.retry = 3;
@@ -957,36 +1560,34 @@ hostnamebyanyaddr(sap)
 
        switch (sap->sa.sa_family)
        {
 
        switch (sap->sa.sa_family)
        {
-#ifdef NETINET
+#if NETINET
          case AF_INET:
          case AF_INET:
-               hp = gethostbyaddr((char *) &sap->sin.sin_addr,
-                       sizeof sap->sin.sin_addr,
+               hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
+                       INADDRSZ,
                        AF_INET);
                break;
 #endif
 
                        AF_INET);
                break;
 #endif
 
-#ifdef NETISO
+#if NETISO
          case AF_ISO:
          case AF_ISO:
-               hp = gethostbyaddr((char *) &sap->siso.siso_addr,
+               hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
                        sizeof sap->siso.siso_addr,
                        AF_ISO);
                break;
 #endif
 
                        sizeof sap->siso.siso_addr,
                        AF_ISO);
                break;
 #endif
 
-#ifdef MAYBENEXTRELEASE                /*** UNTESTED *** UNTESTED *** UNTESTED ***/
          case AF_UNIX:
                hp = NULL;
                break;
          case AF_UNIX:
                hp = NULL;
                break;
-#endif
 
          default:
 
          default:
-               hp = gethostbyaddr(sap->sa.sa_data,
+               hp = sm_gethostbyaddr(sap->sa.sa_data,
                           sizeof sap->sa.sa_data,
                           sap->sa.sa_family);
                break;
        }
 
                           sizeof sap->sa.sa_data,
                           sap->sa.sa_family);
                break;
        }
 
-#ifdef NAMED_BIND
+#if NAMED_BIND
        _res.retry = saveretry;
 #endif /* NAMED_BIND */
 
        _res.retry = saveretry;
 #endif /* NAMED_BIND */
 
@@ -1081,7 +1682,7 @@ host_map_lookup(map, name, avp, statp)
 {
        register struct hostent *hp;
 
 {
        register struct hostent *hp;
 
-       hp = gethostbyname(name);
+       hp = sm_gethostbyname(name);
        if (hp != NULL)
                return hp->h_name;
        *statp = EX_NOHOST;
        if (hp != NULL)
                return hp->h_name;
        *statp = EX_NOHOST;