daemon.c revision 38032
138032Speter/* 238032Speter * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 438032Speter * Copyright (c) 1988, 1993 538032Speter * The Regents of the University of California. All rights reserved. 638032Speter * 738032Speter * By using this file, you agree to the terms and conditions set 838032Speter * forth in the LICENSE file which can be found at the top level of 938032Speter * the sendmail distribution. 1038032Speter * 1138032Speter */ 1238032Speter 1338032Speter#include <errno.h> 1438032Speter#include "sendmail.h" 1538032Speter 1638032Speter#ifndef lint 1738032Speter#ifdef DAEMON 1838032Speterstatic char sccsid[] = "@(#)daemon.c 8.220 (Berkeley) 6/24/98 (with daemon mode)"; 1938032Speter#else 2038032Speterstatic char sccsid[] = "@(#)daemon.c 8.220 (Berkeley) 6/24/98 (without daemon mode)"; 2138032Speter#endif 2238032Speter#endif /* not lint */ 2338032Speter 2438032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) 2538032Speter# define USE_SOCK_STREAM 1 2638032Speter#endif 2738032Speter 2838032Speter#if DAEMON || defined(USE_SOCK_STREAM) 2938032Speter# include <arpa/inet.h> 3038032Speter# if NAMED_BIND 3138032Speter# include <resolv.h> 3238032Speter# ifndef NO_DATA 3338032Speter# define NO_DATA NO_ADDRESS 3438032Speter# endif 3538032Speter# endif 3638032Speter#endif 3738032Speter 3838032Speter#if DAEMON 3938032Speter 4038032Speter# include <sys/time.h> 4138032Speter 4238032Speter# if IP_SRCROUTE 4338032Speter# include <netinet/in_systm.h> 4438032Speter# include <netinet/ip.h> 4538032Speter# include <netinet/ip_var.h> 4638032Speter# endif 4738032Speter 4838032Speter/* 4938032Speter** DAEMON.C -- routines to use when running as a daemon. 5038032Speter** 5138032Speter** This entire file is highly dependent on the 4.2 BSD 5238032Speter** interprocess communication primitives. No attempt has 5338032Speter** been made to make this file portable to Version 7, 5438032Speter** Version 6, MPX files, etc. If you should try such a 5538032Speter** thing yourself, I recommend chucking the entire file 5638032Speter** and starting from scratch. Basic semantics are: 5738032Speter** 5838032Speter** getrequests(e) 5938032Speter** Opens a port and initiates a connection. 6038032Speter** Returns in a child. Must set InChannel and 6138032Speter** OutChannel appropriately. 6238032Speter** clrdaemon() 6338032Speter** Close any open files associated with getting 6438032Speter** the connection; this is used when running the queue, 6538032Speter** etc., to avoid having extra file descriptors during 6638032Speter** the queue run and to avoid confusing the network 6738032Speter** code (if it cares). 6838032Speter** makeconnection(host, port, outfile, infile, e) 6938032Speter** Make a connection to the named host on the given 7038032Speter** port. Set *outfile and *infile to the files 7138032Speter** appropriate for communication. Returns zero on 7238032Speter** success, else an exit status describing the 7338032Speter** error. 7438032Speter** host_map_lookup(map, hbuf, avp, pstat) 7538032Speter** Convert the entry in hbuf into a canonical form. 7638032Speter*/ 7738032Speter/* 7838032Speter** GETREQUESTS -- open mail IPC port and get requests. 7938032Speter** 8038032Speter** Parameters: 8138032Speter** e -- the current envelope. 8238032Speter** 8338032Speter** Returns: 8438032Speter** none. 8538032Speter** 8638032Speter** Side Effects: 8738032Speter** Waits until some interesting activity occurs. When 8838032Speter** it does, a child is created to process it, and the 8938032Speter** parent waits for completion. Return from this 9038032Speter** routine is always in the child. The file pointers 9138032Speter** "InChannel" and "OutChannel" should be set to point 9238032Speter** to the communication channel. 9338032Speter*/ 9438032Speter 9538032Speterint DaemonSocket = -1; /* fd describing socket */ 9638032SpeterSOCKADDR DaemonAddr; /* socket for incoming */ 9738032Speterint ListenQueueSize = 10; /* size of listen queue */ 9838032Speterint TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 9938032Speterint TcpSndBufferSize = 0; /* size of TCP send buffer */ 10038032Speter 10138032Spetervoid 10238032Spetergetrequests(e) 10338032Speter ENVELOPE *e; 10438032Speter{ 10538032Speter int t; 10638032Speter bool refusingconnections = TRUE; 10738032Speter FILE *pidf; 10838032Speter int socksize; 10938032Speter u_short port; 11038032Speter#if XDEBUG 11138032Speter bool j_has_dot; 11238032Speter#endif 11338032Speter extern void reapchild __P((int)); 11438032Speter extern int opendaemonsocket __P((bool)); 11538032Speter 11638032Speter /* 11738032Speter ** Set up the address for the mailer. 11838032Speter */ 11938032Speter 12038032Speter switch (DaemonAddr.sa.sa_family) 12138032Speter { 12238032Speter case AF_UNSPEC: 12338032Speter DaemonAddr.sa.sa_family = AF_INET; 12438032Speter /* fall through ... */ 12538032Speter 12638032Speter case AF_INET: 12738032Speter if (DaemonAddr.sin.sin_addr.s_addr == 0) 12838032Speter DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 12938032Speter port = DaemonAddr.sin.sin_port; 13038032Speter break; 13138032Speter 13238032Speter default: 13338032Speter /* unknown protocol */ 13438032Speter port = 0; 13538032Speter break; 13638032Speter } 13738032Speter if (port == 0) 13838032Speter { 13938032Speter register struct servent *sp; 14038032Speter 14138032Speter sp = getservbyname("smtp", "tcp"); 14238032Speter if (sp == NULL) 14338032Speter { 14438032Speter syserr("554 service \"smtp\" unknown"); 14538032Speter port = htons(25); 14638032Speter } 14738032Speter else 14838032Speter port = sp->s_port; 14938032Speter } 15038032Speter 15138032Speter switch (DaemonAddr.sa.sa_family) 15238032Speter { 15338032Speter case AF_INET: 15438032Speter DaemonAddr.sin.sin_port = port; 15538032Speter break; 15638032Speter 15738032Speter default: 15838032Speter /* unknown protocol */ 15938032Speter break; 16038032Speter } 16138032Speter 16238032Speter /* 16338032Speter ** Try to actually open the connection. 16438032Speter */ 16538032Speter 16638032Speter if (tTd(15, 1)) 16738032Speter printf("getrequests: port 0x%x\n", port); 16838032Speter 16938032Speter /* get a socket for the SMTP connection */ 17038032Speter socksize = opendaemonsocket(TRUE); 17138032Speter 17238032Speter (void) setsignal(SIGCHLD, reapchild); 17338032Speter 17438032Speter /* write the pid to the log file for posterity */ 17538032Speter pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644, 17638032Speter SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT); 17738032Speter if (pidf == NULL) 17838032Speter { 17938032Speter sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile); 18038032Speter } 18138032Speter else 18238032Speter { 18338032Speter extern char *CommandLineArgs; 18438032Speter 18538032Speter /* write the process id on line 1 */ 18638032Speter fprintf(pidf, "%ld\n", (long) getpid()); 18738032Speter 18838032Speter /* line 2 contains all command line flags */ 18938032Speter fprintf(pidf, "%s\n", CommandLineArgs); 19038032Speter 19138032Speter /* flush and close */ 19238032Speter fclose(pidf); 19338032Speter } 19438032Speter 19538032Speter#if XDEBUG 19638032Speter { 19738032Speter char jbuf[MAXHOSTNAMELEN]; 19838032Speter 19938032Speter expand("\201j", jbuf, sizeof jbuf, e); 20038032Speter j_has_dot = strchr(jbuf, '.') != NULL; 20138032Speter } 20238032Speter#endif 20338032Speter 20438032Speter if (tTd(15, 1)) 20538032Speter printf("getrequests: %d\n", DaemonSocket); 20638032Speter 20738032Speter for (;;) 20838032Speter { 20938032Speter register pid_t pid; 21038032Speter auto SOCKADDR_LEN_T lotherend; 21138032Speter int savederrno; 21238032Speter int pipefd[2]; 21338032Speter extern bool refuseconnections __P((int)); 21438032Speter 21538032Speter /* see if we are rejecting connections */ 21638032Speter (void) blocksignal(SIGALRM); 21738032Speter if (refuseconnections(ntohs(port))) 21838032Speter { 21938032Speter if (DaemonSocket >= 0) 22038032Speter { 22138032Speter /* close socket so peer will fail quickly */ 22238032Speter (void) close(DaemonSocket); 22338032Speter DaemonSocket = -1; 22438032Speter } 22538032Speter refusingconnections = TRUE; 22638032Speter sleep(15); 22738032Speter continue; 22838032Speter } 22938032Speter 23038032Speter /* arrange to (re)open the socket if necessary */ 23138032Speter if (refusingconnections) 23238032Speter { 23338032Speter (void) opendaemonsocket(FALSE); 23438032Speter refusingconnections = FALSE; 23538032Speter } 23638032Speter 23738032Speter#if XDEBUG 23838032Speter /* check for disaster */ 23938032Speter { 24038032Speter char jbuf[MAXHOSTNAMELEN]; 24138032Speter extern void dumpstate __P((char *)); 24238032Speter 24338032Speter expand("\201j", jbuf, sizeof jbuf, e); 24438032Speter if (!wordinclass(jbuf, 'w')) 24538032Speter { 24638032Speter dumpstate("daemon lost $j"); 24738032Speter sm_syslog(LOG_ALERT, NOQID, 24838032Speter "daemon process doesn't have $j in $=w; see syslog"); 24938032Speter abort(); 25038032Speter } 25138032Speter else if (j_has_dot && strchr(jbuf, '.') == NULL) 25238032Speter { 25338032Speter dumpstate("daemon $j lost dot"); 25438032Speter sm_syslog(LOG_ALERT, NOQID, 25538032Speter "daemon process $j lost dot; see syslog"); 25638032Speter abort(); 25738032Speter } 25838032Speter } 25938032Speter#endif 26038032Speter 26138032Speter /* wait for a connection */ 26238032Speter setproctitle("accepting connections on port %d", 26338032Speter ntohs(port)); 26438032Speter#if 0 26538032Speter /* 26638032Speter ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 26738032Speter ** fix the SVr4 problem. But it seems to have gone away, 26838032Speter ** so is it worth doing this? 26938032Speter */ 27038032Speter 27138032Speter if (SetNonBlocking(DaemonSocket, FALSE) < 0) 27238032Speter log an error here; 27338032Speter#endif 27438032Speter (void) releasesignal(SIGALRM); 27538032Speter for (;;) 27638032Speter { 27738032Speter fd_set readfds; 27838032Speter struct timeval timeout; 27938032Speter 28038032Speter FD_ZERO(&readfds); 28138032Speter FD_SET(DaemonSocket, &readfds); 28238032Speter timeout.tv_sec = 60; 28338032Speter timeout.tv_usec = 0; 28438032Speter 28538032Speter t = select(DaemonSocket + 1, FDSET_CAST &readfds, 28638032Speter NULL, NULL, &timeout); 28738032Speter if (DoQueueRun) 28838032Speter (void) runqueue(TRUE, FALSE); 28938032Speter if (t <= 0 || !FD_ISSET(DaemonSocket, &readfds)) 29038032Speter continue; 29138032Speter 29238032Speter errno = 0; 29338032Speter lotherend = socksize; 29438032Speter t = accept(DaemonSocket, 29538032Speter (struct sockaddr *)&RealHostAddr, &lotherend); 29638032Speter if (t >= 0 || errno != EINTR) 29738032Speter break; 29838032Speter } 29938032Speter savederrno = errno; 30038032Speter (void) blocksignal(SIGALRM); 30138032Speter if (t < 0) 30238032Speter { 30338032Speter errno = savederrno; 30438032Speter syserr("getrequests: accept"); 30538032Speter 30638032Speter /* arrange to re-open the socket next time around */ 30738032Speter (void) close(DaemonSocket); 30838032Speter DaemonSocket = -1; 30938032Speter refusingconnections = TRUE; 31038032Speter sleep(5); 31138032Speter continue; 31238032Speter } 31338032Speter 31438032Speter /* 31538032Speter ** Create a subprocess to process the mail. 31638032Speter */ 31738032Speter 31838032Speter if (tTd(15, 2)) 31938032Speter printf("getrequests: forking (fd = %d)\n", t); 32038032Speter 32138032Speter /* 32238032Speter ** Create a pipe to keep the child from writing to the 32338032Speter ** socket until after the parent has closed it. Otherwise 32438032Speter ** the parent may hang if the child has closed it first. 32538032Speter */ 32638032Speter 32738032Speter if (pipe(pipefd) < 0) 32838032Speter pipefd[0] = pipefd[1] = -1; 32938032Speter 33038032Speter blocksignal(SIGCHLD); 33138032Speter pid = fork(); 33238032Speter if (pid < 0) 33338032Speter { 33438032Speter syserr("daemon: cannot fork"); 33538032Speter if (pipefd[0] != -1) 33638032Speter { 33738032Speter (void) close(pipefd[0]); 33838032Speter (void) close(pipefd[1]); 33938032Speter } 34038032Speter (void) releasesignal(SIGCHLD); 34138032Speter sleep(10); 34238032Speter (void) close(t); 34338032Speter continue; 34438032Speter } 34538032Speter 34638032Speter if (pid == 0) 34738032Speter { 34838032Speter char *p; 34938032Speter extern SIGFUNC_DECL intsig __P((int)); 35038032Speter FILE *inchannel, *outchannel; 35138032Speter 35238032Speter /* 35338032Speter ** CHILD -- return to caller. 35438032Speter ** Collect verified idea of sending host. 35538032Speter ** Verify calling user id if possible here. 35638032Speter */ 35738032Speter 35838032Speter (void) releasesignal(SIGALRM); 35938032Speter (void) releasesignal(SIGCHLD); 36038032Speter (void) setsignal(SIGCHLD, SIG_DFL); 36138032Speter (void) setsignal(SIGHUP, intsig); 36238032Speter (void) close(DaemonSocket); 36338032Speter proc_list_clear(); 36438032Speter 36538032Speter /* don't schedule queue runs if we are told to ETRN */ 36638032Speter QueueIntvl = 0; 36738032Speter 36838032Speter setproctitle("startup with %s", 36938032Speter anynet_ntoa(&RealHostAddr)); 37038032Speter 37138032Speter if (pipefd[0] != -1) 37238032Speter { 37338032Speter auto char c; 37438032Speter 37538032Speter /* 37638032Speter ** Wait for the parent to close the write end 37738032Speter ** of the pipe, which we will see as an EOF. 37838032Speter ** This guarantees that we won't write to the 37938032Speter ** socket until after the parent has closed 38038032Speter ** the pipe. 38138032Speter */ 38238032Speter 38338032Speter /* close the write end of the pipe */ 38438032Speter (void) close(pipefd[1]); 38538032Speter 38638032Speter /* we shouldn't be interrupted, but ... */ 38738032Speter while (read(pipefd[0], &c, 1) < 0 && 38838032Speter errno == EINTR) 38938032Speter continue; 39038032Speter (void) close(pipefd[0]); 39138032Speter } 39238032Speter 39338032Speter /* determine host name */ 39438032Speter p = hostnamebyanyaddr(&RealHostAddr); 39538032Speter if (strlen(p) > (SIZE_T) MAXNAME) 39638032Speter p[MAXNAME] = '\0'; 39738032Speter RealHostName = newstr(p); 39838032Speter setproctitle("startup with %s", p); 39938032Speter 40038032Speter if ((inchannel = fdopen(t, "r")) == NULL || 40138032Speter (t = dup(t)) < 0 || 40238032Speter (outchannel = fdopen(t, "w")) == NULL) 40338032Speter { 40438032Speter syserr("cannot open SMTP server channel, fd=%d", t); 40538032Speter exit(EX_OK); 40638032Speter } 40738032Speter 40838032Speter InChannel = inchannel; 40938032Speter OutChannel = outchannel; 41038032Speter DisConnected = FALSE; 41138032Speter 41238032Speter /* open maps for check_relay ruleset */ 41338032Speter initmaps(FALSE, e); 41438032Speter 41538032Speter#ifdef XLA 41638032Speter if (!xla_host_ok(RealHostName)) 41738032Speter { 41838032Speter message("421 Too many SMTP sessions for this host"); 41938032Speter exit(EX_OK); 42038032Speter } 42138032Speter#endif 42238032Speter 42338032Speter break; 42438032Speter } 42538032Speter 42638032Speter /* parent -- keep track of children */ 42738032Speter proc_list_add(pid); 42838032Speter (void) releasesignal(SIGCHLD); 42938032Speter 43038032Speter /* close the read end of the synchronization pipe */ 43138032Speter if (pipefd[0] != -1) 43238032Speter (void) close(pipefd[0]); 43338032Speter 43438032Speter /* close the port so that others will hang (for a while) */ 43538032Speter (void) close(t); 43638032Speter 43738032Speter /* release the child by closing the read end of the sync pipe */ 43838032Speter if (pipefd[1] != -1) 43938032Speter (void) close(pipefd[1]); 44038032Speter } 44138032Speter if (tTd(15, 2)) 44238032Speter printf("getreq: returning\n"); 44338032Speter return; 44438032Speter} 44538032Speter/* 44638032Speter** OPENDAEMONSOCKET -- open the SMTP socket 44738032Speter** 44838032Speter** Deals with setting all appropriate options. DaemonAddr must 44938032Speter** be set up in advance. 45038032Speter** 45138032Speter** Parameters: 45238032Speter** firsttime -- set if this is the initial open. 45338032Speter** 45438032Speter** Returns: 45538032Speter** Size in bytes of the daemon socket addr. 45638032Speter** 45738032Speter** Side Effects: 45838032Speter** Leaves DaemonSocket set to the open socket. 45938032Speter** Exits if the socket cannot be created. 46038032Speter*/ 46138032Speter 46238032Speter#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 46338032Speter 46438032Speterint 46538032Speteropendaemonsocket(firsttime) 46638032Speter bool firsttime; 46738032Speter{ 46838032Speter int on = 1; 46938032Speter int socksize = 0; 47038032Speter int ntries = 0; 47138032Speter int saveerrno; 47238032Speter 47338032Speter if (tTd(15, 2)) 47438032Speter printf("opendaemonsocket()\n"); 47538032Speter 47638032Speter do 47738032Speter { 47838032Speter if (ntries > 0) 47938032Speter sleep(5); 48038032Speter if (firsttime || DaemonSocket < 0) 48138032Speter { 48238032Speter DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 48338032Speter if (DaemonSocket < 0) 48438032Speter { 48538032Speter saveerrno = errno; 48638032Speter syserr("opendaemonsocket: can't create server SMTP socket"); 48738032Speter severe: 48838032Speter if (LogLevel > 0) 48938032Speter sm_syslog(LOG_ALERT, NOQID, 49038032Speter "problem creating SMTP socket"); 49138032Speter DaemonSocket = -1; 49238032Speter continue; 49338032Speter } 49438032Speter 49538032Speter /* turn on network debugging? */ 49638032Speter if (tTd(15, 101)) 49738032Speter (void) setsockopt(DaemonSocket, SOL_SOCKET, 49838032Speter SO_DEBUG, (char *)&on, 49938032Speter sizeof on); 50038032Speter 50138032Speter (void) setsockopt(DaemonSocket, SOL_SOCKET, 50238032Speter SO_REUSEADDR, (char *)&on, sizeof on); 50338032Speter (void) setsockopt(DaemonSocket, SOL_SOCKET, 50438032Speter SO_KEEPALIVE, (char *)&on, sizeof on); 50538032Speter 50638032Speter#ifdef SO_RCVBUF 50738032Speter if (TcpRcvBufferSize > 0) 50838032Speter { 50938032Speter if (setsockopt(DaemonSocket, SOL_SOCKET, 51038032Speter SO_RCVBUF, 51138032Speter (char *) &TcpRcvBufferSize, 51238032Speter sizeof(TcpRcvBufferSize)) < 0) 51338032Speter syserr("opendaemonsocket: setsockopt(SO_RCVBUF)"); 51438032Speter } 51538032Speter#endif 51638032Speter 51738032Speter switch (DaemonAddr.sa.sa_family) 51838032Speter { 51938032Speter# if NETINET 52038032Speter case AF_INET: 52138032Speter socksize = sizeof DaemonAddr.sin; 52238032Speter break; 52338032Speter# endif 52438032Speter 52538032Speter# if NETISO 52638032Speter case AF_ISO: 52738032Speter socksize = sizeof DaemonAddr.siso; 52838032Speter break; 52938032Speter# endif 53038032Speter 53138032Speter default: 53238032Speter socksize = sizeof DaemonAddr; 53338032Speter break; 53438032Speter } 53538032Speter 53638032Speter if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 53738032Speter { 53838032Speter /* probably another daemon already */ 53938032Speter saveerrno = errno; 54038032Speter syserr("opendaemonsocket: cannot bind"); 54138032Speter (void) close(DaemonSocket); 54238032Speter goto severe; 54338032Speter } 54438032Speter } 54538032Speter if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 54638032Speter { 54738032Speter saveerrno = errno; 54838032Speter syserr("opendaemonsocket: cannot listen"); 54938032Speter (void) close(DaemonSocket); 55038032Speter goto severe; 55138032Speter } 55238032Speter return socksize; 55338032Speter } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 55438032Speter syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 55538032Speter finis(); 55638032Speter return -1; /* avoid compiler warning on IRIX */ 55738032Speter} 55838032Speter/* 55938032Speter** CLRDAEMON -- reset the daemon connection 56038032Speter** 56138032Speter** Parameters: 56238032Speter** none. 56338032Speter** 56438032Speter** Returns: 56538032Speter** none. 56638032Speter** 56738032Speter** Side Effects: 56838032Speter** releases any resources used by the passive daemon. 56938032Speter*/ 57038032Speter 57138032Spetervoid 57238032Speterclrdaemon() 57338032Speter{ 57438032Speter if (DaemonSocket >= 0) 57538032Speter (void) close(DaemonSocket); 57638032Speter DaemonSocket = -1; 57738032Speter} 57838032Speter/* 57938032Speter** SETDAEMONOPTIONS -- set options for running the daemon 58038032Speter** 58138032Speter** Parameters: 58238032Speter** p -- the options line. 58338032Speter** 58438032Speter** Returns: 58538032Speter** none. 58638032Speter*/ 58738032Speter 58838032Spetervoid 58938032Spetersetdaemonoptions(p) 59038032Speter register char *p; 59138032Speter{ 59238032Speter if (DaemonAddr.sa.sa_family == AF_UNSPEC) 59338032Speter DaemonAddr.sa.sa_family = AF_INET; 59438032Speter 59538032Speter while (p != NULL) 59638032Speter { 59738032Speter register char *f; 59838032Speter register char *v; 59938032Speter 60038032Speter while (isascii(*p) && isspace(*p)) 60138032Speter p++; 60238032Speter if (*p == '\0') 60338032Speter break; 60438032Speter f = p; 60538032Speter p = strchr(p, ','); 60638032Speter if (p != NULL) 60738032Speter *p++ = '\0'; 60838032Speter v = strchr(f, '='); 60938032Speter if (v == NULL) 61038032Speter continue; 61138032Speter while (isascii(*++v) && isspace(*v)) 61238032Speter continue; 61338032Speter if (isascii(*f) && islower(*f)) 61438032Speter *f = toupper(*f); 61538032Speter 61638032Speter switch (*f) 61738032Speter { 61838032Speter case 'F': /* address family */ 61938032Speter if (isascii(*v) && isdigit(*v)) 62038032Speter DaemonAddr.sa.sa_family = atoi(v); 62138032Speter#if NETINET 62238032Speter else if (strcasecmp(v, "inet") == 0) 62338032Speter DaemonAddr.sa.sa_family = AF_INET; 62438032Speter#endif 62538032Speter#if NETISO 62638032Speter else if (strcasecmp(v, "iso") == 0) 62738032Speter DaemonAddr.sa.sa_family = AF_ISO; 62838032Speter#endif 62938032Speter#if NETNS 63038032Speter else if (strcasecmp(v, "ns") == 0) 63138032Speter DaemonAddr.sa.sa_family = AF_NS; 63238032Speter#endif 63338032Speter#if NETX25 63438032Speter else if (strcasecmp(v, "x.25") == 0) 63538032Speter DaemonAddr.sa.sa_family = AF_CCITT; 63638032Speter#endif 63738032Speter else 63838032Speter syserr("554 Unknown address family %s in Family=option", v); 63938032Speter break; 64038032Speter 64138032Speter case 'A': /* address */ 64238032Speter switch (DaemonAddr.sa.sa_family) 64338032Speter { 64438032Speter#if NETINET 64538032Speter case AF_INET: 64638032Speter if (isascii(*v) && isdigit(*v)) 64738032Speter DaemonAddr.sin.sin_addr.s_addr = inet_addr(v); 64838032Speter else 64938032Speter { 65038032Speter register struct hostent *hp; 65138032Speter 65238032Speter hp = sm_gethostbyname(v); 65338032Speter if (hp == NULL) 65438032Speter syserr("554 host \"%s\" unknown", v); 65538032Speter else 65638032Speter bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ); 65738032Speter } 65838032Speter break; 65938032Speter#endif 66038032Speter 66138032Speter default: 66238032Speter syserr("554 Address= option unsupported for family %d", 66338032Speter DaemonAddr.sa.sa_family); 66438032Speter break; 66538032Speter } 66638032Speter break; 66738032Speter 66838032Speter case 'P': /* port */ 66938032Speter switch (DaemonAddr.sa.sa_family) 67038032Speter { 67138032Speter#if NETISO 67238032Speter short port; 67338032Speter#endif 67438032Speter 67538032Speter#if NETINET 67638032Speter case AF_INET: 67738032Speter if (isascii(*v) && isdigit(*v)) 67838032Speter DaemonAddr.sin.sin_port = htons(atoi(v)); 67938032Speter else 68038032Speter { 68138032Speter register struct servent *sp; 68238032Speter 68338032Speter sp = getservbyname(v, "tcp"); 68438032Speter if (sp == NULL) 68538032Speter syserr("554 service \"%s\" unknown", v); 68638032Speter else 68738032Speter DaemonAddr.sin.sin_port = sp->s_port; 68838032Speter } 68938032Speter break; 69038032Speter#endif 69138032Speter 69238032Speter#if NETISO 69338032Speter case AF_ISO: 69438032Speter /* assume two byte transport selector */ 69538032Speter if (isascii(*v) && isdigit(*v)) 69638032Speter port = htons(atoi(v)); 69738032Speter else 69838032Speter { 69938032Speter register struct servent *sp; 70038032Speter 70138032Speter sp = getservbyname(v, "tcp"); 70238032Speter if (sp == NULL) 70338032Speter syserr("554 service \"%s\" unknown", v); 70438032Speter else 70538032Speter port = sp->s_port; 70638032Speter } 70738032Speter bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 70838032Speter break; 70938032Speter#endif 71038032Speter 71138032Speter default: 71238032Speter syserr("554 Port= option unsupported for family %d", 71338032Speter DaemonAddr.sa.sa_family); 71438032Speter break; 71538032Speter } 71638032Speter break; 71738032Speter 71838032Speter case 'L': /* listen queue size */ 71938032Speter ListenQueueSize = atoi(v); 72038032Speter break; 72138032Speter 72238032Speter case 'S': /* send buffer size */ 72338032Speter TcpSndBufferSize = atoi(v); 72438032Speter break; 72538032Speter 72638032Speter case 'R': /* receive buffer size */ 72738032Speter TcpRcvBufferSize = atoi(v); 72838032Speter break; 72938032Speter 73038032Speter default: 73138032Speter syserr("554 DaemonPortOptions parameter \"%s\" unknown", f); 73238032Speter } 73338032Speter } 73438032Speter} 73538032Speter/* 73638032Speter** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 73738032Speter** 73838032Speter** Parameters: 73938032Speter** host -- the name of the host. 74038032Speter** port -- the port number to connect to. 74138032Speter** mci -- a pointer to the mail connection information 74238032Speter** structure to be filled in. 74338032Speter** e -- the current envelope. 74438032Speter** 74538032Speter** Returns: 74638032Speter** An exit code telling whether the connection could be 74738032Speter** made and if not why not. 74838032Speter** 74938032Speter** Side Effects: 75038032Speter** none. 75138032Speter*/ 75238032Speter 75338032Speterstatic jmp_buf CtxConnectTimeout; 75438032Speter 75538032Speterstatic void 75638032Speterconnecttimeout() 75738032Speter{ 75838032Speter errno = ETIMEDOUT; 75938032Speter longjmp(CtxConnectTimeout, 1); 76038032Speter} 76138032Speter 76238032SpeterSOCKADDR CurHostAddr; /* address of current host */ 76338032Speter 76438032Speterint 76538032Spetermakeconnection(host, port, mci, e) 76638032Speter char *host; 76738032Speter u_short port; 76838032Speter register MCI *mci; 76938032Speter ENVELOPE *e; 77038032Speter{ 77138032Speter register volatile int addrno = 0; 77238032Speter register volatile int s; 77338032Speter register struct hostent *volatile hp = (struct hostent *)NULL; 77438032Speter SOCKADDR addr; 77538032Speter int sav_errno; 77638032Speter volatile int addrlen; 77738032Speter volatile bool firstconnect; 77838032Speter EVENT *volatile ev = NULL; 77938032Speter 78038032Speter /* 78138032Speter ** Set up the address for the mailer. 78238032Speter ** Accept "[a.b.c.d]" syntax for host name. 78338032Speter */ 78438032Speter 78538032Speter#if NAMED_BIND 78638032Speter h_errno = 0; 78738032Speter#endif 78838032Speter errno = 0; 78938032Speter bzero(&CurHostAddr, sizeof CurHostAddr); 79038032Speter SmtpPhase = mci->mci_phase = "initial connection"; 79138032Speter CurHostName = host; 79238032Speter 79338032Speter if (host[0] == '[') 79438032Speter { 79538032Speter#if NETINET 79638032Speter unsigned long hid = INADDR_NONE; 79738032Speter#endif 79838032Speter register char *p = strchr(host, ']'); 79938032Speter 80038032Speter if (p != NULL) 80138032Speter { 80238032Speter *p = '\0'; 80338032Speter#if NETINET 80438032Speter hid = inet_addr(&host[1]); 80538032Speter if (hid == INADDR_NONE) 80638032Speter#endif 80738032Speter { 80838032Speter /* try it as a host name (avoid MX lookup) */ 80938032Speter hp = sm_gethostbyname(&host[1]); 81038032Speter if (hp == NULL && p[-1] == '.') 81138032Speter { 81238032Speter#if NAMED_BIND 81338032Speter int oldopts = _res.options; 81438032Speter 81538032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 81638032Speter#endif 81738032Speter p[-1] = '\0'; 81838032Speter hp = sm_gethostbyname(&host[1]); 81938032Speter p[-1] = '.'; 82038032Speter#if NAMED_BIND 82138032Speter _res.options = oldopts; 82238032Speter#endif 82338032Speter } 82438032Speter *p = ']'; 82538032Speter goto gothostent; 82638032Speter } 82738032Speter *p = ']'; 82838032Speter } 82938032Speter if (p == NULL) 83038032Speter { 83138032Speter extern char MsgBuf[]; 83238032Speter 83338032Speter usrerr("553 Invalid numeric domain spec \"%s\"", host); 83438032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 83538032Speter return EX_NOHOST; 83638032Speter } 83738032Speter#if NETINET 83838032Speter addr.sin.sin_family = AF_INET; /*XXX*/ 83938032Speter addr.sin.sin_addr.s_addr = hid; 84038032Speter#endif 84138032Speter } 84238032Speter else 84338032Speter { 84438032Speter /* contortion to get around SGI cc complaints */ 84538032Speter { 84638032Speter register char *p = &host[strlen(host) - 1]; 84738032Speter 84838032Speter hp = sm_gethostbyname(host); 84938032Speter if (hp == NULL && *p == '.') 85038032Speter { 85138032Speter#if NAMED_BIND 85238032Speter int oldopts = _res.options; 85338032Speter 85438032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 85538032Speter#endif 85638032Speter *p = '\0'; 85738032Speter hp = sm_gethostbyname(host); 85838032Speter *p = '.'; 85938032Speter#if NAMED_BIND 86038032Speter _res.options = oldopts; 86138032Speter#endif 86238032Speter } 86338032Speter } 86438032Spetergothostent: 86538032Speter if (hp == NULL) 86638032Speter { 86738032Speter#if NAMED_BIND 86838032Speter /* check for name server timeouts */ 86938032Speter if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 87038032Speter (errno == ECONNREFUSED && UseNameServer)) 87138032Speter { 87238032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL); 87338032Speter return EX_TEMPFAIL; 87438032Speter } 87538032Speter#endif 87638032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 87738032Speter return (EX_NOHOST); 87838032Speter } 87938032Speter addr.sa.sa_family = hp->h_addrtype; 88038032Speter switch (hp->h_addrtype) 88138032Speter { 88238032Speter#if NETINET 88338032Speter case AF_INET: 88438032Speter bcopy(hp->h_addr, 88538032Speter &addr.sin.sin_addr, 88638032Speter INADDRSZ); 88738032Speter break; 88838032Speter#endif 88938032Speter 89038032Speter default: 89138032Speter if (hp->h_length > sizeof addr.sa.sa_data) 89238032Speter { 89338032Speter syserr("makeconnection: long sa_data: family %d len %d", 89438032Speter hp->h_addrtype, hp->h_length); 89538032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 89638032Speter return EX_NOHOST; 89738032Speter } 89838032Speter bcopy(hp->h_addr, 89938032Speter addr.sa.sa_data, 90038032Speter hp->h_length); 90138032Speter break; 90238032Speter } 90338032Speter addrno = 1; 90438032Speter } 90538032Speter 90638032Speter /* 90738032Speter ** Determine the port number. 90838032Speter */ 90938032Speter 91038032Speter if (port == 0) 91138032Speter { 91238032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 91338032Speter 91438032Speter if (sp == NULL) 91538032Speter { 91638032Speter if (LogLevel > 2) 91738032Speter sm_syslog(LOG_ERR, NOQID, 91838032Speter "makeconnection: service \"smtp\" unknown"); 91938032Speter port = htons(25); 92038032Speter } 92138032Speter else 92238032Speter port = sp->s_port; 92338032Speter } 92438032Speter 92538032Speter switch (addr.sa.sa_family) 92638032Speter { 92738032Speter#if NETINET 92838032Speter case AF_INET: 92938032Speter addr.sin.sin_port = port; 93038032Speter addrlen = sizeof (struct sockaddr_in); 93138032Speter break; 93238032Speter#endif 93338032Speter 93438032Speter#if NETISO 93538032Speter case AF_ISO: 93638032Speter /* assume two byte transport selector */ 93738032Speter bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 93838032Speter addrlen = sizeof (struct sockaddr_iso); 93938032Speter break; 94038032Speter#endif 94138032Speter 94238032Speter default: 94338032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 94438032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 94538032Speter return (EX_NOHOST); 94638032Speter } 94738032Speter 94838032Speter /* 94938032Speter ** Try to actually open the connection. 95038032Speter */ 95138032Speter 95238032Speter#ifdef XLA 95338032Speter /* if too many connections, don't bother trying */ 95438032Speter if (!xla_noqueue_ok(host)) 95538032Speter return EX_TEMPFAIL; 95638032Speter#endif 95738032Speter 95838032Speter firstconnect = TRUE; 95938032Speter for (;;) 96038032Speter { 96138032Speter if (tTd(16, 1)) 96238032Speter printf("makeconnection (%s [%s])\n", 96338032Speter host, anynet_ntoa(&addr)); 96438032Speter 96538032Speter /* save for logging */ 96638032Speter CurHostAddr = addr; 96738032Speter 96838032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 96938032Speter { 97038032Speter int rport = IPPORT_RESERVED - 1; 97138032Speter 97238032Speter s = rresvport(&rport); 97338032Speter } 97438032Speter else 97538032Speter { 97638032Speter s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 97738032Speter } 97838032Speter if (s < 0) 97938032Speter { 98038032Speter sav_errno = errno; 98138032Speter syserr("makeconnection: cannot create socket"); 98238032Speter#ifdef XLA 98338032Speter xla_host_end(host); 98438032Speter#endif 98538032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 98638032Speter return EX_TEMPFAIL; 98738032Speter } 98838032Speter 98938032Speter#ifdef SO_SNDBUF 99038032Speter if (TcpSndBufferSize > 0) 99138032Speter { 99238032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 99338032Speter (char *) &TcpSndBufferSize, 99438032Speter sizeof(TcpSndBufferSize)) < 0) 99538032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 99638032Speter } 99738032Speter#endif 99838032Speter 99938032Speter if (tTd(16, 1)) 100038032Speter printf("makeconnection: fd=%d\n", s); 100138032Speter 100238032Speter /* turn on network debugging? */ 100338032Speter if (tTd(16, 101)) 100438032Speter { 100538032Speter int on = 1; 100638032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 100738032Speter (char *)&on, sizeof on); 100838032Speter } 100938032Speter if (e->e_xfp != NULL) 101038032Speter (void) fflush(e->e_xfp); /* for debugging */ 101138032Speter errno = 0; /* for debugging */ 101238032Speter 101338032Speter /* 101438032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 101538032Speter ** Time out the connect to avoid this problem. 101638032Speter */ 101738032Speter 101838032Speter if (setjmp(CtxConnectTimeout) == 0) 101938032Speter { 102038032Speter int i; 102138032Speter 102238032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 102338032Speter ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0); 102438032Speter else if (TimeOuts.to_connect != 0) 102538032Speter ev = setevent(TimeOuts.to_connect, connecttimeout, 0); 102638032Speter else 102738032Speter ev = NULL; 102838032Speter 102938032Speter#if _FFR_CONNECTONLYTO_OPTION 103038032Speter /* for testing */ 103138032Speter if (ConnectOnlyTo != 0) 103238032Speter addr.sin.sin_addr.s_addr = ConnectOnlyTo; 103338032Speter#endif 103438032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 103538032Speter sav_errno = errno; 103638032Speter if (ev != NULL) 103738032Speter clrevent(ev); 103838032Speter if (i >= 0) 103938032Speter break; 104038032Speter } 104138032Speter else 104238032Speter sav_errno = errno; 104338032Speter 104438032Speter /* if running demand-dialed connection, try again */ 104538032Speter if (DialDelay > 0 && firstconnect) 104638032Speter { 104738032Speter if (tTd(16, 1)) 104838032Speter printf("Connect failed (%s); trying again...\n", 104938032Speter errstring(sav_errno)); 105038032Speter firstconnect = FALSE; 105138032Speter sleep(DialDelay); 105238032Speter continue; 105338032Speter } 105438032Speter 105538032Speter /* couldn't connect.... figure out why */ 105638032Speter (void) close(s); 105738032Speter 105838032Speter if (LogLevel >= 14) 105938032Speter sm_syslog(LOG_INFO, e->e_id, 106038032Speter "makeconnection (%s [%s]) failed: %s", 106138032Speter host, anynet_ntoa(&addr), 106238032Speter errstring(sav_errno)); 106338032Speter 106438032Speter if (hp != NULL && hp->h_addr_list[addrno] != NULL) 106538032Speter { 106638032Speter if (tTd(16, 1)) 106738032Speter printf("Connect failed (%s); trying new address....\n", 106838032Speter errstring(sav_errno)); 106938032Speter switch (addr.sa.sa_family) 107038032Speter { 107138032Speter#if NETINET 107238032Speter case AF_INET: 107338032Speter bcopy(hp->h_addr_list[addrno++], 107438032Speter &addr.sin.sin_addr, 107538032Speter INADDRSZ); 107638032Speter break; 107738032Speter#endif 107838032Speter 107938032Speter default: 108038032Speter bcopy(hp->h_addr_list[addrno++], 108138032Speter addr.sa.sa_data, 108238032Speter hp->h_length); 108338032Speter break; 108438032Speter } 108538032Speter continue; 108638032Speter } 108738032Speter 108838032Speter /* couldn't open connection */ 108938032Speter#ifdef XLA 109038032Speter xla_host_end(host); 109138032Speter#endif 109238032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 109338032Speter return EX_TEMPFAIL; 109438032Speter } 109538032Speter 109638032Speter /* connection ok, put it into canonical form */ 109738032Speter if ((mci->mci_out = fdopen(s, "w")) == NULL || 109838032Speter (s = dup(s)) < 0 || 109938032Speter (mci->mci_in = fdopen(s, "r")) == NULL) 110038032Speter { 110138032Speter syserr("cannot open SMTP client channel, fd=%d", s); 110238032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 110338032Speter return EX_TEMPFAIL; 110438032Speter } 110538032Speter 110638032Speter mci_setstat(mci, EX_OK, NULL, NULL); 110738032Speter return (EX_OK); 110838032Speter} 110938032Speter/* 111038032Speter** MYHOSTNAME -- return the name of this host. 111138032Speter** 111238032Speter** Parameters: 111338032Speter** hostbuf -- a place to return the name of this host. 111438032Speter** size -- the size of hostbuf. 111538032Speter** 111638032Speter** Returns: 111738032Speter** A list of aliases for this host. 111838032Speter** 111938032Speter** Side Effects: 112038032Speter** Adds numeric codes to $=w. 112138032Speter*/ 112238032Speter 112338032Speterstruct hostent * 112438032Spetermyhostname(hostbuf, size) 112538032Speter char hostbuf[]; 112638032Speter int size; 112738032Speter{ 112838032Speter register struct hostent *hp; 112938032Speter 113038032Speter if (gethostname(hostbuf, size) < 0) 113138032Speter { 113238032Speter (void) strcpy(hostbuf, "localhost"); 113338032Speter } 113438032Speter hp = sm_gethostbyname(hostbuf); 113538032Speter if (hp == NULL) 113638032Speter return NULL; 113738032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 113838032Speter { 113938032Speter (void) strncpy(hostbuf, hp->h_name, size - 1); 114038032Speter hostbuf[size - 1] = '\0'; 114138032Speter } 114238032Speter 114338032Speter /* 114438032Speter ** If there is still no dot in the name, try looking for a 114538032Speter ** dotted alias. 114638032Speter */ 114738032Speter 114838032Speter if (strchr(hostbuf, '.') == NULL) 114938032Speter { 115038032Speter char **ha; 115138032Speter 115238032Speter for (ha = hp->h_aliases; *ha != NULL; ha++) 115338032Speter { 115438032Speter if (strchr(*ha, '.') != NULL) 115538032Speter { 115638032Speter (void) strncpy(hostbuf, *ha, size - 1); 115738032Speter hostbuf[size - 1] = '\0'; 115838032Speter break; 115938032Speter } 116038032Speter } 116138032Speter } 116238032Speter 116338032Speter /* 116438032Speter ** If _still_ no dot, wait for a while and try again -- it is 116538032Speter ** possible that some service is starting up. This can result 116638032Speter ** in excessive delays if the system is badly configured, but 116738032Speter ** there really isn't a way around that, particularly given that 116838032Speter ** the config file hasn't been read at this point. 116938032Speter ** All in all, a bit of a mess. 117038032Speter */ 117138032Speter 117238032Speter if (strchr(hostbuf, '.') == NULL && 117338032Speter !getcanonname(hostbuf, size, TRUE)) 117438032Speter { 117538032Speter sm_syslog(LOG_CRIT, NOQID, 117638032Speter "My unqualified host name (%s) unknown; sleeping for retry", 117738032Speter hostbuf); 117838032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 117938032Speter hostbuf); 118038032Speter sleep(60); 118138032Speter if (!getcanonname(hostbuf, size, TRUE)) 118238032Speter { 118338032Speter sm_syslog(LOG_ALERT, NOQID, 118438032Speter "unable to qualify my own domain name (%s) -- using short name", 118538032Speter hostbuf); 118638032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 118738032Speter hostbuf); 118838032Speter } 118938032Speter } 119038032Speter return (hp); 119138032Speter} 119238032Speter/* 119338032Speter** ADDRCMP -- compare two host addresses 119438032Speter** 119538032Speter** Parameters: 119638032Speter** hp -- hostent structure for the first address 119738032Speter** ha -- actual first address 119838032Speter** sa -- second address 119938032Speter** 120038032Speter** Returns: 120138032Speter** 0 -- if ha and sa match 120238032Speter** else -- they don't match 120338032Speter*/ 120438032Speter 120538032Speterint 120638032Speteraddrcmp(hp, ha, sa) 120738032Speter struct hostent *hp; 120838032Speter char *ha; 120938032Speter SOCKADDR *sa; 121038032Speter{ 121138032Speter switch (sa->sa.sa_family) 121238032Speter { 121338032Speter case AF_INET: 121438032Speter if (hp->h_addrtype == AF_INET) 121538032Speter return bcmp(ha, (char *) &sa->sin.sin_addr, hp->h_length); 121638032Speter break; 121738032Speter 121838032Speter } 121938032Speter return -1; 122038032Speter} 122138032Speter/* 122238032Speter** GETAUTHINFO -- get the real host name asociated with a file descriptor 122338032Speter** 122438032Speter** Uses RFC1413 protocol to try to get info from the other end. 122538032Speter** 122638032Speter** Parameters: 122738032Speter** fd -- the descriptor 122838032Speter** may_be_forged -- an outage that is set to TRUE if the 122938032Speter** forward lookup of RealHostName does not match 123038032Speter** RealHostAddr; set to FALSE if they do match. 123138032Speter** 123238032Speter** Returns: 123338032Speter** The user@host information associated with this descriptor. 123438032Speter*/ 123538032Speter 123638032Speterstatic jmp_buf CtxAuthTimeout; 123738032Speter 123838032Speterstatic void 123938032Speterauthtimeout() 124038032Speter{ 124138032Speter longjmp(CtxAuthTimeout, 1); 124238032Speter} 124338032Speter 124438032Speterchar * 124538032Spetergetauthinfo(fd, may_be_forged) 124638032Speter int fd; 124738032Speter bool *may_be_forged; 124838032Speter{ 124938032Speter SOCKADDR_LEN_T falen; 125038032Speter register char *volatile p = NULL; 125138032Speter SOCKADDR la; 125238032Speter SOCKADDR_LEN_T lalen; 125338032Speter register struct servent *sp; 125438032Speter volatile int s; 125538032Speter int i = 0; 125638032Speter EVENT *ev; 125738032Speter int nleft; 125838032Speter struct hostent *hp; 125938032Speter char *ostype = NULL; 126038032Speter char **ha; 126138032Speter char ibuf[MAXNAME + 1]; 126238032Speter static char hbuf[MAXNAME * 2 + 11]; 126338032Speter 126438032Speter *may_be_forged = FALSE; 126538032Speter falen = sizeof RealHostAddr; 126638032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 126738032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 126838032Speter { 126938032Speter if (i < 0 && errno != ENOTSOCK) 127038032Speter return NULL; 127138032Speter (void) snprintf(hbuf, sizeof hbuf, "%s@localhost", 127238032Speter RealUserName); 127338032Speter if (tTd(9, 1)) 127438032Speter printf("getauthinfo: %s\n", hbuf); 127538032Speter return hbuf; 127638032Speter } 127738032Speter 127838032Speter if (RealHostName == NULL) 127938032Speter { 128038032Speter /* translate that to a host name */ 128138032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 128238032Speter if (strlen(RealHostName) > MAXNAME) 128338032Speter RealHostName[MAXNAME - 1] = '\0'; 128438032Speter } 128538032Speter 128638032Speter /* cross check RealHostName with forward DNS lookup */ 128738032Speter if (anynet_ntoa(&RealHostAddr)[0] == '[' || 128838032Speter RealHostName[0] == '[') 128938032Speter { 129038032Speter /* 129138032Speter ** address is not a socket or have an 129238032Speter ** IP address with no forward lookup 129338032Speter */ 129438032Speter *may_be_forged = FALSE; 129538032Speter } 129638032Speter else 129738032Speter { 129838032Speter /* try to match the reverse against the forward lookup */ 129938032Speter hp = sm_gethostbyname(RealHostName); 130038032Speter 130138032Speter if (hp == NULL) 130238032Speter *may_be_forged = TRUE; 130338032Speter else 130438032Speter { 130538032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 130638032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 130738032Speter break; 130838032Speter *may_be_forged = *ha == NULL; 130938032Speter } 131038032Speter } 131138032Speter 131238032Speter if (TimeOuts.to_ident == 0) 131338032Speter goto noident; 131438032Speter 131538032Speter lalen = sizeof la; 131638032Speter if (RealHostAddr.sa.sa_family != AF_INET || 131738032Speter getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 131838032Speter la.sa.sa_family != AF_INET) 131938032Speter { 132038032Speter /* no ident info */ 132138032Speter goto noident; 132238032Speter } 132338032Speter 132438032Speter /* create ident query */ 132538032Speter (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n", 132638032Speter ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 132738032Speter 132838032Speter /* create local address */ 132938032Speter la.sin.sin_port = 0; 133038032Speter 133138032Speter /* create foreign address */ 133238032Speter sp = getservbyname("auth", "tcp"); 133338032Speter if (sp != NULL) 133438032Speter RealHostAddr.sin.sin_port = sp->s_port; 133538032Speter else 133638032Speter RealHostAddr.sin.sin_port = htons(113); 133738032Speter 133838032Speter s = -1; 133938032Speter if (setjmp(CtxAuthTimeout) != 0) 134038032Speter { 134138032Speter if (s >= 0) 134238032Speter (void) close(s); 134338032Speter goto noident; 134438032Speter } 134538032Speter 134638032Speter /* put a timeout around the whole thing */ 134738032Speter ev = setevent(TimeOuts.to_ident, authtimeout, 0); 134838032Speter 134938032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 135038032Speter s = socket(AF_INET, SOCK_STREAM, 0); 135138032Speter if (s < 0) 135238032Speter { 135338032Speter clrevent(ev); 135438032Speter goto noident; 135538032Speter } 135638032Speter if (bind(s, &la.sa, sizeof la.sin) < 0 || 135738032Speter connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 135838032Speter { 135938032Speter goto closeident; 136038032Speter } 136138032Speter 136238032Speter if (tTd(9, 10)) 136338032Speter printf("getauthinfo: sent %s", ibuf); 136438032Speter 136538032Speter /* send query */ 136638032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 136738032Speter goto closeident; 136838032Speter 136938032Speter /* get result */ 137038032Speter p = &ibuf[0]; 137138032Speter nleft = sizeof ibuf - 1; 137238032Speter while ((i = read(s, p, nleft)) > 0) 137338032Speter { 137438032Speter p += i; 137538032Speter nleft -= i; 137638032Speter *p = '\0'; 137738032Speter if (strchr(ibuf, '\n') != NULL) 137838032Speter break; 137938032Speter } 138038032Speter (void) close(s); 138138032Speter clrevent(ev); 138238032Speter if (i < 0 || p == &ibuf[0]) 138338032Speter goto noident; 138438032Speter 138538032Speter if (*--p == '\n' && *--p == '\r') 138638032Speter p--; 138738032Speter *++p = '\0'; 138838032Speter 138938032Speter if (tTd(9, 3)) 139038032Speter printf("getauthinfo: got %s\n", ibuf); 139138032Speter 139238032Speter /* parse result */ 139338032Speter p = strchr(ibuf, ':'); 139438032Speter if (p == NULL) 139538032Speter { 139638032Speter /* malformed response */ 139738032Speter goto noident; 139838032Speter } 139938032Speter while (isascii(*++p) && isspace(*p)) 140038032Speter continue; 140138032Speter if (strncasecmp(p, "userid", 6) != 0) 140238032Speter { 140338032Speter /* presumably an error string */ 140438032Speter goto noident; 140538032Speter } 140638032Speter p += 6; 140738032Speter while (isascii(*p) && isspace(*p)) 140838032Speter p++; 140938032Speter if (*p++ != ':') 141038032Speter { 141138032Speter /* either useridxx or malformed response */ 141238032Speter goto noident; 141338032Speter } 141438032Speter 141538032Speter /* p now points to the OSTYPE field */ 141638032Speter while (isascii(*p) && isspace(*p)) 141738032Speter p++; 141838032Speter ostype = p; 141938032Speter p = strchr(p, ':'); 142038032Speter if (p == NULL) 142138032Speter { 142238032Speter /* malformed response */ 142338032Speter goto noident; 142438032Speter } 142538032Speter else 142638032Speter { 142738032Speter char *charset; 142838032Speter 142938032Speter *p = '\0'; 143038032Speter charset = strchr(ostype, ','); 143138032Speter if (charset != NULL) 143238032Speter *charset = '\0'; 143338032Speter } 143438032Speter 143538032Speter /* 1413 says don't do this -- but it's broken otherwise */ 143638032Speter while (isascii(*++p) && isspace(*p)) 143738032Speter continue; 143838032Speter 143938032Speter /* p now points to the authenticated name -- copy carefully */ 144038032Speter if (strncasecmp(ostype, "other", 5) == 0 && 144138032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 144238032Speter { 144338032Speter snprintf(hbuf, sizeof hbuf, "IDENT:"); 144438032Speter cleanstrcpy(&hbuf[6], p, MAXNAME); 144538032Speter } 144638032Speter else 144738032Speter cleanstrcpy(hbuf, p, MAXNAME); 144838032Speter i = strlen(hbuf); 144938032Speter snprintf(&hbuf[i], sizeof hbuf - i, "@%s", 145038032Speter RealHostName == NULL ? "localhost" : RealHostName); 145138032Speter goto postident; 145238032Speter 145338032Spetercloseident: 145438032Speter (void) close(s); 145538032Speter clrevent(ev); 145638032Speter 145738032Speternoident: 145838032Speter if (RealHostName == NULL) 145938032Speter { 146038032Speter if (tTd(9, 1)) 146138032Speter printf("getauthinfo: NULL\n"); 146238032Speter return NULL; 146338032Speter } 146438032Speter snprintf(hbuf, sizeof hbuf, "%s", RealHostName); 146538032Speter 146638032Speterpostident: 146738032Speter#if IP_SRCROUTE 146838032Speter# ifndef GET_IPOPT_DST 146938032Speter# define GET_IPOPT_DST(dst) (dst) 147038032Speter# endif 147138032Speter /* 147238032Speter ** Extract IP source routing information. 147338032Speter ** 147438032Speter ** Format of output for a connection from site a through b 147538032Speter ** through c to d: 147638032Speter ** loose: @site-c@site-b:site-a 147738032Speter ** strict: !@site-c@site-b:site-a 147838032Speter ** 147938032Speter ** o - pointer within ipopt_list structure. 148038032Speter ** q - pointer within ls/ss rr route data 148138032Speter ** p - pointer to hbuf 148238032Speter */ 148338032Speter 148438032Speter if (RealHostAddr.sa.sa_family == AF_INET) 148538032Speter { 148638032Speter SOCKOPT_LEN_T ipoptlen; 148738032Speter int j; 148838032Speter u_char *q; 148938032Speter u_char *o; 149038032Speter int l; 149138032Speter struct in_addr addr; 149238032Speter struct ipoption ipopt; 149338032Speter 149438032Speter ipoptlen = sizeof ipopt; 149538032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 149638032Speter (char *) &ipopt, &ipoptlen) < 0) 149738032Speter goto noipsr; 149838032Speter if (ipoptlen == 0) 149938032Speter goto noipsr; 150038032Speter o = (u_char *) ipopt.ipopt_list; 150138032Speter while (o != NULL && o < (u_char *) &ipopt + ipoptlen) 150238032Speter { 150338032Speter switch (*o) 150438032Speter { 150538032Speter case IPOPT_EOL: 150638032Speter o = NULL; 150738032Speter break; 150838032Speter 150938032Speter case IPOPT_NOP: 151038032Speter o++; 151138032Speter break; 151238032Speter 151338032Speter case IPOPT_SSRR: 151438032Speter case IPOPT_LSRR: 151538032Speter /* 151638032Speter ** Source routing. 151738032Speter ** o[0] is the option type (loose/strict). 151838032Speter ** o[1] is the length of this option, 151938032Speter ** including option type and 152038032Speter ** length. 152138032Speter ** o[2] is the pointer into the route 152238032Speter ** data. 152338032Speter ** o[3] begins the route data. 152438032Speter */ 152538032Speter 152638032Speter p = &hbuf[strlen(hbuf)]; 152738032Speter l = sizeof hbuf - (hbuf - p) - 6; 152838032Speter snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s", 152938032Speter *o == IPOPT_SSRR ? "!" : "", 153038032Speter l > 240 ? 120 : l / 2, 153138032Speter inet_ntoa(GET_IPOPT_DST(ipopt.ipopt_dst))); 153238032Speter i = strlen(p); 153338032Speter p += i; 153438032Speter l -= strlen(p); 153538032Speter 153638032Speter j = o[1] / sizeof(struct in_addr) - 1; 153738032Speter 153838032Speter /* q skips length and router pointer to data */ 153938032Speter q = &o[3]; 154038032Speter for ( ; j >= 0; j--) 154138032Speter { 154238032Speter memcpy(&addr, q, sizeof(addr)); 154338032Speter snprintf(p, SPACELEFT(hbuf, p), 154438032Speter "%c%.*s", 154538032Speter j != 0 ? '@' : ':', 154638032Speter l > 240 ? 120 : 154738032Speter j == 0 ? l : l / 2, 154838032Speter inet_ntoa(addr)); 154938032Speter i = strlen(p); 155038032Speter p += i; 155138032Speter l -= i + 1; 155238032Speter q += sizeof(struct in_addr); 155338032Speter } 155438032Speter o += o[1]; 155538032Speter break; 155638032Speter 155738032Speter default: 155838032Speter /* Skip over option */ 155938032Speter o += o[1]; 156038032Speter break; 156138032Speter } 156238032Speter } 156338032Speter snprintf(p, SPACELEFT(hbuf, p), "]"); 156438032Speter goto postipsr; 156538032Speter } 156638032Speter 156738032Speternoipsr: 156838032Speter#endif 156938032Speter if (RealHostName != NULL && RealHostName[0] != '[') 157038032Speter { 157138032Speter p = &hbuf[strlen(hbuf)]; 157238032Speter (void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 157338032Speter anynet_ntoa(&RealHostAddr)); 157438032Speter } 157538032Speter if (*may_be_forged) 157638032Speter { 157738032Speter p = &hbuf[strlen(hbuf)]; 157838032Speter (void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)"); 157938032Speter } 158038032Speter 158138032Speter#if IP_SRCROUTE 158238032Speterpostipsr: 158338032Speter#endif 158438032Speter if (tTd(9, 1)) 158538032Speter printf("getauthinfo: %s\n", hbuf); 158638032Speter return hbuf; 158738032Speter} 158838032Speter/* 158938032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 159038032Speter** 159138032Speter** Parameters: 159238032Speter** map -- a pointer to this map. 159338032Speter** name -- the (presumably unqualified) hostname. 159438032Speter** av -- unused -- for compatibility with other mapping 159538032Speter** functions. 159638032Speter** statp -- an exit status (out parameter) -- set to 159738032Speter** EX_TEMPFAIL if the name server is unavailable. 159838032Speter** 159938032Speter** Returns: 160038032Speter** The mapping, if found. 160138032Speter** NULL if no mapping found. 160238032Speter** 160338032Speter** Side Effects: 160438032Speter** Looks up the host specified in hbuf. If it is not 160538032Speter** the canonical name for that host, return the canonical 160638032Speter** name (unless MF_MATCHONLY is set, which will cause the 160738032Speter** status only to be returned). 160838032Speter*/ 160938032Speter 161038032Speterchar * 161138032Speterhost_map_lookup(map, name, av, statp) 161238032Speter MAP *map; 161338032Speter char *name; 161438032Speter char **av; 161538032Speter int *statp; 161638032Speter{ 161738032Speter register struct hostent *hp; 161838032Speter struct in_addr in_addr; 161938032Speter char *cp; 162038032Speter register STAB *s; 162138032Speter char hbuf[MAXNAME + 1]; 162238032Speter 162338032Speter /* 162438032Speter ** See if we have already looked up this name. If so, just 162538032Speter ** return it. 162638032Speter */ 162738032Speter 162838032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 162938032Speter if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 163038032Speter { 163138032Speter if (tTd(9, 1)) 163238032Speter printf("host_map_lookup(%s) => CACHE %s\n", 163338032Speter name, 163438032Speter s->s_namecanon.nc_cname == NULL 163538032Speter ? "NULL" 163638032Speter : s->s_namecanon.nc_cname); 163738032Speter errno = s->s_namecanon.nc_errno; 163838032Speter#if NAMED_BIND 163938032Speter h_errno = s->s_namecanon.nc_herrno; 164038032Speter#endif 164138032Speter *statp = s->s_namecanon.nc_stat; 164238032Speter if (*statp == EX_TEMPFAIL) 164338032Speter { 164438032Speter CurEnv->e_status = "4.4.3"; 164538032Speter message("851 %s: Name server timeout", 164638032Speter shortenstring(name, 33)); 164738032Speter } 164838032Speter if (*statp != EX_OK) 164938032Speter return NULL; 165038032Speter if (s->s_namecanon.nc_cname == NULL) 165138032Speter { 165238032Speter syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d", 165338032Speter name, 165438032Speter s->s_namecanon.nc_errno, 165538032Speter s->s_namecanon.nc_herrno); 165638032Speter return NULL; 165738032Speter } 165838032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 165938032Speter cp = map_rewrite(map, name, strlen(name), NULL); 166038032Speter else 166138032Speter cp = map_rewrite(map, 166238032Speter s->s_namecanon.nc_cname, 166338032Speter strlen(s->s_namecanon.nc_cname), 166438032Speter av); 166538032Speter return cp; 166638032Speter } 166738032Speter 166838032Speter /* 166938032Speter ** If we are running without a regular network connection (usually 167038032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 167138032Speter ** lookups because those could try to connect to a server. 167238032Speter */ 167338032Speter 167438032Speter if (CurEnv->e_sendmode == SM_DEFER) 167538032Speter { 167638032Speter if (tTd(9, 1)) 167738032Speter printf("host_map_lookup(%s) => DEFERRED\n", name); 167838032Speter *statp = EX_TEMPFAIL; 167938032Speter return NULL; 168038032Speter } 168138032Speter 168238032Speter /* 168338032Speter ** If first character is a bracket, then it is an address 168438032Speter ** lookup. Address is copied into a temporary buffer to 168538032Speter ** strip the brackets and to preserve name if address is 168638032Speter ** unknown. 168738032Speter */ 168838032Speter 168938032Speter if (*name != '[') 169038032Speter { 169138032Speter if (tTd(9, 1)) 169238032Speter printf("host_map_lookup(%s) => ", name); 169338032Speter s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 169438032Speter snprintf(hbuf, sizeof hbuf, "%s", name); 169538032Speter if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX)) 169638032Speter { 169738032Speter if (tTd(9, 1)) 169838032Speter printf("%s\n", hbuf); 169938032Speter s->s_namecanon.nc_stat = EX_OK; 170038032Speter s->s_namecanon.nc_cname = newstr(hbuf); 170138032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 170238032Speter cp = map_rewrite(map, name, strlen(name), NULL); 170338032Speter else 170438032Speter cp = map_rewrite(map, hbuf, strlen(hbuf), av); 170538032Speter return cp; 170638032Speter } 170738032Speter else 170838032Speter { 170938032Speter s->s_namecanon.nc_errno = errno; 171038032Speter#if NAMED_BIND 171138032Speter s->s_namecanon.nc_herrno = h_errno; 171238032Speter if (tTd(9, 1)) 171338032Speter printf("FAIL (%d)\n", h_errno); 171438032Speter switch (h_errno) 171538032Speter { 171638032Speter case TRY_AGAIN: 171738032Speter if (UseNameServer) 171838032Speter { 171938032Speter CurEnv->e_status = "4.4.3"; 172038032Speter message("851 %s: Name server timeout", 172138032Speter shortenstring(name, 33)); 172238032Speter } 172338032Speter *statp = EX_TEMPFAIL; 172438032Speter break; 172538032Speter 172638032Speter case HOST_NOT_FOUND: 172738032Speter case NO_DATA: 172838032Speter *statp = EX_NOHOST; 172938032Speter break; 173038032Speter 173138032Speter case NO_RECOVERY: 173238032Speter *statp = EX_SOFTWARE; 173338032Speter break; 173438032Speter 173538032Speter default: 173638032Speter *statp = EX_UNAVAILABLE; 173738032Speter break; 173838032Speter } 173938032Speter#else 174038032Speter if (tTd(9, 1)) 174138032Speter printf("FAIL\n"); 174238032Speter *statp = EX_NOHOST; 174338032Speter#endif 174438032Speter s->s_namecanon.nc_stat = *statp; 174538032Speter return NULL; 174638032Speter } 174738032Speter } 174838032Speter if ((cp = strchr(name, ']')) == NULL) 174938032Speter return (NULL); 175038032Speter *cp = '\0'; 175138032Speter in_addr.s_addr = inet_addr(&name[1]); 175238032Speter *cp = ']'; 175338032Speter 175438032Speter /* nope -- ask the name server */ 175538032Speter hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 175638032Speter s->s_namecanon.nc_errno = errno; 175738032Speter#if NAMED_BIND 175838032Speter s->s_namecanon.nc_herrno = h_errno; 175938032Speter#endif 176038032Speter s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 176138032Speter if (hp == NULL) 176238032Speter { 176338032Speter s->s_namecanon.nc_stat = *statp = EX_NOHOST; 176438032Speter return (NULL); 176538032Speter } 176638032Speter 176738032Speter /* found a match -- copy out */ 176838032Speter hp->h_name = denlstring((char *) hp->h_name, TRUE, TRUE); 176938032Speter s->s_namecanon.nc_stat = *statp = EX_OK; 177038032Speter s->s_namecanon.nc_cname = newstr(hp->h_name); 177138032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 177238032Speter cp = map_rewrite(map, name, strlen(name), NULL); 177338032Speter else 177438032Speter cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 177538032Speter return cp; 177638032Speter} 177738032Speter 177838032Speter# else /* DAEMON */ 177938032Speter/* code for systems without sophisticated networking */ 178038032Speter 178138032Speter/* 178238032Speter** MYHOSTNAME -- stub version for case of no daemon code. 178338032Speter** 178438032Speter** Can't convert to upper case here because might be a UUCP name. 178538032Speter** 178638032Speter** Mark, you can change this to be anything you want...... 178738032Speter*/ 178838032Speter 178938032Speterchar ** 179038032Spetermyhostname(hostbuf, size) 179138032Speter char hostbuf[]; 179238032Speter int size; 179338032Speter{ 179438032Speter register FILE *f; 179538032Speter 179638032Speter hostbuf[0] = '\0'; 179738032Speter f = fopen("/usr/include/whoami", "r"); 179838032Speter if (f != NULL) 179938032Speter { 180038032Speter (void) fgets(hostbuf, size, f); 180138032Speter fixcrlf(hostbuf, TRUE); 180238032Speter (void) fclose(f); 180338032Speter } 180438032Speter return (NULL); 180538032Speter} 180638032Speter/* 180738032Speter** GETAUTHINFO -- get the real host name asociated with a file descriptor 180838032Speter** 180938032Speter** Parameters: 181038032Speter** fd -- the descriptor 181138032Speter** may_be_forged -- an outage that is set to TRUE if the 181238032Speter** forward lookup of RealHostName does not match 181338032Speter** RealHostAddr; set to FALSE if they do match. 181438032Speter** 181538032Speter** Returns: 181638032Speter** The host name associated with this descriptor, if it can 181738032Speter** be determined. 181838032Speter** NULL otherwise. 181938032Speter** 182038032Speter** Side Effects: 182138032Speter** none 182238032Speter*/ 182338032Speter 182438032Speterchar * 182538032Spetergetauthinfo(fd, may_be_forged) 182638032Speter int fd; 182738032Speter bool *may_be_forged; 182838032Speter{ 182938032Speter *may_be_forged = FALSE; 183038032Speter return NULL; 183138032Speter} 183238032Speter/* 183338032Speter** MAPHOSTNAME -- turn a hostname into canonical form 183438032Speter** 183538032Speter** Parameters: 183638032Speter** map -- a pointer to the database map. 183738032Speter** name -- a buffer containing a hostname. 183838032Speter** avp -- a pointer to a (cf file defined) argument vector. 183938032Speter** statp -- an exit status (out parameter). 184038032Speter** 184138032Speter** Returns: 184238032Speter** mapped host name 184338032Speter** FALSE otherwise. 184438032Speter** 184538032Speter** Side Effects: 184638032Speter** Looks up the host specified in name. If it is not 184738032Speter** the canonical name for that host, replace it with 184838032Speter** the canonical name. If the name is unknown, or it 184938032Speter** is already the canonical name, leave it unchanged. 185038032Speter*/ 185138032Speter 185238032Speter/*ARGSUSED*/ 185338032Speterchar * 185438032Speterhost_map_lookup(map, name, avp, statp) 185538032Speter MAP *map; 185638032Speter char *name; 185738032Speter char **avp; 185838032Speter char *statp; 185938032Speter{ 186038032Speter register struct hostent *hp; 186138032Speter char *cp; 186238032Speter 186338032Speter hp = sm_gethostbyname(name); 186438032Speter if (hp == NULL) 186538032Speter { 186638032Speter *statp = EX_NOHOST; 186738032Speter return NULL; 186838032Speter } 186938032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 187038032Speter cp = map_rewrite(map, name, strlen(name), NULL); 187138032Speter else 187238032Speter cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp); 187338032Speter return cp; 187438032Speter} 187538032Speter 187638032Speter#endif /* DAEMON */ 187738032Speter/* 187838032Speter** HOST_MAP_INIT -- initialize host class structures 187938032Speter*/ 188038032Speter 188138032Speterbool 188238032Speterhost_map_init(map, args) 188338032Speter MAP *map; 188438032Speter char *args; 188538032Speter{ 188638032Speter register char *p = args; 188738032Speter 188838032Speter for (;;) 188938032Speter { 189038032Speter while (isascii(*p) && isspace(*p)) 189138032Speter p++; 189238032Speter if (*p != '-') 189338032Speter break; 189438032Speter switch (*++p) 189538032Speter { 189638032Speter case 'a': 189738032Speter map->map_app = ++p; 189838032Speter break; 189938032Speter 190038032Speter case 'T': 190138032Speter map->map_tapp = ++p; 190238032Speter break; 190338032Speter 190438032Speter case 'm': 190538032Speter map->map_mflags |= MF_MATCHONLY; 190638032Speter break; 190738032Speter 190838032Speter case 't': 190938032Speter map->map_mflags |= MF_NODEFER; 191038032Speter break; 191138032Speter } 191238032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 191338032Speter p++; 191438032Speter if (*p != '\0') 191538032Speter *p++ = '\0'; 191638032Speter } 191738032Speter if (map->map_app != NULL) 191838032Speter map->map_app = newstr(map->map_app); 191938032Speter if (map->map_tapp != NULL) 192038032Speter map->map_tapp = newstr(map->map_tapp); 192138032Speter return TRUE; 192238032Speter} 192338032Speter/* 192438032Speter** ANYNET_NTOA -- convert a network address to printable form. 192538032Speter** 192638032Speter** Parameters: 192738032Speter** sap -- a pointer to a sockaddr structure. 192838032Speter** 192938032Speter** Returns: 193038032Speter** A printable version of that sockaddr. 193138032Speter*/ 193238032Speter 193338032Speter#ifdef USE_SOCK_STREAM 193438032Speter 193538032Speter#if NETLINK 193638032Speter# include <net/if_dl.h> 193738032Speter#endif 193838032Speter 193938032Speterchar * 194038032Speteranynet_ntoa(sap) 194138032Speter register SOCKADDR *sap; 194238032Speter{ 194338032Speter register char *bp; 194438032Speter register char *ap; 194538032Speter int l; 194638032Speter static char buf[100]; 194738032Speter 194838032Speter /* check for null/zero family */ 194938032Speter if (sap == NULL) 195038032Speter return "NULLADDR"; 195138032Speter if (sap->sa.sa_family == 0) 195238032Speter return "0"; 195338032Speter 195438032Speter switch (sap->sa.sa_family) 195538032Speter { 195638032Speter#if NETUNIX 195738032Speter case AF_UNIX: 195838032Speter if (sap->sunix.sun_path[0] != '\0') 195938032Speter snprintf(buf, sizeof buf, "[UNIX: %.64s]", 196038032Speter sap->sunix.sun_path); 196138032Speter else 196238032Speter snprintf(buf, sizeof buf, "[UNIX: localhost]"); 196338032Speter return buf; 196438032Speter#endif 196538032Speter 196638032Speter#if NETINET 196738032Speter case AF_INET: 196838032Speter return inet_ntoa(sap->sin.sin_addr); 196938032Speter#endif 197038032Speter 197138032Speter#if NETLINK 197238032Speter case AF_LINK: 197338032Speter snprintf(buf, sizeof buf, "[LINK: %s]", 197438032Speter link_ntoa((struct sockaddr_dl *) &sap->sa)); 197538032Speter return buf; 197638032Speter#endif 197738032Speter default: 197838032Speter /* this case is needed when nothing is #defined */ 197938032Speter /* in order to keep the switch syntactically correct */ 198038032Speter break; 198138032Speter } 198238032Speter 198338032Speter /* unknown family -- just dump bytes */ 198438032Speter (void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family); 198538032Speter bp = &buf[strlen(buf)]; 198638032Speter ap = sap->sa.sa_data; 198738032Speter for (l = sizeof sap->sa.sa_data; --l >= 0; ) 198838032Speter { 198938032Speter (void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377); 199038032Speter bp += 3; 199138032Speter } 199238032Speter *--bp = '\0'; 199338032Speter return buf; 199438032Speter} 199538032Speter/* 199638032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 199738032Speter** 199838032Speter** Parameters: 199938032Speter** sap -- SOCKADDR pointer 200038032Speter** 200138032Speter** Returns: 200238032Speter** text representation of host name. 200338032Speter** 200438032Speter** Side Effects: 200538032Speter** none. 200638032Speter*/ 200738032Speter 200838032Speterchar * 200938032Speterhostnamebyanyaddr(sap) 201038032Speter register SOCKADDR *sap; 201138032Speter{ 201238032Speter register struct hostent *hp; 201338032Speter int saveretry; 201438032Speter 201538032Speter#if NAMED_BIND 201638032Speter /* shorten name server timeout to avoid higher level timeouts */ 201738032Speter saveretry = _res.retry; 201838032Speter _res.retry = 3; 201938032Speter#endif /* NAMED_BIND */ 202038032Speter 202138032Speter switch (sap->sa.sa_family) 202238032Speter { 202338032Speter#if NETINET 202438032Speter case AF_INET: 202538032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 202638032Speter INADDRSZ, 202738032Speter AF_INET); 202838032Speter break; 202938032Speter#endif 203038032Speter 203138032Speter#if NETISO 203238032Speter case AF_ISO: 203338032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 203438032Speter sizeof sap->siso.siso_addr, 203538032Speter AF_ISO); 203638032Speter break; 203738032Speter#endif 203838032Speter 203938032Speter#if NETUNIX 204038032Speter case AF_UNIX: 204138032Speter hp = NULL; 204238032Speter break; 204338032Speter#endif 204438032Speter 204538032Speter default: 204638032Speter hp = sm_gethostbyaddr(sap->sa.sa_data, 204738032Speter sizeof sap->sa.sa_data, 204838032Speter sap->sa.sa_family); 204938032Speter break; 205038032Speter } 205138032Speter 205238032Speter#if NAMED_BIND 205338032Speter _res.retry = saveretry; 205438032Speter#endif /* NAMED_BIND */ 205538032Speter 205638032Speter if (hp != NULL && hp->h_name[0] != '[' && 205738032Speter inet_addr(hp->h_name) == INADDR_NONE) 205838032Speter return denlstring((char *) hp->h_name, TRUE, TRUE); 205938032Speter#if NETUNIX 206038032Speter else if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 206138032Speter return "localhost"; 206238032Speter#endif 206338032Speter else 206438032Speter { 206538032Speter /* produce a dotted quad */ 206638032Speter static char buf[203]; 206738032Speter 206838032Speter (void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap)); 206938032Speter return buf; 207038032Speter } 207138032Speter} 207238032Speter 207338032Speter#endif /* SOCK_STREAM */ 2074