BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.sbin / sendmail / src / daemon.c
index 293438b..f16ef27 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * 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.
  *
 
 #ifndef lint
 #ifdef DAEMON
 
 #ifndef lint
 #ifdef DAEMON
-static char sccsid[] = "@(#)daemon.c   8.48 (Berkeley) 4/18/94 (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.48 (Berkeley) 4/18/94 (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 <arpa/inet.h>
 
 #if NAMED_BIND
 # include <arpa/inet.h>
 
 #if NAMED_BIND
-# include <arpa/nameser.h>
 # 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.
 **
@@ -106,13 +110,14 @@ 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;
        bool refusingconnections = TRUE;
        FILE *pidf;
        int socksize;
 getrequests()
 {
        int t;
        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();
@@ -167,11 +172,11 @@ getrequests()
                fclose(pidf);
        }
 
                fclose(pidf);
        }
 
-#ifdef XDEBUG
+#if XDEBUG
        {
                char jbuf[MAXHOSTNAMELEN];
 
        {
                char jbuf[MAXHOSTNAMELEN];
 
-               expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
+               expand("\201j", jbuf, sizeof jbuf, CurEnv);
                j_has_dot = strchr(jbuf, '.') != NULL;
        }
 #endif
                j_has_dot = strchr(jbuf, '.') != NULL;
        }
 #endif
@@ -184,6 +189,7 @@ getrequests()
                register int pid;
                auto int lotherend;
                extern bool refuseconnections();
                register int pid;
                auto int lotherend;
                extern bool refuseconnections();
+               extern int getla();
 
                /* see if we are rejecting connections */
                CurrentLA = getla();
 
                /* see if we are rejecting connections */
                CurrentLA = getla();
@@ -196,29 +202,24 @@ getrequests()
                                DaemonSocket = -1;
                        }
                        refusingconnections = TRUE;
                                DaemonSocket = -1;
                        }
                        refusingconnections = TRUE;
-                       setproctitle("rejecting connections: load average: %d",
-                               CurrentLA);
                        sleep(15);
                        continue;
                }
 
                        sleep(15);
                        continue;
                }
 
+               /* arrange to (re)open the socket if necessary */
                if (refusingconnections)
                {
                if (refusingconnections)
                {
-                       /* start listening again */
                        (void) opendaemonsocket(FALSE);
                        (void) opendaemonsocket(FALSE);
-                       setproctitle("accepting connections");
                        refusingconnections = FALSE;
                }
 
                        refusingconnections = FALSE;
                }
 
