signal and file locking portability changes
[unix-history] / usr / src / usr.sbin / sendmail / src / daemon.c
index 505b1b4..20fbd0e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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%
  */
  *
  * %sccs.include.redist.c%
  */
 
 #ifndef lint
 #ifdef DAEMON
 
 #ifndef lint
 #ifdef DAEMON
-static char sccsid[] = "@(#)daemon.c   5.39 (Berkeley) %G% (with daemon mode)";
+static char sccsid[] = "@(#)daemon.c   8.5 (Berkeley) %G% (with daemon mode)";
 #else
 #else
-static char sccsid[] = "@(#)daemon.c   5.39 (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 */
 
-int la;        /* load average */
-
 #ifdef DAEMON
 
 # include <netdb.h>
 #ifdef DAEMON
 
 # include <netdb.h>
-# include <sys/signal.h>
 # include <sys/wait.h>
 # include <sys/time.h>
 # include <sys/wait.h>
 # include <sys/time.h>
-# include <sys/resource.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.
@@ -48,15 +49,14 @@ int la;     /* load average */
 **             etc., to avoid having extra file descriptors during
 **             the queue run and to avoid confusing the network
 **             code (if it cares).
 **             etc., to avoid having extra file descriptors during
 **             the queue run and to avoid confusing the network
 **             code (if it cares).
-**     makeconnection(host, port, outfile, infile)
+**     makeconnection(host, port, outfile, infile, usesecureport)
 **             Make a connection to the named host on the given
 **             port.  Set *outfile and *infile to the files
 **             appropriate for communication.  Returns zero on
 **             success, else an exit status describing the
 **             error.
 **             Make a connection to the named host on the given
 **             port.  Set *outfile and *infile to the files
 **             appropriate for communication.  Returns zero on
 **             success, else an exit status describing the
 **             error.
-**     maphostname(hbuf, hbufsize)
-**             Convert the entry in hbuf into a canonical form.  It
-**             may not be larger than hbufsize.
+**     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 */
 */
 
 static FILE    *MailPort;      /* port that mail comes in on */
@@ -78,41 +78,47 @@ static FILE *MailPort;      /* port that mail comes in on */
 **             to the communication channel.
 */
 
 **             to the communication channel.
 */
 
-struct sockaddr_in     SendmailAddress;/* internet address of sendmail */
-
-int    DaemonSocket    = -1;           /* fd describing socket */
-char   *NetName;                       /* name of home (local?) network */
+int            DaemonSocket    = -1;           /* fd describing socket */
+SOCKADDR       DaemonAddr;                     /* socket for incoming */
+int            ListenQueueSize = 10;           /* size of listen queue */
 
 getrequests()
 {
        int t;
        register struct servent *sp;
        int on = 1;
 
 getrequests()
 {
        int t;
        register struct servent *sp;
        int on = 1;
+       bool refusingconnections = TRUE;
+       FILE *pidf;
        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("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;
        }
        }
-       SendmailAddress.sin_family = AF_INET;
-       SendmailAddress.sin_addr.s_addr = INADDR_ANY;
-       SendmailAddress.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", SendmailAddress.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 */
@@ -120,32 +126,61 @@ getrequests()
          severe:
 # ifdef LOG
                if (LogLevel > 0)
          severe:
 # ifdef LOG
                if (LogLevel > 0)
-# endif LOG
+# endif /* LOG */
                finis();
        }
 
        /* turn on network debugging? */
                finis();
        }
 
        /* turn on network debugging? */
-       if (tTd(15, 15))
+       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);
 
                (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);
 
-       if (bind(DaemonSocket,
-           (struct sockaddr *)&SendmailAddress, sizeof SendmailAddress) < 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;
        }
-       if (listen(DaemonSocket, 10) < 0)
+
+       (void) setsignal(SIGCHLD, reapchild);
+
+       /* write the pid to the log file for posterity */
+       pidf = fopen(PidFile, "w");
+       if (pidf != NULL)
        {
        {
-               syserr("getrequests: cannot listen");
-               (void) close(DaemonSocket);
-               goto severe;
+               extern char *CommandLineArgs;
+
+               /* write the process id on line 1 */
+               fprintf(pidf, "%d\n", getpid());
+
+               /* line 2 contains all command line flags */
+               fprintf(pidf, "%s\n", CommandLineArgs);
+
+               /* flush and close */
+               fclose(pidf);
        }
 
        }
 
