diff options
Diffstat (limited to 'src/daemon.c')
-rw-r--r-- | src/daemon.c | 2154 |
1 files changed, 0 insertions, 2154 deletions
diff --git a/src/daemon.c b/src/daemon.c deleted file mode 100644 index ae6b004..0000000 --- a/src/daemon.c +++ /dev/null @@ -1,2154 +0,0 @@ -/* - * Copyright (c) 1998 Sendmail, Inc. All rights reserved. - * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -#include <errno.h> -#include "sendmail.h" - -#ifndef lint -#ifdef DAEMON -static char sccsid[] = "@(#)daemon.c 8.236 (Berkeley) 1/25/1999 (with daemon mode)"; -#else -static char sccsid[] = "@(#)daemon.c 8.236 (Berkeley) 1/25/1999 (without daemon mode)"; -#endif -#endif /* not lint */ - -#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) -# define USE_SOCK_STREAM 1 -#endif - -#if DAEMON || defined(USE_SOCK_STREAM) -# include <arpa/inet.h> -# if NAMED_BIND -# include <resolv.h> -# ifndef NO_DATA -# define NO_DATA NO_ADDRESS -# endif -# endif -#endif - -#if DAEMON - -# include <sys/time.h> - -# 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. -** -** This entire file is highly dependent on the 4.2 BSD -** interprocess communication primitives. No attempt has -** been made to make this file portable to Version 7, -** Version 6, MPX files, etc. If you should try such a -** thing yourself, I recommend chucking the entire file -** and starting from scratch. Basic semantics are: -** -** getrequests(e) -** Opens a port and initiates a connection. -** Returns in a child. Must set InChannel and -** OutChannel appropriately. -** clrdaemon() -** Close any open files associated with getting -** the connection; this is used when running the queue, -** 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, e) -** 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. -** host_map_lookup(map, hbuf, avp, pstat) -** Convert the entry in hbuf into a canonical form. -*/ -/* -** GETREQUESTS -- open mail IPC port and get requests. -** -** Parameters: -** e -- the current envelope. -** -** Returns: -** none. -** -** Side Effects: -** Waits until some interesting activity occurs. When -** it does, a child is created to process it, and the -** parent waits for completion. Return from this -** routine is always in the child. The file pointers -** "InChannel" and "OutChannel" should be set to point -** to the communication channel. -*/ - -int DaemonSocket = -1; /* fd describing socket */ -SOCKADDR DaemonAddr; /* socket for incoming */ -int ListenQueueSize = 10; /* size of listen queue */ -int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ -int TcpSndBufferSize = 0; /* size of TCP send buffer */ - -void -getrequests(e) - ENVELOPE *e; -{ - int t; - time_t refuse_connections_until = 0; - bool firsttime = TRUE; - FILE *pidf; - int sff; - int socksize; - u_short port; -#if XDEBUG - bool j_has_dot; -#endif - char status[MAXLINE]; - extern void reapchild __P((int)); -#ifdef NETUNIX - extern int ControlSocket; -#endif - extern int opendaemonsocket __P((bool)); - extern int opencontrolsocket __P((void)); - - /* - ** Set up the address for the mailer. - */ - - switch (DaemonAddr.sa.sa_family) - { - case AF_UNSPEC: - DaemonAddr.sa.sa_family = AF_INET; - /* fall through ... */ - - case AF_INET: - if (DaemonAddr.sin.sin_addr.s_addr == 0) - DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; - port = DaemonAddr.sin.sin_port; - break; - - default: - /* unknown protocol */ - port = 0; - break; - } - if (port == 0) - { - register struct servent *sp; - - sp = getservbyname("smtp", "tcp"); - if (sp == NULL) - { - syserr("554 service \"smtp\" unknown"); - port = htons(25); - } - else - port = sp->s_port; - } - - switch (DaemonAddr.sa.sa_family) - { - case AF_INET: - DaemonAddr.sin.sin_port = port; - break; - - default: - /* unknown protocol */ - break; - } - - /* - ** Try to actually open the connection. - */ - - if (tTd(15, 1)) - printf("getrequests: port 0x%x\n", port); - - /* get a socket for the SMTP connection */ - socksize = opendaemonsocket(TRUE); - - if (opencontrolsocket() < 0) - sm_syslog(LOG_WARNING, NOQID, - "daemon could not open control socket %s: %s", - ControlSocketName, errstring(errno)); - - (void) setsignal(SIGCHLD, reapchild); - - /* write the pid to the log file for posterity */ - sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT; - if (TrustedUid != 0 && RealUid == TrustedUid) - sff |= SFF_OPENASROOT; - pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644, sff); - if (pidf == NULL) - { - sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile); - } - else - { - extern char *CommandLineArgs; - - /* write the process id on line 1 */ - fprintf(pidf, "%ld\n", (long) getpid()); - - /* line 2 contains all command line flags */ - fprintf(pidf, "%s\n", CommandLineArgs); - - /* flush and close */ - fclose(pidf); - } - -#if XDEBUG - { - char jbuf[MAXHOSTNAMELEN]; - - expand("\201j", jbuf, sizeof jbuf, e); - j_has_dot = strchr(jbuf, '.') != NULL; - } -#endif - - /* Add parent process as first item */ - proc_list_add(getpid(), "Sendmail daemon"); - - if (tTd(15, 1)) - printf("getrequests: %d\n", DaemonSocket); - - for (;;) - { - register pid_t pid; - auto SOCKADDR_LEN_T lotherend; - bool timedout = FALSE; - bool control = FALSE; - int savederrno; - int pipefd[2]; - extern bool refuseconnections __P((int)); - - /* see if we are rejecting connections */ - (void) blocksignal(SIGALRM); - if (curtime() >= refuse_connections_until) - { - if (refuseconnections(ntohs(port))) - { - if (DaemonSocket >= 0) - { - /* close socket so peer fails quickly */ - (void) close(DaemonSocket); - DaemonSocket = -1; - } - - /* refuse connections for next 15 seconds */ - refuse_connections_until = curtime() + 15; - } - else if (DaemonSocket < 0 || firsttime) - { - /* arrange to (re)open the socket if needed */ - (void) opendaemonsocket(FALSE); - firsttime = FALSE; - } - } - -#if XDEBUG - /* check for disaster */ - { - char jbuf[MAXHOSTNAMELEN]; - extern void dumpstate __P((char *)); - - expand("\201j", jbuf, sizeof jbuf, e); - if (!wordinclass(jbuf, 'w')) - { - dumpstate("daemon lost $j"); - sm_syslog(LOG_ALERT, NOQID, - "daemon process doesn't have $j in $=w; see syslog"); - abort(); - } - else if (j_has_dot && strchr(jbuf, '.') == NULL) - { - dumpstate("daemon $j lost dot"); - sm_syslog(LOG_ALERT, NOQID, - "daemon process $j lost dot; see syslog"); - abort(); - } - } -#endif - -#if 0 - /* - ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will - ** fix the SVr4 problem. But it seems to have gone away, - ** so is it worth doing this? - */ - - if (DaemonSocket >= 0 && - SetNonBlocking(DaemonSocket, FALSE) < 0) - log an error here; -#endif - (void) releasesignal(SIGALRM); - for (;;) - { - int highest = -1; - fd_set readfds; - struct timeval timeout; - - FD_ZERO(&readfds); - - /* wait for a connection */ - if (DaemonSocket >= 0) - { - sm_setproctitle(TRUE, - "accepting connections on port %d", - ntohs(port)); - if (DaemonSocket > highest) - highest = DaemonSocket; - FD_SET(DaemonSocket, &readfds); - } -#ifdef NETUNIX - if (ControlSocket >= 0) - { - if (ControlSocket > highest) - highest = ControlSocket; - FD_SET(ControlSocket, &readfds); - } -#endif - if (DaemonSocket >= 0) - timeout.tv_sec = 60; - else - timeout.tv_sec = 5; - timeout.tv_usec = 0; - - t = select(highest + 1, FDSET_CAST &readfds, - NULL, NULL, &timeout); - - if (DoQueueRun) - (void) runqueue(TRUE, FALSE); - if (t <= 0) - { - timedout = TRUE; - break; - } - - control = FALSE; - errno = 0; - if (DaemonSocket >= 0 && - FD_ISSET(DaemonSocket, &readfds)) - { - lotherend = socksize; - t = accept(DaemonSocket, - (struct sockaddr *)&RealHostAddr, - &lotherend); - } -#ifdef NETUNIX - else if (ControlSocket >= 0 && - FD_ISSET(ControlSocket, &readfds)) - { - struct sockaddr_un sa_un; - - lotherend = sizeof sa_un; - t = accept(ControlSocket, - (struct sockaddr *)&sa_un, - &lotherend); - control = TRUE; - } -#endif - if (t >= 0 || errno != EINTR) - break; - } - if (timedout) - { - timedout = FALSE; - continue; - } - if (control) - { - if (t >= 0) - { - extern void control_command __P((int, ENVELOPE *)); - - control_command(t, e); - } - else - syserr("getrequests: control accept"); - continue; - } - savederrno = errno; - (void) blocksignal(SIGALRM); - if (t < 0) - { - errno = savederrno; - syserr("getrequests: accept"); - - /* arrange to re-open the socket next time around */ - (void) close(DaemonSocket); - DaemonSocket = -1; - continue; - } - - /* - ** Create a subprocess to process the mail. - */ - - if (tTd(15, 2)) - printf("getrequests: forking (fd = %d)\n", t); - - /* - ** Create a pipe to keep the child from writing to the - ** socket until after the parent has closed it. Otherwise - ** the parent may hang if the child has closed it first. - */ - - if (pipe(pipefd) < 0) - pipefd[0] = pipefd[1] = -1; - - blocksignal(SIGCHLD); - pid = fork(); - if (pid < 0) - { - syserr("daemon: cannot fork"); - if (pipefd[0] != -1) - { - (void) close(pipefd[0]); - (void) close(pipefd[1]); - } - (void) releasesignal(SIGCHLD); - sleep(10); - (void) close(t); - continue; - } - - if (pid == 0) - { - char *p; - extern SIGFUNC_DECL intsig __P((int)); - FILE *inchannel, *outchannel; - - /* - ** CHILD -- return to caller. - ** Collect verified idea of sending host. - ** Verify calling user id if possible here. - */ - - (void) releasesignal(SIGALRM); - (void) releasesignal(SIGCHLD); - (void) setsignal(SIGCHLD, SIG_DFL); - (void) setsignal(SIGHUP, intsig); - (void) close(DaemonSocket); - clrcontrol(); - proc_list_clear(); - - /* Add parent process as first child item */ - proc_list_add(getpid(), "daemon child"); - - /* don't schedule queue runs if we are told to ETRN */ - QueueIntvl = 0; - - sm_setproctitle(TRUE, "startup with %s", - anynet_ntoa(&RealHostAddr)); - - if (pipefd[0] != -1) - { - auto char c; - - /* - ** Wait for the parent to close the write end - ** of the pipe, which we will see as an EOF. - ** This guarantees that we won't write to the - ** socket until after the parent has closed - ** the pipe. - */ - - /* close the write end of the pipe */ - (void) close(pipefd[1]); - - /* we shouldn't be interrupted, but ... */ - while (read(pipefd[0], &c, 1) < 0 && - errno == EINTR) - continue; - (void) close(pipefd[0]); - } - - /* determine host name */ - p = hostnamebyanyaddr(&RealHostAddr); - if (strlen(p) > (SIZE_T) MAXNAME) - p[MAXNAME] = '\0'; - RealHostName = newstr(p); - sm_setproctitle(TRUE, "startup with %s", p); - - if ((inchannel = fdopen(t, "r")) == NULL || - (t = dup(t)) < 0 || - (outchannel = fdopen(t, "w")) == NULL) - { - syserr("cannot open SMTP server channel, fd=%d", t); - finis(FALSE, EX_OK); - } - - InChannel = inchannel; - OutChannel = outchannel; - DisConnected = FALSE; - -#ifdef XLA - if (!xla_host_ok(RealHostName)) - { - message("421 Too many SMTP sessions for this host"); - finis(FALSE, EX_OK); - } -#endif - break; - } - - /* parent -- keep track of children */ - snprintf(status, sizeof status, "SMTP server child for %s", - anynet_ntoa(&RealHostAddr)); - proc_list_add(pid, status); - (void) releasesignal(SIGCHLD); - - /* close the read end of the synchronization pipe */ - if (pipefd[0] != -1) - (void) close(pipefd[0]); - - /* close the port so that others will hang (for a while) */ - (void) close(t); - - /* release the child by closing the read end of the sync pipe */ - if (pipefd[1] != -1) - (void) close(pipefd[1]); - } - if (tTd(15, 2)) - printf("getreq: returning\n"); - return; -} -/* -** OPENDAEMONSOCKET -- open the SMTP socket -** -** Deals with setting all appropriate options. DaemonAddr must -** be set up in advance. -** -** Parameters: -** firsttime -- set if this is the initial open. -** -** Returns: -** Size in bytes of the daemon socket addr. -** -** Side Effects: -** Leaves DaemonSocket set to the open socket. -** Exits if the socket cannot be created. -*/ - -#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ - -int -opendaemonsocket(firsttime) - bool firsttime; -{ - int on = 1; - int socksize = 0; - int ntries = 0; - int saveerrno; - - if (tTd(15, 2)) - printf("opendaemonsocket()\n"); - - do - { - if (ntries > 0) - sleep(5); - if (firsttime || DaemonSocket < 0) - { - DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); - if (DaemonSocket < 0) - { - saveerrno = errno; - syserr("opendaemonsocket: can't create server SMTP socket"); - severe: - if (LogLevel > 0) - sm_syslog(LOG_ALERT, NOQID, - "problem creating SMTP socket"); - DaemonSocket = -1; - continue; - } - - /* turn on network debugging? */ - if (tTd(15, 101)) - (void) setsockopt(DaemonSocket, SOL_SOCKET, - SO_DEBUG, (char *)&on, - sizeof on); - - (void) setsockopt(DaemonSocket, SOL_SOCKET, - SO_REUSEADDR, (char *)&on, sizeof on); - (void) setsockopt(DaemonSocket, SOL_SOCKET, - SO_KEEPALIVE, (char *)&on, sizeof on); - -#ifdef SO_RCVBUF - if (TcpRcvBufferSize > 0) - { - if (setsockopt(DaemonSocket, SOL_SOCKET, - SO_RCVBUF, - (char *) &TcpRcvBufferSize, - sizeof(TcpRcvBufferSize)) < 0) - syserr("opendaemonsocket: setsockopt(SO_RCVBUF)"); - } -#endif - - switch (DaemonAddr.sa.sa_family) - { -# if NETINET - case AF_INET: - socksize = sizeof DaemonAddr.sin; - break; -# endif - -# if NETISO - case AF_ISO: - socksize = sizeof DaemonAddr.siso; - break; -# endif - - default: - socksize = sizeof DaemonAddr; - break; - } - - if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) - { - /* probably another daemon already */ - saveerrno = errno; - syserr("opendaemonsocket: cannot bind"); - (void) close(DaemonSocket); - goto severe; - } - } - if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) - { - saveerrno = errno; - syserr("opendaemonsocket: cannot listen"); - (void) close(DaemonSocket); - goto severe; - } - return socksize; - } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); - syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); - /*NOTREACHED*/ - return -1; /* avoid compiler warning on IRIX */ -} -/* -** CLRDAEMON -- reset the daemon connection -** -** Parameters: -** none. -** -** Returns: -** none. -** -** Side Effects: -** releases any resources used by the passive daemon. -*/ - -void -clrdaemon() -{ - if (DaemonSocket >= 0) - (void) close(DaemonSocket); - DaemonSocket = -1; -} -/* -** SETDAEMONOPTIONS -- set options for running the daemon -** -** Parameters: -** p -- the options line. -** -** Returns: -** none. -*/ - -void -setdaemonoptions(p) - register char *p; -{ - if (DaemonAddr.sa.sa_family == AF_UNSPEC) - DaemonAddr.sa.sa_family = AF_INET; - - while (p != NULL) - { - register char *f; - register char *v; - - while (isascii(*p) && isspace(*p)) - p++; - if (*p == '\0') - break; - f = p; - p = strchr(p, ','); - if (p != NULL) - *p++ = '\0'; - v = strchr(f, '='); - if (v == NULL) - continue; - while (isascii(*++v) && isspace(*v)) - continue; - if (isascii(*f) && islower(*f)) - *f = toupper(*f); - - switch (*f) - { - case 'F': /* address family */ - if (isascii(*v) && isdigit(*v)) - DaemonAddr.sa.sa_family = atoi(v); -#if NETINET - else if (strcasecmp(v, "inet") == 0) - DaemonAddr.sa.sa_family = AF_INET; -#endif -#if NETISO - else if (strcasecmp(v, "iso") == 0) - DaemonAddr.sa.sa_family = AF_ISO; -#endif -#if NETNS - else if (strcasecmp(v, "ns") == 0) - DaemonAddr.sa.sa_family = AF_NS; -#endif -#if NETX25 - else if (strcasecmp(v, "x.25") == 0) - DaemonAddr.sa.sa_family = AF_CCITT; -#endif - else - syserr("554 Unknown address family %s in Family=option", v); - break; - - case 'A': /* address */ - switch (DaemonAddr.sa.sa_family) - { -#if NETINET - case AF_INET: - if (isascii(*v) && isdigit(*v)) - DaemonAddr.sin.sin_addr.s_addr = inet_addr(v); - else - { - register struct hostent *hp; - - hp = sm_gethostbyname(v); - if (hp == NULL) - syserr("554 host \"%s\" unknown", v); - else - bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ); - } - break; -#endif - - default: - syserr("554 Address= option unsupported for family %d", - DaemonAddr.sa.sa_family); - break; - } - break; - - case 'P': /* port */ - switch (DaemonAddr.sa.sa_family) - { -#if NETISO - short port; -#endif - -#if NETINET - case AF_INET: - if (isascii(*v) && isdigit(*v)) - DaemonAddr.sin.sin_port = htons(atoi(v)); - else - { - register struct servent *sp; - - sp = getservbyname(v, "tcp"); - if (sp == NULL) - syserr("554 service \"%s\" unknown", v); - else - DaemonAddr.sin.sin_port = sp->s_port; - } - break; -#endif - -#if NETISO - case AF_ISO: - /* assume two byte transport selector */ - if (isascii(*v) && isdigit(*v)) - port = htons(atoi(v)); - else - { - register struct servent *sp; - - sp = getservbyname(v, "tcp"); - if (sp == NULL) - syserr("554 service \"%s\" unknown", v); - else - port = sp->s_port; - } - bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); - break; -#endif - - default: - syserr("554 Port= option unsupported for family %d", - DaemonAddr.sa.sa_family); - break; - } - break; - - case 'L': /* listen queue size */ - ListenQueueSize = atoi(v); - break; - - case 'S': /* send buffer size */ - TcpSndBufferSize = atoi(v); - break; - - case 'R': /* receive buffer size */ - TcpRcvBufferSize = atoi(v); - break; - - default: - syserr("554 DaemonPortOptions parameter \"%s\" unknown", f); - } - } -} -/* -** MAKECONNECTION -- make a connection to an SMTP socket on another machine. -** -** Parameters: -** host -- the name of the host. -** port -- the port number to connect to. -** mci -- a pointer to the mail connection information -** structure to be filled in. -** e -- the current envelope. -** -** Returns: -** An exit code telling whether the connection could be -** made and if not why not. -** -** Side Effects: -** none. -*/ - -static jmp_buf CtxConnectTimeout; - -static void -connecttimeout() -{ - errno = ETIMEDOUT; - longjmp(CtxConnectTimeout, 1); -} - -SOCKADDR CurHostAddr; /* address of current host */ - -int -makeconnection(host, port, mci, e) - char *host; - u_short port; - register MCI *mci; - ENVELOPE *e; -{ - register volatile int addrno = 0; - register volatile int s; - register struct hostent *volatile hp = (struct hostent *)NULL; - SOCKADDR addr; - int sav_errno; - volatile int addrlen; - volatile bool firstconnect; - EVENT *volatile ev = NULL; - - /* - ** Set up the address for the mailer. - ** Accept "[a.b.c.d]" syntax for host name. - */ - -#if NAMED_BIND - h_errno = 0; -#endif - errno = 0; - bzero(&CurHostAddr, sizeof CurHostAddr); - SmtpPhase = mci->mci_phase = "initial connection"; - CurHostName = host; - - if (host[0] == '[') - { -#if NETINET - unsigned long hid = INADDR_NONE; -#endif - register char *p = strchr(host, ']'); - - if (p != NULL) - { - *p = '\0'; -#if NETINET - hid = inet_addr(&host[1]); - if (hid == INADDR_NONE) -#endif - { - /* try it as a host name (avoid MX lookup) */ - hp = sm_gethostbyname(&host[1]); - if (hp == NULL && p[-1] == '.') - { -#if NAMED_BIND - int oldopts = _res.options; - - _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); -#endif - p[-1] = '\0'; - hp = sm_gethostbyname(&host[1]); - p[-1] = '.'; -#if NAMED_BIND - _res.options = oldopts; -#endif - } - *p = ']'; - goto gothostent; - } - *p = ']'; - } - if (p == NULL) - { - extern char MsgBuf[]; - - usrerr("553 Invalid numeric domain spec \"%s\"", host); - mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); - return EX_NOHOST; - } -#if NETINET - addr.sin.sin_family = AF_INET; /*XXX*/ - addr.sin.sin_addr.s_addr = hid; -#endif - } - else - { - /* contortion to get around SGI cc complaints */ - { - register char *p = &host[strlen(host) - 1]; - - hp = sm_gethostbyname(host); - if (hp == NULL && *p == '.') - { -#if NAMED_BIND - int oldopts = _res.options; - - _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); -#endif - *p = '\0'; - hp = sm_gethostbyname(host); - *p = '.'; -#if NAMED_BIND - _res.options = oldopts; -#endif - } - } -gothostent: - if (hp == NULL) - { -#if NAMED_BIND - /* check for name server timeouts */ - if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || - (errno == ECONNREFUSED && UseNameServer)) - { - mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL); - return EX_TEMPFAIL; - } -#endif - mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); - return (EX_NOHOST); - } - addr.sa.sa_family = hp->h_addrtype; - switch (hp->h_addrtype) - { -#if NETINET - case AF_INET: - bcopy(hp->h_addr, - &addr.sin.sin_addr, - INADDRSZ); - break; -#endif - - default: - if (hp->h_length > sizeof addr.sa.sa_data) - { - syserr("makeconnection: long sa_data: family %d len %d", - hp->h_addrtype, hp->h_length); - mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); - return EX_NOHOST; - } - bcopy(hp->h_addr, - addr.sa.sa_data, - hp->h_length); - break; - } - addrno = 1; - } - - /* - ** Determine the port number. - */ - - if (port == 0) - { - register struct servent *sp = getservbyname("smtp", "tcp"); - - if (sp == NULL) - { - if (LogLevel > 2) - sm_syslog(LOG_ERR, NOQID, - "makeconnection: service \"smtp\" unknown"); - port = htons(25); - } - else - port = sp->s_port; - } - - switch (addr.sa.sa_family) - { -#if NETINET - case AF_INET: - addr.sin.sin_port = port; - addrlen = sizeof (struct sockaddr_in); - break; -#endif - -#if 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); - mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); - return (EX_NOHOST); - } - - /* - ** 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 - - firstconnect = TRUE; - for (;;) - { - if (tTd(16, 1)) - printf("makeconnection (%s [%s])\n", - host, anynet_ntoa(&addr)); - - /* save for logging */ - CurHostAddr = addr; - - if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) - { - int rport = IPPORT_RESERVED - 1; - - s = rresvport(&rport); - } - else - { - s = socket(addr.sa.sa_family, SOCK_STREAM, 0); - } - if (s < 0) - { - sav_errno = errno; - syserr("makeconnection: cannot create socket"); -#ifdef XLA - xla_host_end(host); -#endif - mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); - return EX_TEMPFAIL; - } - -#ifdef SO_SNDBUF - if (TcpSndBufferSize > 0) - { - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, - (char *) &TcpSndBufferSize, - sizeof(TcpSndBufferSize)) < 0) - syserr("makeconnection: setsockopt(SO_SNDBUF)"); - } -#endif - - if (tTd(16, 1)) - printf("makeconnection: fd=%d\n", s); - - /* turn on network debugging? */ - if (tTd(16, 101)) - { - int on = 1; - (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, - (char *)&on, sizeof on); - } - if (e->e_xfp != NULL) - (void) fflush(e->e_xfp); /* for debugging */ - errno = 0; /* for debugging */ - - /* - ** Linux seems to hang in connect for 90 minutes (!!!). - ** Time out the connect to avoid this problem. - */ - - if (setjmp(CtxConnectTimeout) == 0) - { - int i; - - if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) - ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0); - else if (TimeOuts.to_connect != 0) - ev = setevent(TimeOuts.to_connect, connecttimeout, 0); - else - ev = NULL; - -#if _FFR_CONNECTONLYTO_OPTION - /* for testing */ - if (ConnectOnlyTo != 0) - addr.sin.sin_addr.s_addr = ConnectOnlyTo; -#endif - i = connect(s, (struct sockaddr *) &addr, addrlen); - sav_errno = errno; - if (ev != NULL) - clrevent(ev); - if (i >= 0) - break; - } - else - sav_errno = errno; - - /* 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 */ - (void) close(s); - - if (LogLevel >= 14) - sm_syslog(LOG_INFO, e->e_id, - "makeconnection (%s [%s]) failed: %s", - host, anynet_ntoa(&addr), - errstring(sav_errno)); - - if (hp != NULL && hp->h_addr_list[addrno] != NULL) - { - if (tTd(16, 1)) - printf("Connect failed (%s); trying new address....\n", - errstring(sav_errno)); - switch (addr.sa.sa_family) - { -#if NETINET - case AF_INET: - bcopy(hp->h_addr_list[addrno++], - &addr.sin.sin_addr, - INADDRSZ); - break; -#endif - - default: - bcopy(hp->h_addr_list[addrno++], - addr.sa.sa_data, - hp->h_length); - break; - } - continue; - } - - /* couldn't open connection */ -#ifdef XLA - xla_host_end(host); -#endif - mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); - return EX_TEMPFAIL; - } - - /* connection ok, put it into canonical form */ - if ((mci->mci_out = fdopen(s, "w")) == NULL || - (s = dup(s)) < 0 || - (mci->mci_in = fdopen(s, "r")) == NULL) - { - syserr("cannot open SMTP client channel, fd=%d", s); - mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); - return EX_TEMPFAIL; - } - - mci_setstat(mci, EX_OK, NULL, NULL); - return (EX_OK); -} -/* -** MYHOSTNAME -- return the name of this host. -** -** Parameters: -** hostbuf -- a place to return the name of this host. -** size -- the size of hostbuf. -** -** Returns: -** A list of aliases for this host. -** -** Side Effects: -** Adds numeric codes to $=w. -*/ - -struct hostent * -myhostname(hostbuf, size) - char hostbuf[]; - int size; -{ - register struct hostent *hp; - - if (gethostname(hostbuf, size) < 0) - { - (void) strcpy(hostbuf, "localhost"); - } - hp = sm_gethostbyname(hostbuf); - if (hp == NULL) - return NULL; - if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) - { - (void) strncpy(hostbuf, hp->h_name, size - 1); - hostbuf[size - 1] = '\0'; - } - - /* - ** If there is still no dot in the name, try looking for a - ** dotted alias. - */ - - if (strchr(hostbuf, '.') == NULL) - { - char **ha; - - for (ha = hp->h_aliases; *ha != NULL; ha++) - { - if (strchr(*ha, '.') != NULL) - { - (void) strncpy(hostbuf, *ha, size - 1); - hostbuf[size - 1] = '\0'; - break; - } - } - } - - /* - ** If _still_ no dot, wait for a while and try again -- it is - ** possible that some service is starting up. This can result - ** in excessive delays if the system is badly configured, but - ** there really isn't a way around that, particularly given that - ** the config file hasn't been read at this point. - ** All in all, a bit of a mess. - */ - - if (strchr(hostbuf, '.') == NULL && - !getcanonname(hostbuf, size, TRUE)) - { - sm_syslog(LOG_CRIT, NOQID, - "My unqualified host name (%s) unknown; sleeping for retry", - hostbuf); - message("My unqualified host name (%s) unknown; sleeping for retry", - hostbuf); - sleep(60); - if (!getcanonname(hostbuf, size, TRUE)) - { - sm_syslog(LOG_ALERT, NOQID, - "unable to qualify my own domain name (%s) -- using short name", - hostbuf); - message("WARNING: unable to qualify my own domain name (%s) -- using short name", - hostbuf); - } - } - return (hp); -} -/* -** ADDRCMP -- compare two host addresses -** -** Parameters: -** hp -- hostent structure for the first address -** ha -- actual first address -** sa -- second address -** -** Returns: -** 0 -- if ha and sa match -** else -- they don't match -*/ - -int -addrcmp(hp, ha, sa) - struct hostent *hp; - char *ha; - SOCKADDR *sa; -{ - switch (sa->sa.sa_family) - { - case AF_INET: - if (hp->h_addrtype == AF_INET) - return bcmp(ha, (char *) &sa->sin.sin_addr, hp->h_length); - break; - - } - return -1; -} -/* -** 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 -** may_be_forged -- an outage that is set to TRUE if the -** forward lookup of RealHostName does not match -** RealHostAddr; set to FALSE if they do match. -** -** Returns: -** The user@host information associated with this descriptor. -*/ - -static jmp_buf CtxAuthTimeout; - -static void -authtimeout() -{ - longjmp(CtxAuthTimeout, 1); -} - -char * -getauthinfo(fd, may_be_forged) - int fd; - bool *may_be_forged; -{ - SOCKADDR_LEN_T falen; - register char *volatile p = NULL; - SOCKADDR la; - SOCKADDR_LEN_T lalen; - register struct servent *sp; - volatile int s; - int i = 0; - EVENT *ev; - int nleft; - struct hostent *hp; - char *ostype = NULL; - char **ha; - char ibuf[MAXNAME + 1]; - static char hbuf[MAXNAME * 2 + 11]; - - *may_be_forged = FALSE; - falen = sizeof RealHostAddr; - if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || - falen <= 0 || RealHostAddr.sa.sa_family == 0) - { - if (i < 0 && errno != ENOTSOCK) - return NULL; - (void) snprintf(hbuf, sizeof hbuf, "%s@localhost", - RealUserName); - if (tTd(9, 1)) - printf("getauthinfo: %s\n", hbuf); - return hbuf; - } - - if (RealHostName == NULL) - { - /* translate that to a host name */ - RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); - if (strlen(RealHostName) > MAXNAME) - RealHostName[MAXNAME] = '\0'; - } - - /* cross check RealHostName with forward DNS lookup */ - if (anynet_ntoa(&RealHostAddr)[0] == '[' || - RealHostName[0] == '[') - { - /* - ** address is not a socket or have an - ** IP address with no forward lookup - */ - *may_be_forged = FALSE; - } - else - { - /* try to match the reverse against the forward lookup */ - hp = sm_gethostbyname(RealHostName); - - if (hp == NULL) - *may_be_forged = TRUE; - else - { - for (ha = hp->h_addr_list; *ha != NULL; ha++) - if (addrcmp(hp, *ha, &RealHostAddr) == 0) - break; - *may_be_forged = *ha == NULL; - } - } - - if (TimeOuts.to_ident == 0) - goto noident; - - lalen = sizeof la; - if (RealHostAddr.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) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", - ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); - - /* create local address */ - la.sin.sin_port = 0; - - /* create foreign address */ - sp = getservbyname("auth", "tcp"); - if (sp != NULL) - RealHostAddr.sin.sin_port = sp->s_port; - else - RealHostAddr.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(TimeOuts.to_ident, authtimeout, 0); - - /* connect to foreign IDENT server using same address as SMTP socket */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) - { - clrevent(ev); - goto noident; - } - if (bind(s, &la.sa, sizeof la.sin) < 0 || - connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) - { - goto closeident; - } - - if (tTd(9, 10)) - printf("getauthinfo: sent %s", ibuf); - - /* send query */ - if (write(s, ibuf, strlen(ibuf)) < 0) - goto closeident; - - /* get result */ - p = &ibuf[0]; - nleft = sizeof ibuf - 1; - while ((i = read(s, p, nleft)) > 0) - { - p += i; - nleft -= i; - *p = '\0'; - if (strchr(ibuf, '\n') != NULL) - break; - } - (void) close(s); - clrevent(ev); - if (i < 0 || p == &ibuf[0]) - goto noident; - - if (*--p == '\n' && *--p == '\r') - p--; - *++p = '\0'; - - if (tTd(9, 3)) - printf("getauthinfo: got %s\n", ibuf); - - /* parse result */ - p = strchr(ibuf, ':'); - 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 */ - while (isascii(*p) && isspace(*p)) - p++; - ostype = p; - p = strchr(p, ':'); - if (p == NULL) - { - /* malformed response */ - goto noident; - } - else - { - char *charset; - - *p = '\0'; - charset = strchr(ostype, ','); - if (charset != NULL) - *charset = '\0'; - } - - /* 1413 says don't do this -- but it's broken otherwise */ - while (isascii(*++p) && isspace(*p)) - continue; - - /* p now points to the authenticated name -- copy carefully */ - if (strncasecmp(ostype, "other", 5) == 0 && - (ostype[5] == ' ' || ostype[5] == '\0')) - { - snprintf(hbuf, sizeof hbuf, "IDENT:"); - cleanstrcpy(&hbuf[6], p, MAXNAME); - } - else - cleanstrcpy(hbuf, p, MAXNAME); - i = strlen(hbuf); - snprintf(&hbuf[i], sizeof hbuf - i, "@%s", - RealHostName == NULL ? "localhost" : RealHostName); - goto postident; - -closeident: - (void) close(s); - clrevent(ev); - -noident: - if (RealHostName == NULL) - { - if (tTd(9, 1)) - printf("getauthinfo: NULL\n"); - return NULL; - } - snprintf(hbuf, sizeof hbuf, "%s", RealHostName); - -postident: -#if IP_SRCROUTE -# ifndef GET_IPOPT_DST -# define GET_IPOPT_DST(dst) (dst) -# endif - /* - ** 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) - { - SOCKOPT_LEN_T ipoptlen; - int j; - u_char *q; - u_char *o; - int l; - 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: - /* - ** Source routing. - ** o[0] is the option type (loose/strict). - ** o[1] is the length of this option, - ** including option type and - ** length. - ** o[2] is the pointer into the route - ** data. - ** o[3] begins the route data. - */ - - p = &hbuf[strlen(hbuf)]; - l = sizeof hbuf - (hbuf - p) - 6; - snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s", - *o == IPOPT_SSRR ? "!" : "", - l > 240 ? 120 : l / 2, - inet_ntoa(GET_IPOPT_DST(ipopt.ipopt_dst))); - i = strlen(p); - p += i; - l -= strlen(p); - - j = o[1] / sizeof(struct in_addr) - 1; - - /* q skips length and router pointer to data */ - q = &o[3]; - for ( ; j >= 0; j--) - { - memcpy(&addr, q, sizeof(addr)); - snprintf(p, SPACELEFT(hbuf, p), - "%c%.*s", - j != 0 ? '@' : ':', - l > 240 ? 120 : - j == 0 ? l : l / 2, - inet_ntoa(addr)); - i = strlen(p); - p += i; - l -= i + 1; - q += sizeof(struct in_addr); - } - o += o[1]; - break; - - default: - /* Skip over option */ - o += o[1]; - break; - } - } - snprintf(p, SPACELEFT(hbuf, p), "]"); - goto postipsr; - } - -noipsr: -#endif - if (RealHostName != NULL && RealHostName[0] != '[') - { - p = &hbuf[strlen(hbuf)]; - (void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", - anynet_ntoa(&RealHostAddr)); - } - if (*may_be_forged) - { - p = &hbuf[strlen(hbuf)]; - (void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)"); - } - -#if IP_SRCROUTE -postipsr: -#endif - if (tTd(9, 1)) - printf("getauthinfo: %s\n", hbuf); - return hbuf; -} -/* -** HOST_MAP_LOOKUP -- turn a hostname into canonical form -** -** Parameters: -** map -- a pointer to this map. -** 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 (unless MF_MATCHONLY is set, which will cause the -** status only to be returned). -*/ - -char * -host_map_lookup(map, name, av, statp) - MAP *map; - char *name; - char **av; - int *statp; -{ - register struct hostent *hp; - struct in_addr in_addr; - char *cp; - register STAB *s; - char hbuf[MAXNAME + 1]; - - /* - ** 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 == 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; - if (*statp == EX_TEMPFAIL) - { - CurEnv->e_status = "4.4.3"; - message("851 %s: Name server timeout", - shortenstring(name, 33)); - } - if (*statp != EX_OK) - return NULL; - if (s->s_namecanon.nc_cname == NULL) - { - syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d", - name, - s->s_namecanon.nc_errno, - s->s_namecanon.nc_herrno); - return NULL; - } - if (bitset(MF_MATCHONLY, map->map_mflags)) - cp = map_rewrite(map, name, strlen(name), NULL); - else - cp = map_rewrite(map, - s->s_namecanon.nc_cname, - strlen(s->s_namecanon.nc_cname), - av); - return cp; - } - - /* - ** If we are running without a regular network connection (usually - ** dial-on-demand) and we are just queueing, we want to avoid DNS - ** lookups because those could try to connect to a server. - */ - - if (CurEnv->e_sendmode == SM_DEFER) - { - if (tTd(9, 1)) - printf("host_map_lookup(%s) => DEFERRED\n", name); - *statp = EX_TEMPFAIL; - return NULL; - } - - /* - ** 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 != '[') - { - if (tTd(9, 1)) - printf("host_map_lookup(%s) => ", name); - s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ - snprintf(hbuf, sizeof hbuf, "%s", name); - if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX)) - { - if (tTd(9, 1)) - printf("%s\n", hbuf); - s->s_namecanon.nc_stat = EX_OK; - s->s_namecanon.nc_cname = newstr(hbuf); - if (bitset(MF_MATCHONLY, map->map_mflags)) - cp = map_rewrite(map, name, strlen(name), NULL); - else - cp = map_rewrite(map, hbuf, strlen(hbuf), av); - return cp; - } - else - { - s->s_namecanon.nc_errno = errno; -#if NAMED_BIND - s->s_namecanon.nc_herrno = h_errno; - if (tTd(9, 1)) - printf("FAIL (%d)\n", h_errno); - switch (h_errno) - { - case TRY_AGAIN: - if (UseNameServer) - { - CurEnv->e_status = "4.4.3"; - message("851 %s: Name server timeout", - shortenstring(name, 33)); - } - *statp = EX_TEMPFAIL; - break; - - case HOST_NOT_FOUND: - case NO_DATA: - *statp = EX_NOHOST; - break; - - case NO_RECOVERY: - *statp = EX_SOFTWARE; - break; - - default: - *statp = EX_UNAVAILABLE; - break; - } -#else - if (tTd(9, 1)) - printf("FAIL\n"); - *statp = EX_NOHOST; -#endif - s->s_namecanon.nc_stat = *statp; - return NULL; - } - } - if ((cp = strchr(name, ']')) == NULL) - return (NULL); - *cp = '\0'; - in_addr.s_addr = inet_addr(&name[1]); - *cp = ']'; - - /* nope -- ask the name server */ - 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; -#endif - s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ - if (hp == NULL) - { - s->s_namecanon.nc_stat = *statp = EX_NOHOST; - return (NULL); - } - - /* found a match -- copy out */ - hp->h_name = denlstring((char *) hp->h_name, TRUE, TRUE); - s->s_namecanon.nc_stat = *statp = EX_OK; - s->s_namecanon.nc_cname = newstr(hp->h_name); - if (bitset(MF_MATCHONLY, map->map_mflags)) - cp = map_rewrite(map, name, strlen(name), NULL); - else - cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); - return cp; -} - -# else /* DAEMON */ -/* code for systems without sophisticated networking */ - -/* -** MYHOSTNAME -- stub version for case of no daemon code. -** -** Can't convert to upper case here because might be a UUCP name. -** -** Mark, you can change this to be anything you want...... -*/ - -char ** -myhostname(hostbuf, size) - char hostbuf[]; - int size; -{ - register FILE *f; - - hostbuf[0] = '\0'; - f = fopen("/usr/include/whoami", "r"); - if (f != NULL) - { - (void) fgets(hostbuf, size, f); - fixcrlf(hostbuf, TRUE); - (void) fclose(f); - } - return (NULL); -} -/* -** GETAUTHINFO -- get the real host name asociated with a file descriptor -** -** Parameters: -** fd -- the descriptor -** may_be_forged -- an outage that is set to TRUE if the -** forward lookup of RealHostName does not match -** RealHostAddr; set to FALSE if they do match. -** -** Returns: -** The host name associated with this descriptor, if it can -** be determined. -** NULL otherwise. -** -** Side Effects: -** none -*/ - -char * -getauthinfo(fd, may_be_forged) - int fd; - bool *may_be_forged; -{ - *may_be_forged = FALSE; - return NULL; -} -/* -** MAPHOSTNAME -- turn a hostname into canonical form -** -** Parameters: -** 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: -** mapped host name -** FALSE otherwise. -** -** Side Effects: -** 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*/ -char * -host_map_lookup(map, name, avp, statp) - MAP *map; - char *name; - char **avp; - char *statp; -{ - register struct hostent *hp; - char *cp; - - hp = sm_gethostbyname(name); - if (hp == NULL) - { - *statp = EX_NOHOST; - return NULL; - } - if (bitset(MF_MATCHONLY, map->map_mflags)) - cp = map_rewrite(map, name, strlen(name), NULL); - else - cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp); - return cp; -} - -#endif /* DAEMON */ -/* -** HOST_MAP_INIT -- initialize host class structures -*/ - -bool -host_map_init(map, args) - MAP *map; - char *args; -{ - register char *p = args; - - for (;;) - { - while (isascii(*p) && isspace(*p)) - p++; - if (*p != '-') - break; - switch (*++p) - { - case 'a': - map->map_app = ++p; - break; - - case 'T': - map->map_tapp = ++p; - break; - - case 'm': - map->map_mflags |= MF_MATCHONLY; - break; - - case 't': - map->map_mflags |= MF_NODEFER; - break; - } - while (*p != '\0' && !(isascii(*p) && isspace(*p))) - p++; - if (*p != '\0') - *p++ = '\0'; - } - if (map->map_app != NULL) - map->map_app = newstr(map->map_app); - if (map->map_tapp != NULL) - map->map_tapp = newstr(map->map_tapp); - return TRUE; -} -/* -** ANYNET_NTOA -- convert a network address to printable form. -** -** Parameters: -** sap -- a pointer to a sockaddr structure. -** -** Returns: -** A printable version of that sockaddr. -*/ - -#ifdef USE_SOCK_STREAM - -#if NETLINK -# include <net/if_dl.h> -#endif - -char * -anynet_ntoa(sap) - register SOCKADDR *sap; -{ - register char *bp; - register char *ap; - int l; - static char buf[100]; - - /* check for null/zero family */ - if (sap == NULL) - return "NULLADDR"; - if (sap->sa.sa_family == 0) - return "0"; - - switch (sap->sa.sa_family) - { -#if NETUNIX - case AF_UNIX: - if (sap->sunix.sun_path[0] != '\0') - snprintf(buf, sizeof buf, "[UNIX: %.64s]", - sap->sunix.sun_path); - else - snprintf(buf, sizeof buf, "[UNIX: localhost]"); - return buf; -#endif - -#if NETINET - case AF_INET: - return inet_ntoa(sap->sin.sin_addr); -#endif - -#if NETLINK - case AF_LINK: - snprintf(buf, sizeof buf, "[LINK: %s]", - link_ntoa((struct sockaddr_dl *) &sap->sa)); - return buf; -#endif - default: - /* this case is needed when nothing is #defined */ - /* in order to keep the switch syntactically correct */ - break; - } - - /* unknown family -- just dump bytes */ - (void) snprintf(buf, sizeof 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) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377); - bp += 3; - } - *--bp = '\0'; - return buf; -} -/* -** 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; - int saveretry; - -#if NAMED_BIND - /* shorten name server timeout to avoid higher level timeouts */ - saveretry = _res.retry; - _res.retry = 3; -#endif /* NAMED_BIND */ - - switch (sap->sa.sa_family) - { -#if NETINET - case AF_INET: - hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, - INADDRSZ, - AF_INET); - break; -#endif - -#if NETISO - case AF_ISO: - hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, - sizeof sap->siso.siso_addr, - AF_ISO); - break; -#endif - -#if NETUNIX - case AF_UNIX: - hp = NULL; - break; -#endif - - default: - hp = sm_gethostbyaddr(sap->sa.sa_data, - sizeof sap->sa.sa_data, - sap->sa.sa_family); - break; - } - -#if NAMED_BIND - _res.retry = saveretry; -#endif /* NAMED_BIND */ - - if (hp != NULL && hp->h_name[0] != '[' && - inet_addr(hp->h_name) == INADDR_NONE) - return denlstring((char *) hp->h_name, TRUE, TRUE); -#if NETUNIX - else if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') - return "localhost"; -#endif - else - { - /* produce a dotted quad */ - static char buf[203]; - - (void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap)); - return buf; - } -} - -#endif /* SOCK_STREAM */ |