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