-       (void) signal(SIGCHLD, reapchild);
 
        if (tTd(15, 1))
                printf("getrequests: %d\n", DaemonSocket);
 
        if (tTd(15, 1))
                printf("getrequests: %d\n", DaemonSocket);
@@ -164,9 +199,10 @@ getrequests()
 **     Parameters:
 **             host -- the name of the host.
 **             port -- the port number to connect to.
 **     Parameters:
 **             host -- the name of the host.
 **             port -- the port number to connect to.
-**             outfile -- a pointer to a place to put the outfile
-**                     descriptor.
-**             infile -- ditto for infile.
+**             mci -- a pointer to the mail connection information
+**                     structure to be filled in.
+**             usesecureport -- if set, use a low numbered (reserved)
+**                     port to provide some rudimentary authentication.
 **
 **     Returns:
 **             An exit code telling whether the connection could be
 **
 **     Returns:
 **             An exit code telling whether the connection could be
@@ -176,16 +212,20 @@ getrequests()
 **             none.
 */
 
 **             none.
 */
 
-makeconnection(host, port, outfile, infile)
+SOCKADDR       CurHostAddr;            /* address of current host */
+
+int
+makeconnection(host, port, mci, usesecureport)
        char *host;
        u_short port;
        char *host;
        u_short port;