-#ifdef XDEBUG
+#if XDEBUG
                /* check for disaster */
                {
                /* check for disaster */
                {
-                       register STAB *s;
                        char jbuf[MAXHOSTNAMELEN];
 
                        char jbuf[MAXHOSTNAMELEN];
 
-                       expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
-                       if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL ||
-                           !bitnset('w', s->s_class))
+                       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");
                        {
                                dumpstate("daemon lost $j");
                                syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog");
@@ -234,6 +235,7 @@ getrequests()
 #endif
 
                /* wait for a connection */
 #endif
 
                /* wait for a connection */
+               setproctitle("accepting connections");
                do
                {
                        errno = 0;
                do
                {
                        errno = 0;
@@ -244,6 +246,10 @@ getrequests()
                if (t < 0)
                {
                        syserr("getrequests: accept");
                if (t < 0)
                {
                        syserr("getrequests: accept");
+
+                       /* arrange to re-open the socket next time around */
+                       (void) close(DaemonSocket);
+                       DaemonSocket = -1;
                        sleep(5);
                        continue;
                }
                        sleep(5);
                        continue;
                }
@@ -268,6 +274,7 @@ getrequests()
                {
                        char *p;
                        extern char *hostnamebyanyaddr();
                {
                        char *p;
                        extern char *hostnamebyanyaddr();
+                       extern void intsig();
 
                        /*
                        **  CHILD -- return to caller.
 
                        /*
                        **  CHILD -- return to caller.
@@ -276,6 +283,8 @@ getrequests()
                        */
 
                        (void) setsignal(SIGCHLD, SIG_DFL);
                        */
 
                        (void) setsignal(SIGCHLD, SIG_DFL);
+                       (void) setsignal(SIGHUP, intsig);
+                       (void) close(DaemonSocket);
                        DisConnected = FALSE;
 
                        setproctitle("startup with %s",
                        DisConnected = FALSE;
 
                        setproctitle("startup with %s",
@@ -283,19 +292,11 @@ getrequests()
 
                        /* determine host name */
                        p = hostnamebyanyaddr(&RealHostAddr);
 
                        /* determine host name */
                        p = hostnamebyanyaddr(&RealHostAddr);
+                       if (strlen(p) > MAXNAME)
+                               p[MAXNAME] = '\0';
                        RealHostName = newstr(p);
                        setproctitle("startup with %s", p);
 
                        RealHostName = newstr(p);
                        setproctitle("startup with %s", p);
 
-#ifdef LOG
-                       if (LogLevel > 11)
-                       {
-                               /* log connection information */
-                               syslog(LOG_INFO, "connect from %s (%s)",
-                                       RealHostName, anynet_ntoa(&RealHostAddr));
-                       }
-#endif
-
-                       (void) close(DaemonSocket);
                        if ((InChannel = fdopen(t, "r")) == NULL ||
                            (t = dup(t)) < 0 ||
                            (OutChannel = fdopen(t, "w")) == NULL)
                        if ((InChannel = fdopen(t, "r")) == NULL ||
                            (t = dup(t)) < 0 ||
                            (OutChannel = fdopen(t, "w")) == NULL)
@@ -318,6 +319,8 @@ getrequests()
                        return;
                }
 
                        return;
                }
 
+               CurChildren++;
+
                /* close the port so that others will hang (for a while) */
                (void) close(t);
        }
                /* close the port so that others will hang (for a while) */
                (void) close(t);
        }
@@ -347,7 +350,7 @@ opendaemonsocket(firsttime)
        bool firsttime;
 {
        int on = 1;
        bool firsttime;
 {
        int on = 1;
-       int socksize;
+       int socksize = 0;
        int ntries = 0;
        int saveerrno;
 
        int ntries = 0;
        int saveerrno;
 
@@ -399,13 +402,13 @@ opendaemonsocket(firsttime)
 
                        switch (DaemonAddr.sa.sa_family)
                        {
 
                        switch (DaemonAddr.sa.sa_family)
                        {
-# ifdef NETINET
+# if NETINET
                          case AF_INET:
                                socksize = sizeof DaemonAddr.sin;
                                break;
 # endif
 
                          case AF_INET:
                                socksize = sizeof DaemonAddr.sin;
                                break;
 # endif
 
-# ifdef NETISO
+# if NETISO
                          case AF_ISO:
                                socksize = sizeof DaemonAddr.siso;
                                break;
                          case AF_ISO:
                                socksize = sizeof DaemonAddr.siso;
                                break;
@@ -433,6 +436,7 @@ opendaemonsocket(firsttime)
                }
                return socksize;
        } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
                }
                return socksize;
        } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
+       syserr("!opendaemonsocket: server SMTP socket wedged: exiting");
        finis();
 }
 \f/*
        finis();
 }
 \f/*
@@ -448,6 +452,7 @@ opendaemonsocket(firsttime)
 **             releases any resources used by the passive daemon.
 */
 
 **             releases any resources used by the passive daemon.
 */
 
+void
 clrdaemon()
 {
        if (DaemonSocket >= 0)
 clrdaemon()
 {
        if (DaemonSocket >= 0)
@@ -464,6 +469,7 @@ clrdaemon()
 **             none.
 */
 
 **             none.
 */
 
+void
 setdaemonoptions(p)
        register char *p;
 {
 setdaemonoptions(p)
        register char *p;
 {
@@ -488,25 +494,27 @@ setdaemonoptions(p)
                        continue;
                while (isascii(*++v) && isspace(*v))
                        continue;
                        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);
 
                switch (*f)
                {
                  case 'F':             /* address family */
                        if (isascii(*v) && isdigit(*v))
                                DaemonAddr.sa.sa_family = atoi(v);
-#ifdef NETINET
+#if NETINET
                        else if (strcasecmp(v, "inet") == 0)
                                DaemonAddr.sa.sa_family = AF_INET;
 #endif
                        else if (strcasecmp(v, "inet") == 0)
                                DaemonAddr.sa.sa_family = AF_INET;
 #endif
-#ifdef NETISO
+#if NETISO
                        else if (strcasecmp(v, "iso") == 0)
                                DaemonAddr.sa.sa_family = AF_ISO;
 #endif
                        else if (strcasecmp(v, "iso") == 0)
                                DaemonAddr.sa.sa_family = AF_ISO;
 #endif
-#ifdef NETNS
+#if NETNS
                        else if (strcasecmp(v, "ns") == 0)
                                DaemonAddr.sa.sa_family = AF_NS;
 #endif
                        else if (strcasecmp(v, "ns") == 0)
                                DaemonAddr.sa.sa_family = AF_NS;
 #endif
-#ifdef NETX25
+#if NETX25
                        else if (strcasecmp(v, "x.25") == 0)
                                DaemonAddr.sa.sa_family = AF_CCITT;
 #endif
                        else if (strcasecmp(v, "x.25") == 0)
                                DaemonAddr.sa.sa_family = AF_CCITT;
 #endif
@@ -517,10 +525,10 @@ setdaemonoptions(p)
                  case 'A':             /* address */
                        switch (DaemonAddr.sa.sa_family)
                        {
                  case 'A':             /* address */
                        switch (DaemonAddr.sa.sa_family)
                        {
-#ifdef NETINET
+#if NETINET
                          case AF_INET:
                                if (isascii(*v) && isdigit(*v))
                          case AF_INET:
                                if (isascii(*v) && isdigit(*v))
-                                       DaemonAddr.sin.sin_addr.s_addr = inet_network(v);
+                                       DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v));
                                else
                                {
                                        register struct netent *np;
                                else
                                {
                                        register struct netent *np;
@@ -546,7 +554,7 @@ setdaemonoptions(p)
                        {
                                short port;
 
                        {
                                short port;
 
-#ifdef NETINET
+#if NETINET
                          case AF_INET:
                                if (isascii(*v) && isdigit(*v))
                                        DaemonAddr.sin.sin_port = htons(atoi(v));
                          case AF_INET:
                                if (isascii(*v) && isdigit(*v))
                                        DaemonAddr.sin.sin_port = htons(atoi(v));
@@ -563,7 +571,7 @@ setdaemonoptions(p)
                                break;
 #endif
 
                                break;
 #endif
 
-#ifdef NETISO
+#if NETISO
                          case AF_ISO:
                                /* assume two byte transport selector */
                                if (isascii(*v) && isdigit(*v))
                          case AF_ISO:
                                /* assume two byte transport selector */
                                if (isascii(*v) && isdigit(*v))
@@ -600,6 +608,9 @@ setdaemonoptions(p)
                  case 'R':             /* receive buffer size */
                        TcpRcvBufferSize = atoi(v);
                        break;
                  case 'R':             /* receive buffer size */
                        TcpRcvBufferSize = atoi(v);
                        break;
+
+                 default:
+                       syserr("554 DaemonPortOptions parameter \"%s\" unknown", f);
                }
        }
 }
                }
        }
 }
@@ -631,14 +642,13 @@ 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;
-#if NAMED_BIND
-       extern int h_errno;
-#endif
+       bool firstconnect;
 
        /*
        **  Set up the address for the mailer.
 
        /*
        **  Set up the address for the mailer.
@@ -661,18 +671,26 @@ 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 (hp == NULL && p[-1] == '.')
                                {
+#if NAMED_BIND
+                                       int oldopts = _res.options;
+
+                                       _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
+#endif
                                        p[-1] = '\0';
                                        p[-1] = '\0';
-                                       hp = gethostbyname(&host[1]);
+                                       hp = sm_gethostbyname(&host[1]);
                                        p[-1] = '.';
                                        p[-1] = '.';
+#if NAMED_BIND
+                                       _res.options = oldopts;
+#endif
                                }
                                *p = ']';
                                goto gothostent;
                                }
                                *p = ']';
                                goto gothostent;
@@ -682,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
@@ -693,34 +712,43 @@ makeconnection(host, port, mci, usesecureport)
        {
                register char *p = &host[strlen(host) - 1];
 
        {
                register char *p = &host[strlen(host) - 1];
 
-               hp = gethostbyname(host);
+               hp = sm_gethostbyname(host);
                if (hp == NULL && *p == '.')
                {
                if (hp == NULL && *p == '.')
                {
+#if NAMED_BIND
+                       int oldopts = _res.options;
+
+                       _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
+#endif
                        *p = '\0';
                        *p = '\0';
-                       hp = gethostbyname(host);
+                       hp = sm_gethostbyname(host);
                        *p = '.';
                        *p = '.';
+#if NAMED_BIND
+                       _res.options = oldopts;
+#endif
                }
 gothostent:
                if (hp == NULL)
                {
 #if NAMED_BIND
                }
 gothostent:
                if (hp == NULL)
                {
 #if NAMED_BIND
-                       if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
-                               return (EX_TEMPFAIL);
-
-                       /* if name server is specified, assume temp fail */
-                       if (errno == ECONNREFUSED && UseNameServer)
+                       /* 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,
-                               sizeof addr.sin.sin_addr);
+                               INADDRSZ);
                        break;
 #endif
 
                        break;
 #endif
 
@@ -737,15 +765,16 @@ 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");
+#ifdef LOG
+                       if (LogLevel > 2)
+                               syslog(LOG_ERR, "makeconnection: service \"smtp\" unknown");
+#endif
                        port = htons(25);
                }
                else
                        port = htons(25);
                }
                else
@@ -754,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);
@@ -784,6 +813,7 @@ gothostent:
                return EX_TEMPFAIL;
 #endif
 
                return EX_TEMPFAIL;
 #endif
 
+       firstconnect = TRUE;
        for (;;)
        {
                if (tTd(16, 1))
        for (;;)
        {
                if (tTd(16, 1))
@@ -806,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;
                }
 
@@ -836,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,
-                                     sizeof addr.sin.sin_addr);
+                                     INADDRSZ);
                                break;
 #endif
 
                                break;
 #endif
 
@@ -902,61 +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);
+       hp = sm_gethostbyname(hostbuf);
        if (hp == NULL)
        if (hp == NULL)
+               return NULL;
+       if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
        {
        {
-               syserr("!My host name (%s) does not seem to exist!", hostbuf);
+               (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 NAMED_BIND
-       /* if still no dot, try DNS directly (i.e., avoid NIS problems) */
+       /*
+       **  If there is still no dot in the name, try looking for a
+       **  dotted alias.
+       */
+
        if (strchr(hostbuf, '.') == NULL)
        {
        if (strchr(hostbuf, '.') == NULL)
        {
-               extern bool getcanonname();
-               extern int h_errno;
+               char **ha;
 
 
-               /* try twice in case name server not yet started up */
-               if (!getcanonname(hostbuf, size, TRUE) &&
-                   UseNameServer &&
-                   (h_errno != TRY_AGAIN ||
-                    (sleep(30), !getcanonname(hostbuf, size, TRUE))))
+               for (ha = hp->h_aliases; *ha != NULL; ha++)
                {
                {
-                       errno = h_errno + E_DNSBASE;
-                       syserr("!My host name (%s) not known to DNS",
-                               hostbuf);
+                       if (strchr(*ha, '.') != NULL)
+                       {
+                               (void) strncpy(hostbuf, *ha, size - 1);
+                               hostbuf[size - 1] = '\0';
+                               break;
+                       }
                }
        }
                }
        }
-#endif
-
-       if (hp->h_addrtype == AF_INET && hp->h_length == 4)
-       {
-               register int i;
 
 
-               for (i = 0; hp->h_addr_list[i] != NULL; i++)
-               {
-                       char ipbuf[100];
+       /*
+       **  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.
+       */
 
 
-                       sprintf(ipbuf, "[%s]",
-                               inet_ntoa(*((struct in_addr *) hp->h_addr_list[i])));
-                       setclass('w', ipbuf);
-               }
+       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);
        }
        }
-
-       return (hp->h_aliases);
+       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
@@ -970,39 +1015,34 @@ myhostname(hostbuf, size)
 **             The user@host information associated with this descriptor.
 */
 
 **             The user@host information associated with this descriptor.
 */
 
-#if 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;
 {
        int falen;
        register char *p;
 char *
 getauthinfo(fd)
        int fd;
 {
        int falen;
        register char *p;
-#if 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 RealHostAddr;
 
        falen = sizeof RealHostAddr;
-       if (getpeername(fd, &RealHostAddr.sa, &falen) < 0 || falen <= 0 ||
-           RealHostAddr.sa.sa_family == 0)
+       if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 ||
+           falen <= 0 || RealHostAddr.sa.sa_family == 0)
        {
                (void) sprintf(hbuf, "%s@localhost", RealUserName);
                if (tTd(9, 1))
        {
                (void) sprintf(hbuf, "%s@localhost", RealUserName);
                if (tTd(9, 1))
@@ -1016,7 +1056,6 @@ getauthinfo(fd)
                RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
        }
 
                RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
        }
 
-#if IDENTPROTO
        if (TimeOuts.to_ident == 0)
                goto noident;
 
        if (TimeOuts.to_ident == 0)
                goto noident;
 
@@ -1030,7 +1069,7 @@ getauthinfo(fd)
        }
 
        /* create ident query */
        }
 
        /* create ident query */
-       (void) sprintf(hbuf, "%d,%d\r\n",
+       (void) sprintf(ibuf, "%d,%d\r\n",
                ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
 
        /* create local address */
                ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
 
        /* create local address */
@@ -1068,27 +1107,34 @@ getauthinfo(fd)
        }
 
        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 */
@@ -1111,6 +1157,14 @@ getauthinfo(fd)
        }
 
        /* 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)
        {
@@ -1122,17 +1176,17 @@ getauthinfo(fd)
        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 == NULL ? "localhost" : 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;
 
 closeident:
        (void) close(s);
        clrevent(ev);
 
 
 closeident:
        (void) close(s);
        clrevent(ev);
 
-#endif /* IDENTPROTO */
-
 noident:
        if (RealHostName == NULL)
        {
 noident:
        if (RealHostName == NULL)
        {
@@ -1142,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;
@@ -1181,15 +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 hbuf[MAXNAME];
-       extern struct hostent *gethostbyaddr();
-#if NAMED_BIND
-       extern int h_errno;
-#endif
+       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
@@ -1201,17 +1330,20 @@ 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;
 #endif
                *statp = s->s_namecanon.nc_stat;
                errno = s->s_namecanon.nc_errno;
 #if NAMED_BIND
                h_errno = s->s_namecanon.nc_herrno;
 #endif
                *statp = s->s_namecanon.nc_stat;
-               if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL)
+               if (*statp == EX_TEMPFAIL)
                {
                {
-                       sprintf(hbuf, "%s: Name server timeout",
+                       CurEnv->e_status = "4.4.3";
+                       usrerr("451 %s: Name server timeout",
                                shortenstring(name, 33));
                                shortenstring(name, 33));
-                       CurEnv->e_message = newstr(hbuf);
                }
                return s->s_namecanon.nc_cname;
        }
                }
                return s->s_namecanon.nc_cname;
        }
@@ -1230,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);
@@ -1253,16 +1391,15 @@ host_map_lookup(map, name, av, statp)
                          case TRY_AGAIN:
                                if (UseNameServer)
                                {
                          case TRY_AGAIN:
                                if (UseNameServer)
                                {
-                                       sprintf(hbuf, "%s: Name server timeout",
+                                       CurEnv->e_status = "4.4.3";
+                                       usrerr("451 %s: Name server timeout",
                                                shortenstring(name, 33));
                                                shortenstring(name, 33));
-                                       message("%s", hbuf);
-                                       if (CurEnv->e_message == NULL)
-                                               CurEnv->e_message = newstr(hbuf);
                                }
                                *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;
 
@@ -1280,14 +1417,15 @@ host_map_lookup(map, name, av, statp)
                        *statp = EX_NOHOST;
 #endif
                        s->s_namecanon.nc_stat = *statp;
                        *statp = EX_NOHOST;
 #endif
                        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 */
@@ -1304,10 +1442,10 @@ 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;
 #if NAMED_BIND
        s->s_namecanon.nc_herrno = h_errno;
        s->s_namecanon.nc_errno = errno;
 #if NAMED_BIND
        s->s_namecanon.nc_herrno = h_errno;
@@ -1335,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;
@@ -1352,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);
@@ -1361,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 */
@@ -1413,30 +1560,28 @@ 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;
@@ -1537,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;