signal and file locking portability changes
[unix-history] / usr / src / usr.sbin / sendmail / src / daemon.c
index 0652c4c..20fbd0e 100644 (file)
@@ -1,21 +1,20 @@
 /*
  * Copyright (c) 1983 Eric P. Allman
 /*
  * Copyright (c) 1983 Eric P. Allman
- * Copyright (c) 1988 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%
  */
 
 #include <errno.h>
  *
  * %sccs.include.redist.c%
  */
 
 #include <errno.h>
-#include <signal.h>
 #include "sendmail.h"
 # include <sys/mx.h>
 
 #ifndef lint
 #ifdef DAEMON
 #include "sendmail.h"
 # include <sys/mx.h>
 
 #ifndef lint
 #ifdef DAEMON
-static char sccsid[] = "@(#)daemon.c   6.16 (Berkeley) %G% (with daemon mode)";
+static char sccsid[] = "@(#)daemon.c   8.5 (Berkeley) %G% (with daemon mode)";
 #else
 #else
-static char sccsid[] = "@(#)daemon.c   6.16 (Berkeley) %G% (without daemon mode)";
+static char sccsid[] = "@(#)daemon.c   8.5 (Berkeley) %G% (without daemon mode)";
 #endif
 #endif /* not lint */
 
 #endif
 #endif /* not lint */
 
@@ -25,6 +24,11 @@ static char sccsid[] = "@(#)daemon.c 6.16 (Berkeley) %G% (without daemon mode)";
 # include <sys/wait.h>
 # include <sys/time.h>
 
 # include <sys/wait.h>
 # include <sys/time.h>
 
+#ifdef NAMED_BIND
+# include <arpa/nameser.h>
+# include <resolv.h>
+#endif
+
 /*
 **  DAEMON.C -- routines to use when running as a daemon.
 **
 /*
 **  DAEMON.C -- routines to use when running as a daemon.
 **
@@ -51,7 +55,7 @@ static char sccsid[] = "@(#)daemon.c  6.16 (Berkeley) %G% (without daemon mode)";
 **             appropriate for communication.  Returns zero on
 **             success, else an exit status describing the
 **             error.
 **             appropriate for communication.  Returns zero on
 **             success, else an exit status describing the
 **             error.
-**     maphostname(map, hbuf, hbufsiz, avp)
+**     host_map_lookup(map, hbuf, avp, pstat)
 **             Convert the entry in hbuf into a canonical form.
 */
 
 **             Convert the entry in hbuf into a canonical form.
 */
 
@@ -74,7 +78,9 @@ static FILE   *MailPort;      /* port that mail comes in on */
 **             to the communication channel.
 */
 
 **             to the communication channel.
 */
 