-       FILE **outfile;
-       FILE **infile;
+       register MCI *mci;
+       bool usesecureport;
 {
        register int i, s;
        register struct hostent *hp = (struct hostent *)NULL;
 {
        register int i, s;
        register struct hostent *hp = (struct hostent *)NULL;
-       extern char *inet_ntoa();
+       SOCKADDR addr;
        int sav_errno;
        int sav_errno;
+       int addrlen;
 #ifdef NAMED_BIND
        extern int h_errno;
 #endif
 #ifdef NAMED_BIND
        extern int h_errno;
 #endif
@@ -199,28 +239,43 @@ makeconnection(host, port, outfile, infile)
        h_errno = 0;
 #endif
        errno = 0;
        h_errno = 0;
 #endif
        errno = 0;
+       bzero(&CurHostAddr, sizeof CurHostAddr);
+       CurHostName = host;
 
        if (host[0] == '[')
        {
                long hid;
 
        if (host[0] == '[')
        {
                long hid;
-               register char *p = index(host, ']');
+               register char *p = strchr(host, ']');
 
                if (p != NULL)
                {
                        *p = '\0';
 
                if (p != NULL)
                {
                        *p = '\0';
+#ifdef NETINET
                        hid = inet_addr(&host[1]);
                        hid = inet_addr(&host[1]);
+                       if (hid == -1)
+#endif
+                       {
+                               /* try it as a host name (avoid MX lookup) */
+                               hp = gethostbyname(&host[1]);
+                               *p = ']';
+                               goto gothostent;
+                       }
                        *p = ']';
                }
                        *p = ']';
                }
-               if (p == NULL || hid == -1)
+               if (p == NULL)
                {
                {
-                       usrerr("Invalid numeric domain spec \"%s\"", host);
+                       usrerr("553 Invalid numeric domain spec \"%s\"", host);
                        return (EX_NOHOST);
                }
                        return (EX_NOHOST);
                }
-               SendmailAddress.sin_addr.s_addr = hid;
+#ifdef NETINET
+               addr.sin.sin_family = AF_INET;          /*XXX*/
+               addr.sin.sin_addr.s_addr = hid;
+#endif
        }
        else
        {
                hp = gethostbyname(host);
        }
        else
        {
                hp = gethostbyname(host);
+gothostent:
                if (hp == NULL)
                {
 #ifdef NAMED_BIND
                if (hp == NULL)
                {
 #ifdef NAMED_BIND
@@ -231,15 +286,25 @@ makeconnection(host, port, outfile, infile)
                        if (errno == ECONNREFUSED && UseNameServer)
                                return (EX_TEMPFAIL);
 #endif
                        if (errno == ECONNREFUSED && UseNameServer)
                                return (EX_TEMPFAIL);
 #endif
-
-                       /*
-                       **  XXX Should look for mail forwarder record here
-                       **  XXX if (h_errno == NO_ADDRESS).
-                       */
-
                        return (EX_NOHOST);
                }
                        return (EX_NOHOST);
                }
-               bcopy(hp->h_addr, (char *) &SendmailAddress.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;
        }
 
@@ -248,109 +313,137 @@ makeconnection(host, port, outfile, infile)
        */
 
        if (port != 0)
        */
 
        if (port != 0)
-               SendmailAddress.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("makeconnection: server \"smtp\" unknown");
-                       return (EX_OSFILE);
+                       syserr("554 makeconnection: service \"smtp\" unknown");
+                       return (EX_OSERR);
                }
                }
-               SendmailAddress.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.
        */
 
-again:
-       if (tTd(16, 1))
-               printf("makeconnection (%s [%s])\n", host,
-                   inet_ntoa(SendmailAddress.sin_addr));
+#ifdef XLA
+       /* if too many connections, don't bother trying */
+       if (!xla_noqueue_ok(host))
+               return EX_TEMPFAIL;
+#endif
 
 
-#ifdef NVMUNIX
-       s = socket(AF_INET, SOCK_STREAM, 0, 0);
-#else NVMUNIX
-       s = socket(AF_INET, SOCK_STREAM, 0);
-#endif NVMUNIX
-       if (s < 0)
+       for (;;)
        {
        {
-               syserr("makeconnection: no socket");
-               sav_errno = errno;
-               goto failure;
-       }
+               if (tTd(16, 1))
+                       printf("makeconnection (%s [%s])\n",
+                               host, anynet_ntoa(&addr));
 
 
-       if (tTd(16, 1))
-               printf("makeconnection: %d\n", s);
+               /* save for logging */
+               CurHostAddr = addr;
 
 
-       /* turn on network debugging? */
-       if (tTd(16, 14))
-       {
-               int on = 1;
-               (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on);
-       }
-       if (CurEnv->e_xfp != NULL)
-               (void) fflush(CurEnv->e_xfp);           /* for debugging */
-       errno = 0;                                      /* for debugging */
-#ifdef NVMUNIX
-       bind(s, &SendmailAddress, sizeof SendmailAddress, 0);
-       if (connect(s, &SendmailAddress, sizeof SendmailAddress, 0) < 0)
-#else NVMUNIX
-       SendmailAddress.sin_family = AF_INET;
-       if (connect(s,
-           (struct sockaddr *)&SendmailAddress, sizeof SendmailAddress) < 0)
-#endif NVMUNIX
-       {
+               if (usesecureport)
+               {
+                       int rport = IPPORT_RESERVED - 1;
+
+                       s = rresvport(&rport);
+               }
+               else
+               {
+                       s = socket(AF_INET, SOCK_STREAM, 0);
+               }
+               if (s < 0)
+               {
+                       sav_errno = errno;
+                       syserr("makeconnection: no socket");
+                       goto failure;
+               }
+
+               if (tTd(16, 1))
+                       printf("makeconnection: fd=%d\n", s);
+
+               /* turn on network debugging? */
+               if (tTd(16, 101))
+               {
+                       int on = 1;
+                       (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG,
+                                         (char *)&on, sizeof on);
+               }
+               if (CurEnv->e_xfp != NULL)
+                       (void) fflush(CurEnv->e_xfp);           /* for debugging */
+               errno = 0;                                      /* for debugging */
+               if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0)
+                       break;
+
+               /* couldn't connect.... figure out why */
                sav_errno = errno;
                (void) close(s);
                if (hp && hp->h_addr_list[i])
                {
                sav_errno = errno;
                (void) close(s);
                if (hp && hp->h_addr_list[i])
                {
-                       bcopy(hp->h_addr_list[i++],
-                           (char *)&SendmailAddress.sin_addr, hp->h_length);
-                       goto again;
+                       if (tTd(16, 1))
+                               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);
+                               break;
+                       }
+                       continue;
                }
 
                /* failure, decide if temporary or not */
        failure:
                }
 
                /* failure, decide if temporary or not */
        failure:
-               switch (sav_errno)
+#ifdef XLA
+               xla_host_end(host);
+#endif
+               if (transienterror(sav_errno))
+                       return EX_TEMPFAIL;
+               else
                {
                {
-                 case EISCONN:
-                 case ETIMEDOUT:
-                 case EINPROGRESS:
-                 case EALREADY:
-                 case EADDRINUSE:
-                 case EHOSTDOWN:
-                 case ENETDOWN:
-                 case ENETRESET:
-                 case ENOBUFS:
-                 case ECONNREFUSED:
-                 case ECONNRESET:
-                 case EHOSTUNREACH:
-                 case ENETUNREACH:
-                       /* there are others, I'm sure..... */
-                       return (EX_TEMPFAIL);
-
-                 case EPERM:
-                       /* why is this happening? */
-                       syserr("makeconnection: funny failure, addr=%lx, port=%x",
-                               SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port);
-                       return (EX_TEMPFAIL);
-
-                 default:
-                       {
-                               extern char *errstring();
-
-                               message(Arpa_Info, "%s", errstring(sav_errno));
-                               return (EX_UNAVAILABLE);
-                       }
+                       message("%s", errstring(sav_errno));
+                       return (EX_UNAVAILABLE);
                }
        }
 
        /* connection ok, put it into canonical form */
                }
        }
 
        /* connection ok, put it into canonical form */
