BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / sendmail / src / daemon.c
index 61a6181..f16ef27 100644 (file)
@@ -3,18 +3,43 @@
  * 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.81 (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.81 (Berkeley) %G% (without daemon mode)";
+static char sccsid[] = "@(#)daemon.c   8.105 (Berkeley) 6/20/95 (without daemon mode)";
 #endif
 #endif /* not lint */
 
 #endif
 #endif /* not lint */
 
@@ -26,6 +51,12 @@ static char sccsid[] = "@(#)daemon.c 8.81 (Berkeley) %G% (without daemon mode)";
 # 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.
 **
@@ -55,8 +86,6 @@ static char sccsid[] = "@(#)daemon.c  8.81 (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.
 **
@@ -88,7 +117,7 @@ getrequests()
        bool refusingconnections = TRUE;
        FILE *pidf;
        int socksize;
        bool refusingconnections = TRUE;
        FILE *pidf;
        int socksize;
-#ifdef XDEBUG
+#if XDEBUG
        bool j_has_dot;
 #endif
        extern void reapchild();
        bool j_has_dot;
 #endif
        extern void reapchild();
@@ -143,7 +172,7 @@ getrequests()
                fclose(pidf);
        }
 
                fclose(pidf);
        }
 
-#ifdef XDEBUG
+#if XDEBUG
        {
                char jbuf[MAXHOSTNAMELEN];
 
        {
                char jbuf[MAXHOSTNAMELEN];
 
@@ -155,13 +184,435 @@ getrequests()
        if (tTd(15, 1))
                printf("getrequests: %d\n", DaemonSocket);
 
        if (tTd(15, 1))
                printf("getrequests: %d\n", DaemonSocket);
 
-       struct wh wbuf;
+       for (;;)
+       {
+               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;
+               }
+
+               /* arrange to (re)open the socket if necessary */
+               if (refusingconnections)
+               {
+                       (void) opendaemonsocket(FALSE);
+                       refusingconnections = FALSE;
+               }
+
+#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();
 
 
-       wbuf.index = index;
-       wbuf.count = 0;
-       wbuf.ccount = cnt;
-       wbuf.data = buf;
-       write(MailPort, &wbuf, sizeof wbuf);
+                       /*
+                       **  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 */
+
+int
+opendaemonsocket(firsttime)
+       bool firsttime;
+{
+       int on = 1;
+       int socksize = 0;
+       int ntries = 0;
+       int saveerrno;
+
+       if (tTd(15, 2))
+               printf("opendaemonsocket()\n");
+
+       do
+       {
+               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);
+       DaemonSocket = -1;
+}
+\f/*
+**  SETDAEMONOPTIONS -- set options for running the daemon
+**
+**     Parameters:
+**             p -- the options line.
+**
+**     Returns:
+**             none.
+*/
+
+void
+setdaemonoptions(p)
+       register char *p;
+{
+       if (DaemonAddr.sa.sa_family == AF_UNSPEC)
+               DaemonAddr.sa.sa_family = AF_INET;
+
+       while (p != NULL)
+       {
+               register char *f;
+               register char *v;
+
+               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);
+
+               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;
+
+                 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
+
+                         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;
+
+                 case 'R':             /* receive buffer size */
+                       TcpRcvBufferSize = atoi(v);
+                       break;
+
+                 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.
@@ -198,9 +649,6 @@ makeconnection(host, port, mci, usesecureport)
        int sav_errno;
        int addrlen;
        bool firstconnect;
        int sav_errno;
        int addrlen;
        bool firstconnect;
-#if NAMED_BIND
-       extern int h_errno;
-#endif
 
        /*
        **  Set up the address for the mailer.
 
        /*
        **  Set up the address for the mailer.
@@ -223,7 +671,7 @@ 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
                        hid = inet_addr(&host[1]);
                        if (hid == -1)
 #endif
@@ -252,9 +700,10 @@ 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
                addr.sin.sin_family = AF_INET;          /*XXX*/
                addr.sin.sin_addr.s_addr = hid;
 #endif
@@ -295,7 +744,7 @@ gothostent:
                addr.sa.sa_family = hp->h_addrtype;
                switch (hp->h_addrtype)
                {
                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,
@@ -316,9 +765,7 @@ 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");
 
        {
                register struct servent *sp = getservbyname("smtp", "tcp");
 
@@ -336,14 +783,14 @@ gothostent:
 
        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);
@@ -389,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;
                }
 
@@ -440,7 +887,7 @@ gothostent:
                                        errstring(sav_errno));
                        switch (addr.sa.sa_family)
                        {
                                        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,
@@ -503,7 +950,6 @@ myhostname(hostbuf, size)
 {
        register struct hostent *hp;
        extern bool getcanonname();
 {
        register struct hostent *hp;
        extern bool getcanonname();
-       extern int h_errno;
 
        if (gethostname(hostbuf, size) < 0)
        {
 
        if (gethostname(hostbuf, size) < 0)
        {
@@ -518,27 +964,43 @@ myhostname(hostbuf, size)
                hostbuf[size - 1] = '\0';
        }
 
                hostbuf[size - 1] = '\0';
        }
 
-#if NAMED_BIND
        /*
        /*
-       **  If still no dot, try DNS directly (i.e., avoid NIS problems).
-       **  This ought to be driven from the configuration file, but
-       **  we are called before the configuration is read.  We could
-       **  check for an /etc/resolv.conf file, but that isn't required.
+       **  If there is still no dot in the name, try looking for a
+       **  dotted alias.
+       */
+
+       if (strchr(hostbuf, '.') == NULL)
+       {
+               char **ha;
+
+               for (ha = hp->h_aliases; *ha != NULL; ha++)
+               {
+                       if (strchr(*ha, '.') != NULL)
+                       {
+                               (void) strncpy(hostbuf, *ha, size - 1);
+                               hostbuf[size - 1] = '\0';
+                               break;
+                       }
+               }
+       }
+
+       /*
+       **  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 &&
        **  All in all, a bit of a mess.
        */
 
        if (strchr(hostbuf, '.') == NULL &&
-           !getcanonname(hostbuf, size, TRUE) &&
-           h_errno == TRY_AGAIN)
+           !getcanonname(hostbuf, size, TRUE))
        {
        {
-               /* try twice in case name server not yet started up */
-               message("My unqualifed host name (%s) unknown to DNS; sleeping for retry",
+               message("My unqualifed host name (%s) unknown; sleeping for retry",
                        hostbuf);
                sleep(60);
                        hostbuf);
                sleep(60);
-               if (!getcanonname(hostbuf, size, TRUE))
-                       errno = h_errno + E_DNSBASE;
+               (void) getcanonname(hostbuf, size, TRUE);
        }
        }
-#endif
        return (hp);
 }
 \f/*
        return (hp);
 }
 \f/*
@@ -575,10 +1037,8 @@ getauthinfo(fd)
        EVENT *ev;
        int nleft;
        char ibuf[MAXNAME + 1];
        EVENT *ev;
        int nleft;
        char ibuf[MAXNAME + 1];
-       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 RealHostAddr;
        if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 ||
 
        falen = sizeof RealHostAddr;
        if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 ||
@@ -721,7 +1181,7 @@ getauthinfo(fd)
        i = strlen(hbuf);
        hbuf[i++] = '@';
        strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName);
        i = strlen(hbuf);
        hbuf[i++] = '@';
        strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName);
-       goto finish;
+       goto postident;
 
 closeident:
        (void) close(s);
 
 closeident:
        (void) close(s);
@@ -736,12 +1196,92 @@ noident:
        }
        (void) strcpy(hbuf, RealHostName);
 
        }
        (void) strcpy(hbuf, RealHostName);
 
-finish:
+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));
        }
        if (RealHostName != NULL && RealHostName[0] != '[')
        {
                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;
@@ -779,9 +1319,6 @@ host_map_lookup(map, name, av, statp)
        char *cp;
        register STAB *s;
        char hbuf[MAXNAME + 1];
        char *cp;
        register STAB *s;
        char hbuf[MAXNAME + 1];
-#if NAMED_BIND
-       extern int h_errno;
-#endif
 
        /*
        **  See if we have already looked up this name.  If so, just
 
        /*
        **  See if we have already looked up this name.  If so, just
@@ -793,7 +1330,10 @@ 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;
 #if NAMED_BIND
                h_errno = s->s_namecanon.nc_herrno;
                errno = s->s_namecanon.nc_errno;
 #if NAMED_BIND
                h_errno = s->s_namecanon.nc_herrno;
@@ -801,6 +1341,7 @@ host_map_lookup(map, name, av, statp)
                *statp = s->s_namecanon.nc_stat;
                if (*statp == EX_TEMPFAIL)
                {
                *statp = s->s_namecanon.nc_stat;
                if (*statp == EX_TEMPFAIL)
                {
+                       CurEnv->e_status = "4.4.3";
                        usrerr("451 %s: Name server timeout",
                                shortenstring(name, 33));
                }
                        usrerr("451 %s: Name server timeout",
                                shortenstring(name, 33));
                }
@@ -828,7 +1369,7 @@ host_map_lookup(map, name, av, statp)
                        bcopy(name, hbuf, sizeof hbuf - 1);
                        hbuf[sizeof hbuf - 1] = '\0';
                }
                        bcopy(name, hbuf, sizeof hbuf - 1);
                        hbuf[sizeof hbuf - 1] = '\0';
                }
-               if (getcanonname(hbuf, sizeof hbuf - 1, !NoMXforCanon))
+               if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
                {
                        if (tTd(9, 1))
                                printf("%s\n", hbuf);
                {
                        if (tTd(9, 1))
                                printf("%s\n", hbuf);
@@ -850,6 +1391,7 @@ host_map_lookup(map, name, av, statp)
                          case TRY_AGAIN:
                                if (UseNameServer)
                                {
                          case TRY_AGAIN:
                                if (UseNameServer)
                                {
+                                       CurEnv->e_status = "4.4.3";
                                        usrerr("451 %s: Name server timeout",
                                                shortenstring(name, 33));
                                }
                                        usrerr("451 %s: Name server timeout",
                                                shortenstring(name, 33));
                                }
@@ -857,6 +1399,7 @@ host_map_lookup(map, name, av, statp)
                                break;
 
                          case HOST_NOT_FOUND:
                                break;
 
                          case HOST_NOT_FOUND:
+                         case NO_DATA:
                                *statp = EX_NOHOST;
                                break;
 
                                *statp = EX_NOHOST;
                                break;
 
@@ -930,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;
@@ -947,7 +1494,7 @@ anynet_ntoa(sap)
 
        switch (sap->sa.sa_family)
        {
 
        switch (sap->sa.sa_family)
        {
-#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);
@@ -956,14 +1503,21 @@ anynet_ntoa(sap)
                return buf;
 #endif
 
                return buf;
 #endif
 
-#ifdef NETINET
+#if NETINET
          case AF_INET:
                return inet_ntoa(sap->sin.sin_addr);
 #endif
 
          case AF_INET:
                return inet_ntoa(sap->sin.sin_addr);
 #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 */
@@ -1006,7 +1560,7 @@ hostnamebyanyaddr(sap)
 
        switch (sap->sa.sa_family)
        {
 
        switch (sap->sa.sa_family)
        {
-#ifdef NETINET
+#if NETINET
          case AF_INET:
                hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
                        INADDRSZ,
          case AF_INET:
                hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
                        INADDRSZ,
@@ -1014,7 +1568,7 @@ hostnamebyanyaddr(sap)
                break;
 #endif
 
                break;
 #endif
 
-#ifdef NETISO
+#if NETISO
          case AF_ISO:
                hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
                        sizeof sap->siso.siso_addr,
          case AF_ISO:
                hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
                        sizeof sap->siso.siso_addr,