-int    DaemonSocket    = -1;           /* fd describing socket */
+int            DaemonSocket    = -1;           /* fd describing socket */
+SOCKADDR       DaemonAddr;                     /* socket for incoming */
+int            ListenQueueSize = 10;           /* size of listen queue */
 
 getrequests()
 {
 
 getrequests()
 {
@@ -83,32 +89,36 @@ getrequests()
        int on = 1;
        bool refusingconnections = TRUE;
        FILE *pidf;
        int on = 1;
        bool refusingconnections = TRUE;
        FILE *pidf;
-       struct sockaddr_in srvraddr;
        extern void reapchild();
 
        /*
        **  Set up the address for the mailer.
        */
 
        extern void reapchild();
 
        /*
        **  Set up the address for the mailer.
        */
 
-       sp = getservbyname("smtp", "tcp");
-       if (sp == NULL)
+       if (DaemonAddr.sin.sin_family == 0)
+               DaemonAddr.sin.sin_family = AF_INET;
+       if (DaemonAddr.sin.sin_addr.s_addr == 0)
+               DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
+       if (DaemonAddr.sin.sin_port == 0)
        {
        {
-               syserr("554 server \"smtp\" unknown");
-               goto severe;
+               sp = getservbyname("smtp", "tcp");
+               if (sp == NULL)
+               {
+                       syserr("554 service \"smtp\" unknown");
+                       goto severe;
+               }
+               DaemonAddr.sin.sin_port = sp->s_port;
        }
        }
-       srvraddr.sin_family = AF_INET;
-       srvraddr.sin_addr.s_addr = INADDR_ANY;
-       srvraddr.sin_port = sp->s_port;
 
        /*
        **  Try to actually open the connection.
        */
 
        if (tTd(15, 1))
 
        /*
        **  Try to actually open the connection.
        */
 
        if (tTd(15, 1))
-               printf("getrequests: port 0x%x\n", srvraddr.sin_port);
+               printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port);
 
        /* get a socket for the SMTP connection */
 
        /* get a socket for the SMTP connection */
-       DaemonSocket = socket(AF_INET, SOCK_STREAM, 0);
+       DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
        if (DaemonSocket < 0)
        {
                /* probably another daemon already */
        if (DaemonSocket < 0)
        {
                /* probably another daemon already */
@@ -127,20 +137,47 @@ getrequests()
        (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on);
        (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (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);
 
-       if (bind(DaemonSocket, (struct sockaddr *)&srvraddr, sizeof srvraddr) < 0)
+       switch (DaemonAddr.sa.sa_family)
+       {
+# ifdef NETINET
+         case AF_INET:
+               t = sizeof DaemonAddr.sin;
+               break;
+# endif
+
+# ifdef NETISO
+         case AF_ISO:
+               t = sizeof DaemonAddr.siso;
+               break;
+# endif
+
+         default:
+               t = sizeof DaemonAddr;
+               break;
+       }
+
+       if (bind(DaemonSocket, &DaemonAddr.sa, t) < 0)
        {
                syserr("getrequests: cannot bind");
                (void) close(DaemonSocket);
                goto severe;
        }
 
        {
                syserr("getrequests: cannot bind");
                (void) close(DaemonSocket);
                goto severe;
        }
 
-       (void) signal(SIGCHLD, reapchild);
+       (void) setsignal(SIGCHLD, reapchild);
 
        /* write the pid to the log file for posterity */
        pidf = fopen(PidFile, "w");
        if (pidf != NULL)
        {
 
        /* write the pid to the log file for posterity */
        pidf = fopen(PidFile, "w");
        if (pidf != NULL)
        {
+               extern char *CommandLineArgs;
+
+               /* write the process id on line 1 */
                fprintf(pidf, "%d\n", getpid());
                fprintf(pidf, "%d\n", getpid());
+
+               /* line 2 contains all command line flags */
+               fprintf(pidf, "%s\n", CommandLineArgs);
+
+               /* flush and close */
                fclose(pidf);
        }
 
                fclose(pidf);
        }
 
@@ -175,7 +212,7 @@ getrequests()
 **             none.
 */
 
 **             none.
 */
 
-struct sockaddr_in     CurHostAddr;            /* address of current host */
+SOCKADDR       CurHostAddr;            /* address of current host */
 
 int
 makeconnection(host, port, mci, usesecureport)
 
 int
 makeconnection(host, port, mci, usesecureport)
@@ -186,9 +223,9 @@ makeconnection(host, port, mci, usesecureport)
 {
        register int i, s;
        register struct hostent *hp = (struct hostent *)NULL;
 {
        register int i, s;
        register struct hostent *hp = (struct hostent *)NULL;
-       struct sockaddr_in addr;
+       SOCKADDR addr;
        int sav_errno;
        int sav_errno;
-       extern char *inet_ntoa();
+       int addrlen;
 #ifdef NAMED_BIND
        extern int h_errno;
 #endif
 #ifdef NAMED_BIND
        extern int h_errno;
 #endif
@@ -202,6 +239,8 @@ makeconnection(host, port, mci, usesecureport)
        h_errno = 0;
 #endif
        errno = 0;
        h_errno = 0;
 #endif
        errno = 0;
+       bzero(&CurHostAddr, sizeof CurHostAddr);
+       CurHostName = host;
 
        if (host[0] == '[')
        {
 
        if (host[0] == '[')
        {
@@ -211,8 +250,10 @@ makeconnection(host, port, mci, usesecureport)
                if (p != NULL)
                {
                        *p = '\0';
                if (p != NULL)
                {
                        *p = '\0';
+#ifdef NETINET
                        hid = inet_addr(&host[1]);
                        if (hid == -1)
                        hid = inet_addr(&host[1]);
                        if (hid == -1)
+#endif
                        {
                                /* try it as a host name (avoid MX lookup) */
                                hp = gethostbyname(&host[1]);
                        {
                                /* try it as a host name (avoid MX lookup) */
                                hp = gethostbyname(&host[1]);
@@ -226,7 +267,10 @@ makeconnection(host, port, mci, usesecureport)
                        usrerr("553 Invalid numeric domain spec \"%s\"", host);
                        return (EX_NOHOST);
                }
                        usrerr("553 Invalid numeric domain spec \"%s\"", host);
                        return (EX_NOHOST);
                }
-               addr.sin_addr.s_addr = hid;
+#ifdef NETINET
+               addr.sin.sin_family = AF_INET;          /*XXX*/
+               addr.sin.sin_addr.s_addr = hid;
+#endif
        }
        else
        {
        }
        else
        {
@@ -244,7 +288,23 @@ gothostent:
 #endif
                        return (EX_NOHOST);
                }
 #endif
                        return (EX_NOHOST);
                }
-               bcopy(hp->h_addr, (char *) &addr.sin_addr, hp->h_length);
+               addr.sa.sa_family = hp->h_addrtype;
+               switch (hp->h_addrtype)
+               {
+#ifdef NETINET
+                 case AF_INET:
+                       bcopy(hp->h_addr,
+                               &addr.sin.sin_addr,
+                               hp->h_length);
+                       break;
+#endif
+
+                 default:
+                       bcopy(hp->h_addr,
+                               addr.sa.sa_data,
+                               hp->h_length);
+                       break;
+               }
                i = 1;
        }
 
                i = 1;
        }
 
@@ -253,28 +313,56 @@ gothostent:
        */
 
        if (port != 0)
        */
 
        if (port != 0)
-               addr.sin_port = htons(port);
+               port = htons(port);
        else
        {
                register struct servent *sp = getservbyname("smtp", "tcp");
 
                if (sp == NULL)
                {
        else
        {
                register struct servent *sp = getservbyname("smtp", "tcp");
 
                if (sp == NULL)
                {
-                       syserr("554 makeconnection: server \"smtp\" unknown");
+                       syserr("554 makeconnection: service \"smtp\" unknown");
                        return (EX_OSERR);
                }
                        return (EX_OSERR);
                }
-               addr.sin_port = sp->s_port;
+               port = sp->s_port;
+       }
+
+       switch (addr.sa.sa_family)
+       {
+#ifdef NETINET
+         case AF_INET:
+               addr.sin.sin_port = port;
+               addrlen = sizeof (struct sockaddr_in);
+               break;
+#endif
+
+#ifdef NETISO
+         case AF_ISO:
+               /* assume two byte transport selector */
+               bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
+               addrlen = sizeof (struct sockaddr_iso);
+               break;
+#endif
+
+         default:
+               syserr("Can't connect to address family %d", addr.sa.sa_family);
+               return (EX_NOHOST);
        }
 
        /*
        **  Try to actually open the connection.
        */
 
        }
 
        /*
        **  Try to actually open the connection.
        */
 
+#ifdef XLA
+       /* if too many connections, don't bother trying */
+       if (!xla_noqueue_ok(host))
+               return EX_TEMPFAIL;
+#endif
+
        for (;;)
        {
                if (tTd(16, 1))
        for (;;)
        {
                if (tTd(16, 1))
-                       printf("makeconnection (%s [%s])\n", host,
-                           inet_ntoa(addr.sin_addr));
+                       printf("makeconnection (%s [%s])\n",
+                               host, anynet_ntoa(&addr));
 
                /* save for logging */
                CurHostAddr = addr;
 
                /* save for logging */
                CurHostAddr = addr;
@@ -309,8 +397,7 @@ gothostent:
                if (CurEnv->e_xfp != NULL)
                        (void) fflush(CurEnv->e_xfp);           /* for debugging */
                errno = 0;                                      /* for debugging */
                if (CurEnv->e_xfp != NULL)
                        (void) fflush(CurEnv->e_xfp);           /* for debugging */
                errno = 0;                                      /* for debugging */
-               addr.sin_family = AF_INET;
-               if (connect(s, (struct sockaddr *) &addr, sizeof addr) >= 0)
+               if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
                        break;
 
                /* couldn't connect.... figure out why */
                        break;
 
                /* couldn't connect.... figure out why */
@@ -319,27 +406,36 @@ gothostent:
                if (hp && hp->h_addr_list[i])
                {
                        if (tTd(16, 1))
                if (hp && hp->h_addr_list[i])
                {
                        if (tTd(16, 1))
-                               printf("Connect failed; trying new address....\n");
-                       bcopy(hp->h_addr_list[i++], (char *) &addr.sin_addr,
+                               printf("Connect failed (%s); trying new address....\n",
+                                       errstring(sav_errno));
+                       switch (addr.sa.sa_family)
+                       {
+#ifdef NETINET
+                         case AF_INET:
+                               bcopy(hp->h_addr_list[i++],
+                                     &addr.sin.sin_addr,
+                                     hp->h_length);
+                               break;
+#endif
+
+                         default:
+                               bcopy(hp->h_addr_list[i++],
+                                       addr.sa.sa_data,
                                        hp->h_length);
                                        hp->h_length);
+                               break;
+                       }
                        continue;
                }
 
                /* failure, decide if temporary or not */
        failure:
                        continue;
                }
 
                /* failure, decide if temporary or not */
        failure:
+#ifdef XLA
+               xla_host_end(host);
+#endif
                if (transienterror(sav_errno))
                        return EX_TEMPFAIL;
                if (transienterror(sav_errno))
                        return EX_TEMPFAIL;
-               else if (sav_errno == EPERM)
-               {
-                       /* why is this happening? */
-                       syserr("makeconnection: funny failure, addr=%lx, port=%x",
-                               addr.sin_addr.s_addr, addr.sin_port);
-                       return (EX_TEMPFAIL);
-               }
                else
                {
                else
                {
-                       extern char *errstring();
-
                        message("%s", errstring(sav_errno));
                        return (EX_UNAVAILABLE);
                }
                        message("%s", errstring(sav_errno));
                        return (EX_UNAVAILABLE);
                }
@@ -404,51 +500,198 @@ myhostname(hostbuf, size)
                return (NULL);
 }
 \f/*
                return (NULL);
 }
 \f/*
-**  GETREALHOSTNAME -- get the real host name asociated with a file descriptor
+**  GETAUTHINFO -- get the real host name asociated with a file descriptor
+**
+**     Uses RFC1413 protocol to try to get info from the other end.
 **
 **     Parameters:
 **             fd -- the descriptor
 **
 **     Returns:
 **
 **     Parameters:
 **             fd -- the descriptor
 **
 **     Returns:
-**             The host name associated with this descriptor, if it can
-**                     be determined.
-**             NULL otherwise.
+**             The user@host information associated with this descriptor.
 **
 **     Side Effects:
 **
 **     Side Effects:
-**             none
+**             Sets RealHostName to the name of the host at the other end.
 */
 
 */
 
+#ifdef IDENTPROTO
+
+static jmp_buf CtxAuthTimeout;
+
+static
+authtimeout()
+{
+       longjmp(CtxAuthTimeout, 1);
+}
+
+#endif
+
 char *
 char *
-getrealhostname(fd)
+getauthinfo(fd)
        int fd;
 {
        int fd;
 {
-       register struct hostent *hp;
-       struct sockaddr_in sin;
-       int sinlen;
-       char hbuf[MAXNAME];
-       extern struct hostent *gethostbyaddr();
-       extern char *inet_ntoa();
+       SOCKADDR fa;
+       int falen;
+       register char *p;
+#ifdef IDENTPROTO
+       SOCKADDR la;
+       int lalen;
+       register struct servent *sp;
+       int s;
+       int i;
+       EVENT *ev;
+#endif
+       static char hbuf[MAXNAME * 2 + 2];
+       extern char *hostnamebyanyaddr();
+       extern char RealUserName[];                     /* main.c */
 
 
-       if (getsockname(fd, (struct sockaddr *) &sin, &sinlen) < 0 ||
-           sinlen <= 0)
-               return NULL;
-       hp = gethostbyaddr((char *) &sin.sin_addr, sizeof sin.sin_addr,
-                          sin.sin_family);
-       if (hp != NULL)
-               (void) strcpy(hbuf, hp->h_name);
+       falen = sizeof fa;
+       if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0)
+       {
+               RealHostName = "localhost";
+               (void) sprintf(hbuf, "%s@localhost", RealUserName);
+               if (tTd(9, 1))
+                       printf("getauthinfo: %s\n", hbuf);
+               return hbuf;
+       }
+
+       RealHostName = newstr(hostnamebyanyaddr(&fa));
+       RealHostAddr = fa;
+
+#ifdef IDENTPROTO
+       lalen = sizeof la;
+       if (fa.sa.sa_family != AF_INET ||
+           getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
+           la.sa.sa_family != AF_INET)
+       {
+               /* no ident info */
+               goto noident;
+       }
+
+       /* create ident query */
+       (void) sprintf(hbuf, "%d,%d\r\n",
+               ntohs(fa.sin.sin_port), ntohs(la.sin.sin_port));
+
+       /* create local address */
+       bzero(&la, sizeof la);
+
+       /* create foreign address */
+       sp = getservbyname("auth", "tcp");
+       if (sp != NULL)
+               fa.sin.sin_port = sp->s_port;
        else
        else
-               (void) sprintf(hbuf, "[%s]", inet_ntoa(sin.sin_addr));
+               fa.sin.sin_port = htons(113);
+
+       s = -1;
+       if (setjmp(CtxAuthTimeout) != 0)
+       {
+               if (s >= 0)
+                       (void) close(s);
+               goto noident;
+       }
+
+       /* put a timeout around the whole thing */
+       ev = setevent((time_t) 30, authtimeout, 0);
+
+       /* connect to foreign IDENT server */
+       s = socket(AF_INET, SOCK_STREAM, 0);
+       if (s < 0)
+       {
+               clrevent(ev);
+               goto noident;
+       }
+       if (connect(s, &fa.sa, sizeof fa.sin) < 0)
+       {
+closeident:
+               (void) close(s);
+               clrevent(ev);
+               goto noident;
+       }
+
+       if (tTd(9, 10))
+               printf("getauthinfo: sent %s", hbuf);
+
+       /* send query */
+       if (write(s, hbuf, strlen(hbuf)) < 0)
+               goto closeident;
+
+       /* get result */
+       i = read(s, hbuf, sizeof hbuf);
+       (void) close(s);
+       clrevent(ev);
+       if (i <= 0)
+               goto noident;
+       if (hbuf[--i] == '\n' && hbuf[--i] == '\r')
+               i--;
+       hbuf[++i] = '\0';
+
+       if (tTd(9, 3))
+               printf("getauthinfo:  got %s\n", hbuf);
+
+       /* parse result */
+       p = strchr(hbuf, ':');
+       if (p == NULL)
+       {
+               /* malformed response */
+               goto noident;
+       }
+       while (isascii(*++p) && isspace(*p))
+               continue;
+       if (strncasecmp(p, "userid", 6) != 0)
+       {
+               /* presumably an error string */
+               goto noident;
+       }
+       p += 6;
+       while (isascii(*p) && isspace(*p))
+               p++;
+       if (*p++ != ':')
+       {
+               /* either useridxx or malformed response */
+               goto noident;
+       }
+
+       /* p now points to the OSTYPE field */
+       p = strchr(p, ':');
+       if (p == NULL)
+       {
+               /* malformed response */
+               goto noident;
+       }
+
+       /* 1413 says don't do this -- but it's broken otherwise */
+       while (isascii(*++p) && isspace(*p))
+               continue;
+
+       /* p now points to the authenticated name */
+       (void) sprintf(hbuf, "%s@%s", p, RealHostName);
+       goto finish;
+
+#endif /* IDENTPROTO */
+
+noident:
+       (void) strcpy(hbuf, RealHostName);
+
+finish:
+       if (RealHostName[0] != '[')
+       {
+               p = &hbuf[strlen(hbuf)];
+               (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr));
+       }
+       if (tTd(9, 1))
+               printf("getauthinfo: %s\n", hbuf);
        return hbuf;
 }
 \f/*
        return hbuf;
 }
 \f/*
-**  MAPHOSTNAME -- turn a hostname into canonical form
+**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
 **
 **     Parameters:
 **             map -- a pointer to this map (unused).
 **
 **     Parameters:
 **             map -- a pointer to this map (unused).
-**             hbuf -- a buffer containing a hostname.
-**             hbsize -- the size of hbuf.
-**             avp -- unused -- for compatibility with other mapping
+**             name -- the (presumably unqualified) hostname.
+**             av -- unused -- for compatibility with other mapping
 **                     functions.
 **                     functions.
+**             statp -- an exit status (out parameter) -- set to
+**                     EX_TEMPFAIL if the name server is unavailable.
 **
 **     Returns:
 **             The mapping, if found.
 **
 **     Returns:
 **             The mapping, if found.
@@ -461,63 +704,260 @@ getrealhostname(fd)
 */
 
 char *
 */
 
 char *
-maphostname(map, hbuf, hbsize, avp)
+host_map_lookup(map, name, av, statp)
        MAP *map;
        MAP *map;
-       char *hbuf;
-       int hbsize;
-       char **avp;
+       char *name;
+       char **av;
+       int *statp;
 {
        register struct hostent *hp;
        u_long in_addr;
        char *cp;
        int i;
 {
        register struct hostent *hp;
        u_long in_addr;
        char *cp;
        int i;
-       struct hostent *gethostbyaddr();
+       register STAB *s;
+       char hbuf[MAXNAME];
+       extern struct hostent *gethostbyaddr();
+       extern int h_errno;
+
+       /*
+       **  See if we have already looked up this name.  If so, just
+       **  return it.
+       */
 
 
-       /* allow room for null */
-       hbsize--;
+       s = stab(name, ST_NAMECANON, ST_ENTER);
+       if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
+       {
+               if (tTd(9, 1))
+                       printf("host_map_lookup(%s) => CACHE %s\n",
+                               name, s->s_namecanon.nc_cname);
+               errno = s->s_namecanon.nc_errno;
+               h_errno = s->s_namecanon.nc_herrno;
+               *statp = s->s_namecanon.nc_stat;
+               return s->s_namecanon.nc_cname;
+       }
 
        /*
 
        /*
-        * If first character is a bracket, then it is an address
-        * lookup.  Address is copied into a temporary buffer to
-        * strip the brackets and to preserve hbuf if address is
-        * unknown.
-        */
+       **  If first character is a bracket, then it is an address
+       **  lookup.  Address is copied into a temporary buffer to
+       **  strip the brackets and to preserve name if address is
+       **  unknown.
+       */
 
 
-       if (*hbuf != '[')
+       if (*name != '[')
        {
                extern bool getcanonname();
 
        {
                extern bool getcanonname();
 
-               if (getcanonname(hbuf, hbsize))
-                       return hbuf;
+               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 (tTd(9, 1))
+                               printf("%s\n", hbuf);
+                       cp = map_rewrite(map, hbuf, strlen(hbuf), av);
+                       s->s_namecanon.nc_cname = newstr(cp);
+                       return cp;
+               }
                else
                else
-                       return NULL;
+               {
+                       register struct hostent *hp;
+
+                       if (tTd(9, 1))
+                               printf("FAIL (%d)\n", h_errno);
+                       s->s_namecanon.nc_errno = errno;
+                       s->s_namecanon.nc_herrno = h_errno;
+                       switch (h_errno)
+                       {
+                         case TRY_AGAIN:
+                               if (UseNameServer)
+                               {
+                                       char *msg = "Recipient domain nameserver timed out";
+
+                                       message(msg);
+                                       if (CurEnv->e_message == NULL)
+                                               CurEnv->e_message = newstr(msg);
+                               }
+                               *statp = EX_TEMPFAIL;
+                               break;
+
+                         case HOST_NOT_FOUND:
+                               *statp = EX_NOHOST;
+                               break;
+
+                         case NO_RECOVERY:
+                               *statp = EX_SOFTWARE;
+                               break;
+
+                         default:
+                               *statp = EX_UNAVAILABLE;
+                               break;
+                       }
+                       s->s_namecanon.nc_stat = *statp;
+                       if (*statp != EX_TEMPFAIL || UseNameServer)
+                               return NULL;
+
+                       /*
+                       **  Try to look it up in /etc/hosts
+                       */
+
+                       hp = gethostbyname(name);
+                       if (hp == NULL)
+                       {
+                               /* no dice there either */
+                               s->s_namecanon.nc_stat = *statp = EX_NOHOST;
+                               return NULL;
+                       }
+
+                       s->s_namecanon.nc_stat = *statp = EX_OK;
+                       cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
+                       s->s_namecanon.nc_cname = newstr(cp);
+                       return cp;
+               }
        }
        }
-       if ((cp = strchr(hbuf, ']')) == NULL)
+       if ((cp = strchr(name, ']')) == NULL)
                return (NULL);
        *cp = '\0';
                return (NULL);
        *cp = '\0';
-       in_addr = inet_addr(&hbuf[1]);
+       in_addr = inet_addr(&name[1]);
 
        /* check to see if this is one of our addresses */
        for (i = 0; MyIpAddrs[i].s_addr != 0; i++)
        {
                if (MyIpAddrs[i].s_addr == in_addr)
                {
 
        /* check to see if this is one of our addresses */
        for (i = 0; MyIpAddrs[i].s_addr != 0; i++)
        {
                if (MyIpAddrs[i].s_addr == in_addr)
                {
-                       strncpy(hbuf, MyHostName, hbsize);
-                       hbuf[hbsize] = '\0';
-                       return hbuf;
+                       return map_rewrite(map, MyHostName, strlen(MyHostName), av);
                }
        }
 
        /* nope -- ask the name server */
        hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
                }
        }
 
        /* nope -- ask the name server */
        hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
+       s->s_namecanon.nc_errno = errno;
+       s->s_namecanon.nc_herrno = h_errno;
+       s->s_namecanon.nc_flags |= NCF_VALID;           /* will be soon */
        if (hp == NULL)
        if (hp == NULL)
+       {
+               s->s_namecanon.nc_stat = *statp = EX_NOHOST;
                return (NULL);
                return (NULL);
+       }
 
        /* found a match -- copy out */
 
        /* found a match -- copy out */
-       if (strlen(hp->h_name) > hbsize)
-               hp->h_name[hbsize] = '\0';
-       (void) strcpy(hbuf, hp->h_name);
-       return hbuf;
+       cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
+       s->s_namecanon.nc_stat = *statp = EX_OK;
+       s->s_namecanon.nc_cname = newstr(cp);
+       return cp;
+}
+\f/*
+**  ANYNET_NTOA -- convert a network address to printable form.
+**
+**     Parameters:
+**             sap -- a pointer to a sockaddr structure.
+**
+**     Returns:
+**             A printable version of that sockaddr.
+*/
+
+char *
+anynet_ntoa(sap)
+       register SOCKADDR *sap;
+{
+       register char *bp;
+       register char *ap;
+       int l;
+       static char buf[80];
+
+       /* check for null/zero family */
+       if (sap == NULL)
+               return "NULLADDR";
+       if (sap->sa.sa_family == 0)
+               return "0";
+
+#ifdef NETINET
+       if (sap->sa.sa_family == AF_INET)
+       {
+               extern char *inet_ntoa();
+
+               return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr);
+       }
+#endif
+
+       /* unknown family -- just dump bytes */
+       (void) sprintf(buf, "Family %d: ", sap->sa.sa_family);
+       bp = &buf[strlen(buf)];
+       ap = sap->sa.sa_data;
+       for (l = sizeof sap->sa.sa_data; --l >= 0; )
+       {
+               (void) sprintf(bp, "%02x:", *ap++ & 0377);
+               bp += 3;
+       }
+       *--bp = '\0';
+       return buf;
+}
+\f/*
+**  HOSTNAMEBYANYADDR -- return name of host based on address
+**
+**     Parameters:
+**             sap -- SOCKADDR pointer
+**
+**     Returns:
+**             text representation of host name.
+**
+**     Side Effects:
+**             none.
+*/
+
+char *
+hostnamebyanyaddr(sap)
+       register SOCKADDR *sap;
+{
+       register struct hostent *hp;
+
+#ifdef NAMED_BIND
+       int saveretry;
+
+       /* shorten name server timeout to avoid higher level timeouts */
+       saveretry = _res.retry;
+       _res.retry = 3;
+#endif /* NAMED_BIND */
+
+       switch (sap->sa.sa_family)
+       {
+#ifdef NETINET
+         case AF_INET:
+               hp = gethostbyaddr((char *) &sap->sin.sin_addr,
+                       sizeof sap->sin.sin_addr,
+                       AF_INET);
+               break;
+#endif
+
+#ifdef NETISO
+         case AF_ISO:
+               hp = gethostbyaddr((char *) &sap->siso.siso_addr,
+                       sizeof sap->siso.siso_addr,
+                       AF_ISO);
+               break;
+#endif
+
+         default:
+               hp = gethostbyaddr(sap->sa.sa_data,
+                          sizeof sap->sa.sa_data,
+                          sap->sa.sa_family);
+               break;
+       }
+
+#ifdef NAMED_BIND
+       _res.retry = saveretry;
+#endif /* NAMED_BIND */
+
+       if (hp != NULL)
+               return hp->h_name;
+       else
+       {
+               /* produce a dotted quad */
+               static char buf[512];
+
+               (void) sprintf(buf, "[%s]", anynet_ntoa(sap));
+               return buf;
+       }
 }
 
 # else /* DAEMON */
 }
 
 # else /* DAEMON */
@@ -549,7 +989,7 @@ myhostname(hostbuf, size)
        return (NULL);
 }
 \f/*
        return (NULL);
 }
 \f/*
-**  GETREALHOSTNAME -- get the real host name asociated with a file descriptor
+**  GETAUTHINFO -- get the real host name asociated with a file descriptor
 **
 **     Parameters:
 **             fd -- the descriptor
 **
 **     Parameters:
 **             fd -- the descriptor
@@ -564,7 +1004,7 @@ myhostname(hostbuf, size)
 */
 
 char *
 */
 
 char *
-getrealhostname(fd)
+getauthinfo(fd)
        int fd;
 {
        return NULL;
        int fd;
 {
        return NULL;
@@ -574,15 +1014,16 @@ getrealhostname(fd)
 **
 **     Parameters:
 **             map -- a pointer to the database map.
 **
 **     Parameters:
 **             map -- a pointer to the database map.
-**             hbuf -- a buffer containing a hostname.
+**             name -- a buffer containing a hostname.
 **             avp -- a pointer to a (cf file defined) argument vector.
 **             avp -- a pointer to a (cf file defined) argument vector.
+**             statp -- an exit status (out parameter).
 **
 **     Returns:
 **             mapped host name
 **             FALSE otherwise.
 **
 **     Side Effects:
 **
 **     Returns:
 **             mapped host name
 **             FALSE otherwise.
 **
 **     Side Effects:
-**             Looks up the host specified in hbuf.  If it is not
+**             Looks up the host specified in name.  If it is not
 **             the canonical name for that host, replace it with
 **             the canonical name.  If the name is unknown, or it
 **             is already the canonical name, leave it unchanged.
 **             the canonical name for that host, replace it with
 **             the canonical name.  If the name is unknown, or it
 **             is already the canonical name, leave it unchanged.
@@ -590,12 +1031,18 @@ getrealhostname(fd)
 
 /*ARGSUSED*/
 char *
 
 /*ARGSUSED*/
 char *
-maphostname(map, hbuf, hbsize, avp)
+host_map_lookup(map, name, avp, statp)
        MAP *map;
        MAP *map;
-       char *hbuf;
-       int hbsize;
+       char *name;
        char **avp;
        char **avp;
+       char *statp;
 {
 {
+       register struct hostent *hp;
+
+       hp = gethostbyname(name);
+       if (hp != NULL)
+               return hp->h_name;
+       *statp = EX_NOHOST;
        return NULL;
 }
 
        return NULL;
 }