-       *outfile = fdopen(s, "w");
-       *infile = fdopen(dup(s), "r");
+       mci->mci_out = fdopen(s, "w");
+       mci->mci_in = fdopen(dup(s), "r");
 
        return (EX_OK);
 }
 
        return (EX_OK);
 }
@@ -365,16 +458,18 @@ again:
 **             A list of aliases for this host.
 **
 **     Side Effects:
 **             A list of aliases for this host.
 **
 **     Side Effects:
-**             none.
+**             Sets the MyIpAddrs buffer to a list of my IP addresses.
 */
 
 */
 
+struct in_addr MyIpAddrs[MAXIPADDR + 1];
+
 char **
 myhostname(hostbuf, size)
        char hostbuf[];
        int size;
 {
 char **
 myhostname(hostbuf, size)
        char hostbuf[];
        int size;
 {
+       register struct hostent *hp;
        extern struct hostent *gethostbyname();
        extern struct hostent *gethostbyname();
-       struct hostent *hp;
 
        if (gethostname(hostbuf, size) < 0)
        {
 
        if (gethostname(hostbuf, size) < 0)
        {
@@ -383,62 +478,489 @@ myhostname(hostbuf, size)
        hp = gethostbyname(hostbuf);
        if (hp != NULL)
        {
        hp = gethostbyname(hostbuf);
        if (hp != NULL)
        {
-               (void) strcpy(hostbuf, hp->h_name);
+               (void) strncpy(hostbuf, hp->h_name, size - 1);
+               hostbuf[size - 1] = '\0';
+
+               if (hp->h_addrtype == AF_INET && hp->h_length == 4)
+               {
+                       register int i;
+
+                       for (i = 0; i < MAXIPADDR; i++)
+                       {
+                               if (hp->h_addr_list[i] == NULL)
+                                       break;
+                               MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i];
+                       }
+                       MyIpAddrs[i].s_addr = 0;
+               }
+
                return (hp->h_aliases);
        }
        else
                return (NULL);
 }
 \f/*
                return (hp->h_aliases);
        }
        else
                return (NULL);
 }
 \f/*
- *  MAPHOSTNAME -- turn a hostname into canonical form
- *
- *     Parameters:
- *             hbuf -- a buffer containing a hostname.
- *             hbsize -- the size of hbuf.
- *
- *     Returns:
- *             TRUE if the host name was mapped.
- *             FALSE otherwise.
- *
- *     Side Effects:
- *             Looks up the host specified in hbuf.  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.
- */
+**  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:
+**             The user@host information associated with this descriptor.
+**
+**     Side Effects:
+**             Sets RealHostName to the name of the host at the other end.
+*/
+
+#ifdef IDENTPROTO
+
+static jmp_buf CtxAuthTimeout;
+
+static
+authtimeout()
+{
+       longjmp(CtxAuthTimeout, 1);
+}
+
+#endif
+
+char *
+getauthinfo(fd)
+       int fd;
+{
+       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 */
+
+       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
+               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';
 
 
-bool
-maphostname(hbuf, hbsize)
-       char *hbuf;
-       int hbsize;
+       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/*
+**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
+**
+**     Parameters:
+**             map -- a pointer to this map (unused).
+**             name -- the (presumably unqualified) hostname.
+**             av -- unused -- for compatibility with other mapping
+**                     functions.
+**             statp -- an exit status (out parameter) -- set to
+**                     EX_TEMPFAIL if the name server is unavailable.
+**
+**     Returns:
+**             The mapping, if found.
+**             NULL if no mapping found.
+**
+**     Side Effects:
+**             Looks up the host specified in hbuf.  If it is not
+**             the canonical name for that host, return the canonical
+**             name.
+*/
+
+char *
+host_map_lookup(map, name, av, statp)
+       MAP *map;
+       char *name;
+       char **av;
+       int *statp;
 {
        register struct hostent *hp;
        u_long in_addr;
 {
        register struct hostent *hp;
        u_long in_addr;
-       char ptr[256], *cp;
-       struct hostent *gethostbyaddr();
+       char *cp;
+       int i;
+       register STAB *s;
+       char hbuf[MAXNAME];
+       extern struct hostent *gethostbyaddr();
+       extern int h_errno;
 
        /*
 
        /*
-        * 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 (*hbuf != '[')
-               return (getcanonname(hbuf, hbsize));
-       if ((cp = index(strcpy(ptr, hbuf), ']')) == NULL)
-               return (FALSE);
+       **  See if we have already looked up this name.  If so, just
+       **  return it.
+       */
+
+       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 name if address is
+       **  unknown.
+       */
+
+       if (*name != '[')
+       {
+               extern bool getcanonname();
+
+               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
+               {
+                       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(name, ']')) == NULL)
+               return (NULL);
        *cp = '\0';
        *cp = '\0';
-       in_addr = inet_addr(&ptr[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)
+               {
+                       return map_rewrite(map, MyHostName, strlen(MyHostName), av);
+               }
+       }
+
+       /* nope -- ask the name server */
        hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET);
        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)
-               return (FALSE);
-       if (strlen(hp->h_name) >= hbsize)
-               hp->h_name[hbsize - 1] = '\0';
-       (void)strcpy(hbuf, hp->h_name);
-       return (TRUE);
+       {
+               s->s_namecanon.nc_stat = *statp = EX_NOHOST;
+               return (NULL);
+       }
+
+       /* found a match -- copy out */
+       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 */
 /* code for systems without sophisticated networking */
 
 /*
 /* code for systems without sophisticated networking */
 
 /*
@@ -467,30 +989,61 @@ myhostname(hostbuf, size)
        return (NULL);
 }
 \f/*
        return (NULL);
 }
 \f/*
+**  GETAUTHINFO -- get the real host name asociated with a file descriptor
+**
+**     Parameters:
+**             fd -- the descriptor
+**
+**     Returns:
+**             The host name associated with this descriptor, if it can
+**                     be determined.
+**             NULL otherwise.
+**
+**     Side Effects:
+**             none
+*/
+
+char *
+getauthinfo(fd)
+       int fd;
+{
+       return NULL;
+}
+\f/*
 **  MAPHOSTNAME -- turn a hostname into canonical form
 **
 **     Parameters:
 **  MAPHOSTNAME -- turn a hostname into canonical form
 **
 **     Parameters:
-**             hbuf -- a buffer containing a hostname.
-**             hbsize -- the size of hbuf.
+**             map -- a pointer to the database map.
+**             name -- a buffer containing a hostname.
+**             avp -- a pointer to a (cf file defined) argument vector.
+**             statp -- an exit status (out parameter).
 **
 **     Returns:
 **
 **     Returns:
-**             TRUE if the hostname was mapped.
+**             mapped host name
 **             FALSE otherwise.
 **
 **     Side Effects:
 **             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.
 */
 
 /*ARGSUSED*/
 **             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.
 */
 
 /*ARGSUSED*/
-bool
-maphostname(hbuf, hbsize)
-       char *hbuf;
-       int hbsize;
+char *
+host_map_lookup(map, name, avp, statp)
+       MAP *map;
+       char *name;
+       char **avp;
+       char *statp;
 {
 {
-       return (FALSE);
+       register struct hostent *hp;
+
+       hp = gethostbyname(name);
+       if (hp != NULL)
+               return hp->h_name;
+       *statp = EX_NOHOST;
+       return NULL;
 }
 
 }
 
-#endif DAEMON
+#endif /* DAEMON */