138032Speter/* 2261363Sgshapiro * Copyright (c) 1998-2007, 2009, 2010 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 15168515Sgshapiro#include "map.h" 1638032Speter 17266692SgshapiroSM_RCSID("@(#)$Id: daemon.c,v 8.698 2013-11-22 20:51:55 ca Exp $") 1864562Sgshapiro 1938032Speter#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) 2038032Speter# define USE_SOCK_STREAM 1 2164562Sgshapiro#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */ 2238032Speter 2390792Sgshapiro#if defined(USE_SOCK_STREAM) 2464562Sgshapiro# if NETINET || NETINET6 2564562Sgshapiro# include <arpa/inet.h> 2664562Sgshapiro# endif /* NETINET || NETINET6 */ 2738032Speter# if NAMED_BIND 2838032Speter# ifndef NO_DATA 2938032Speter# define NO_DATA NO_ADDRESS 3064562Sgshapiro# endif /* ! NO_DATA */ 3164562Sgshapiro# endif /* NAMED_BIND */ 3290792Sgshapiro#endif /* defined(USE_SOCK_STREAM) */ 3338032Speter 3490792Sgshapiro#if STARTTLS 35285303Sgshapiro# include <openssl/rand.h> 3690792Sgshapiro#endif /* STARTTLS */ 3738032Speter 38157001Sgshapiro#include <sm/time.h> 3966494Sgshapiro 4090792Sgshapiro#if IP_SRCROUTE && NETINET 4190792Sgshapiro# include <netinet/in_systm.h> 4290792Sgshapiro# include <netinet/ip.h> 4390792Sgshapiro# if HAS_IN_H 4490792Sgshapiro# include <netinet/in.h> 4590792Sgshapiro# ifndef IPOPTION 4690792Sgshapiro# define IPOPTION ip_opts 4790792Sgshapiro# define IP_LIST ip_opts 4890792Sgshapiro# define IP_DST ip_dst 4990792Sgshapiro# endif /* ! IPOPTION */ 5090792Sgshapiro# else /* HAS_IN_H */ 5190792Sgshapiro# include <netinet/ip_var.h> 5290792Sgshapiro# ifndef IPOPTION 5390792Sgshapiro# define IPOPTION ipoption 5490792Sgshapiro# define IP_LIST ipopt_list 5590792Sgshapiro# define IP_DST ipopt_dst 5690792Sgshapiro# endif /* ! IPOPTION */ 5790792Sgshapiro# endif /* HAS_IN_H */ 5890792Sgshapiro#endif /* IP_SRCROUTE && NETINET */ 5938032Speter 6090792Sgshapiro#include <sm/fdset.h> 6138032Speter 62168515Sgshapiro#define DAEMON_C 1 63168515Sgshapiro#include <daemon.h> 6464562Sgshapiro 65141858Sgshapirostatic void connecttimeout __P((int)); 6690792Sgshapirostatic int opendaemonsocket __P((DAEMON_T *, bool)); 6790792Sgshapirostatic unsigned short setupdaemon __P((SOCKADDR *)); 6890792Sgshapirostatic void getrequests_checkdiskspace __P((ENVELOPE *e)); 69141858Sgshapirostatic void setsockaddroptions __P((char *, DAEMON_T *)); 70141858Sgshapirostatic void printdaemonflags __P((DAEMON_T *)); 71141858Sgshapirostatic int addr_family __P((char *)); 72141858Sgshapirostatic int addrcmp __P((struct hostent *, char *, SOCKADDR *)); 73141858Sgshapirostatic void authtimeout __P((int)); 7464562Sgshapiro 7538032Speter/* 7638032Speter** DAEMON.C -- routines to use when running as a daemon. 7738032Speter** 7838032Speter** This entire file is highly dependent on the 4.2 BSD 7938032Speter** interprocess communication primitives. No attempt has 8038032Speter** been made to make this file portable to Version 7, 8138032Speter** Version 6, MPX files, etc. If you should try such a 8238032Speter** thing yourself, I recommend chucking the entire file 8338032Speter** and starting from scratch. Basic semantics are: 8438032Speter** 8538032Speter** getrequests(e) 8638032Speter** Opens a port and initiates a connection. 8738032Speter** Returns in a child. Must set InChannel and 8838032Speter** OutChannel appropriately. 8938032Speter** clrdaemon() 9038032Speter** Close any open files associated with getting 9138032Speter** the connection; this is used when running the queue, 9238032Speter** etc., to avoid having extra file descriptors during 9338032Speter** the queue run and to avoid confusing the network 9438032Speter** code (if it cares). 9590792Sgshapiro** makeconnection(host, port, mci, e, enough) 9638032Speter** Make a connection to the named host on the given 9790792Sgshapiro** port. Returns zero on success, else an exit status 9890792Sgshapiro** describing the error. 9938032Speter** host_map_lookup(map, hbuf, avp, pstat) 10038032Speter** Convert the entry in hbuf into a canonical form. 10138032Speter*/ 10264562Sgshapiro 10390792Sgshapirostatic int NDaemons = 0; /* actual number of daemons */ 10464562Sgshapiro 10590792Sgshapirostatic time_t NextDiskSpaceCheck = 0; 10664562Sgshapiro 10790792Sgshapiro/* 10838032Speter** GETREQUESTS -- open mail IPC port and get requests. 10938032Speter** 11038032Speter** Parameters: 11138032Speter** e -- the current envelope. 11238032Speter** 11338032Speter** Returns: 11464562Sgshapiro** pointer to flags. 11538032Speter** 11638032Speter** Side Effects: 11738032Speter** Waits until some interesting activity occurs. When 11838032Speter** it does, a child is created to process it, and the 11938032Speter** parent waits for completion. Return from this 12038032Speter** routine is always in the child. The file pointers 12138032Speter** "InChannel" and "OutChannel" should be set to point 12238032Speter** to the communication channel. 12390792Sgshapiro** May restart persistent queue runners if they have ended 12490792Sgshapiro** for some reason. 12538032Speter*/ 12638032Speter 12764562SgshapiroBITMAP256 * 12838032Spetergetrequests(e) 12938032Speter ENVELOPE *e; 13038032Speter{ 13138032Speter int t; 13264562Sgshapiro int idx, curdaemon = -1; 13364562Sgshapiro int i, olddaemon = 0; 13490792Sgshapiro#if XDEBUG 13538032Speter bool j_has_dot; 13690792Sgshapiro#endif /* XDEBUG */ 13742575Speter char status[MAXLINE]; 13864562Sgshapiro SOCKADDR sa; 139168515Sgshapiro SOCKADDR_LEN_T len = sizeof(sa); 14094334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 14194334Sgshapiro time_t lastrun; 14294334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 14364562Sgshapiro# if NETUNIX 14442575Speter extern int ControlSocket; 14564562Sgshapiro# endif /* NETUNIX */ 14664562Sgshapiro extern ENVELOPE BlankEnvelope; 14738032Speter 14838032Speter 149125820Sgshapiro /* initialize data for function that generates queue ids */ 150125820Sgshapiro init_qid_alg(); 15190792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 15238032Speter { 15364562Sgshapiro Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr)); 15490792Sgshapiro Daemons[idx].d_firsttime = true; 15564562Sgshapiro Daemons[idx].d_refuse_connections_until = (time_t) 0; 15638032Speter } 15771345Sgshapiro 15838032Speter /* 15938032Speter ** Try to actually open the connection. 16038032Speter */ 16138032Speter 16238032Speter if (tTd(15, 1)) 16364562Sgshapiro { 16490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 16571345Sgshapiro { 16690792Sgshapiro sm_dprintf("getrequests: daemon %s: port %d\n", 16790792Sgshapiro Daemons[idx].d_name, 16890792Sgshapiro ntohs(Daemons[idx].d_port)); 16971345Sgshapiro } 17064562Sgshapiro } 17138032Speter 17238032Speter /* get a socket for the SMTP connection */ 17390792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 17490792Sgshapiro Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true); 17538032Speter 17642575Speter if (opencontrolsocket() < 0) 17742575Speter sm_syslog(LOG_WARNING, NOQID, 17843730Speter "daemon could not open control socket %s: %s", 17990792Sgshapiro ControlSocketName, sm_errstring(errno)); 18042575Speter 18190792Sgshapiro /* If there are any queue runners released reapchild() co-ord's */ 18290792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 18338032Speter 18490792Sgshapiro /* write the pid to file, command line args to syslog */ 18564562Sgshapiro log_sendmail_pid(e); 18638032Speter 18790792Sgshapiro#if XDEBUG 18838032Speter { 18938032Speter char jbuf[MAXHOSTNAMELEN]; 19038032Speter 191168515Sgshapiro expand("\201j", jbuf, sizeof(jbuf), e); 19238032Speter j_has_dot = strchr(jbuf, '.') != NULL; 19338032Speter } 19490792Sgshapiro#endif /* XDEBUG */ 19538032Speter 19642575Speter /* Add parent process as first item */ 197132943Sgshapiro proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1, NULL); 19842575Speter 19938032Speter if (tTd(15, 1)) 20064562Sgshapiro { 20190792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 202203004Sgshapiro sm_dprintf("getrequests: daemon %s: socket %d\n", 20364562Sgshapiro Daemons[idx].d_name, 20464562Sgshapiro Daemons[idx].d_socket); 20564562Sgshapiro } 20638032Speter 20738032Speter for (;;) 20838032Speter { 20938032Speter register pid_t pid; 21038032Speter auto SOCKADDR_LEN_T lotherend; 21190792Sgshapiro bool timedout = false; 21290792Sgshapiro bool control = false; 21364562Sgshapiro int save_errno; 21438032Speter int pipefd[2]; 21590792Sgshapiro time_t now; 21690792Sgshapiro#if STARTTLS 21766494Sgshapiro long seed; 21890792Sgshapiro#endif /* STARTTLS */ 21938032Speter 22038032Speter /* see if we are rejecting connections */ 22190792Sgshapiro (void) sm_blocksignal(SIGALRM); 222120256Sgshapiro CHECK_RESTART; 22364562Sgshapiro 22490792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 22571345Sgshapiro { 22690792Sgshapiro /* 22790792Sgshapiro ** XXX do this call outside the loop? 22890792Sgshapiro ** no: refuse_connections may sleep(). 22990792Sgshapiro */ 23071345Sgshapiro 23190792Sgshapiro now = curtime(); 23290792Sgshapiro if (now < Daemons[idx].d_refuse_connections_until) 23364562Sgshapiro continue; 23490792Sgshapiro if (bitnset(D_DISABLE, Daemons[idx].d_flags)) 23590792Sgshapiro continue; 236168515Sgshapiro if (refuseconnections(e, idx, curdaemon == idx)) 23738032Speter { 23864562Sgshapiro if (Daemons[idx].d_socket >= 0) 23942575Speter { 24071345Sgshapiro /* close socket so peer fails quickly */ 24171345Sgshapiro (void) close(Daemons[idx].d_socket); 24271345Sgshapiro Daemons[idx].d_socket = -1; 24342575Speter } 24442575Speter 24542575Speter /* refuse connections for next 15 seconds */ 24690792Sgshapiro Daemons[idx].d_refuse_connections_until = now + 15; 24738032Speter } 24864562Sgshapiro else if (Daemons[idx].d_socket < 0 || 24964562Sgshapiro Daemons[idx].d_firsttime) 25042575Speter { 25190792Sgshapiro if (!Daemons[idx].d_firsttime && LogLevel > 8) 25271345Sgshapiro sm_syslog(LOG_INFO, NOQID, 25371345Sgshapiro "accepting connections again for daemon %s", 25471345Sgshapiro Daemons[idx].d_name); 25564562Sgshapiro 25671345Sgshapiro /* arrange to (re)open the socket if needed */ 25790792Sgshapiro (void) opendaemonsocket(&Daemons[idx], false); 25890792Sgshapiro Daemons[idx].d_firsttime = false; 25942575Speter } 26038032Speter } 26138032Speter 26277349Sgshapiro /* May have been sleeping above, check again */ 263120256Sgshapiro CHECK_RESTART; 264132943Sgshapiro 26590792Sgshapiro getrequests_checkdiskspace(e); 26671345Sgshapiro 26790792Sgshapiro#if XDEBUG 26838032Speter /* check for disaster */ 26938032Speter { 27038032Speter char jbuf[MAXHOSTNAMELEN]; 27138032Speter 272168515Sgshapiro expand("\201j", jbuf, sizeof(jbuf), e); 27338032Speter if (!wordinclass(jbuf, 'w')) 27438032Speter { 27538032Speter dumpstate("daemon lost $j"); 27638032Speter sm_syslog(LOG_ALERT, NOQID, 27764562Sgshapiro "daemon process doesn't have $j in $=w; see syslog"); 27838032Speter abort(); 27938032Speter } 28038032Speter else if (j_has_dot && strchr(jbuf, '.') == NULL) 28138032Speter { 28238032Speter dumpstate("daemon $j lost dot"); 28338032Speter sm_syslog(LOG_ALERT, NOQID, 28464562Sgshapiro "daemon process $j lost dot; see syslog"); 28538032Speter abort(); 28638032Speter } 28738032Speter } 28890792Sgshapiro#endif /* XDEBUG */ 28938032Speter 29090792Sgshapiro#if 0 29138032Speter /* 29238032Speter ** Andrew Sun <asun@ieps-sun.ml.com> claims that this will 29338032Speter ** fix the SVr4 problem. But it seems to have gone away, 29438032Speter ** so is it worth doing this? 29538032Speter */ 29638032Speter 29742575Speter if (DaemonSocket >= 0 && 29890792Sgshapiro SetNonBlocking(DaemonSocket, false) < 0) 29938032Speter log an error here; 30090792Sgshapiro#endif /* 0 */ 30190792Sgshapiro (void) sm_releasesignal(SIGALRM); 30264562Sgshapiro 30338032Speter for (;;) 30438032Speter { 30590792Sgshapiro bool setproc = false; 30642575Speter int highest = -1; 30738032Speter fd_set readfds; 30838032Speter struct timeval timeout; 30938032Speter 310120256Sgshapiro CHECK_RESTART; 31138032Speter FD_ZERO(&readfds); 31290792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 31342575Speter { 31464562Sgshapiro /* wait for a connection */ 31564562Sgshapiro if (Daemons[idx].d_socket >= 0) 31664562Sgshapiro { 31771345Sgshapiro if (!setproc && 31871345Sgshapiro !bitnset(D_ETRNONLY, 31971345Sgshapiro Daemons[idx].d_flags)) 32064562Sgshapiro { 32190792Sgshapiro sm_setproctitle(true, e, 32264562Sgshapiro "accepting connections"); 32390792Sgshapiro setproc = true; 32464562Sgshapiro } 32564562Sgshapiro if (Daemons[idx].d_socket > highest) 32664562Sgshapiro highest = Daemons[idx].d_socket; 32790792Sgshapiro SM_FD_SET(Daemons[idx].d_socket, 32890792Sgshapiro &readfds); 32964562Sgshapiro } 33042575Speter } 33164562Sgshapiro 33290792Sgshapiro#if NETUNIX 33342575Speter if (ControlSocket >= 0) 33442575Speter { 33542575Speter if (ControlSocket > highest) 33642575Speter highest = ControlSocket; 33790792Sgshapiro SM_FD_SET(ControlSocket, &readfds); 33842575Speter } 33990792Sgshapiro#endif /* NETUNIX */ 34064562Sgshapiro 34177349Sgshapiro timeout.tv_sec = 5; 34238032Speter timeout.tv_usec = 0; 34338032Speter 34442575Speter t = select(highest + 1, FDSET_CAST &readfds, 34564562Sgshapiro NULL, NULL, &timeout); 34642575Speter 34777349Sgshapiro /* Did someone signal while waiting? */ 348120256Sgshapiro CHECK_RESTART; 34971345Sgshapiro 35090792Sgshapiro curdaemon = -1; 35190792Sgshapiro if (doqueuerun()) 35294334Sgshapiro { 35390792Sgshapiro (void) runqueue(true, false, false, false); 35494334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 35594334Sgshapiro lastrun = now; 35694334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 35794334Sgshapiro } 35894334Sgshapiro#if _FFR_QUEUE_RUN_PARANOIA 359157001Sgshapiro else if (CheckQueueRunners > 0 && QueueIntvl > 0 && 360157001Sgshapiro lastrun + QueueIntvl + CheckQueueRunners < now) 36194334Sgshapiro { 36271345Sgshapiro 36394334Sgshapiro /* 36494334Sgshapiro ** set lastrun unconditionally to avoid 36594334Sgshapiro ** calling checkqueuerunner() all the time. 36694334Sgshapiro ** That's also why we currently ignore the 36794334Sgshapiro ** result of the function call. 36894334Sgshapiro */ 36994334Sgshapiro 37094334Sgshapiro (void) checkqueuerunner(); 37194334Sgshapiro lastrun = now; 37294334Sgshapiro } 37394334Sgshapiro#endif /* _FFR_QUEUE_RUN_PARANOIA */ 37494334Sgshapiro 37542575Speter if (t <= 0) 37642575Speter { 37790792Sgshapiro timedout = true; 37842575Speter break; 37942575Speter } 38038032Speter 38190792Sgshapiro control = false; 38238032Speter errno = 0; 38364562Sgshapiro 38464562Sgshapiro /* look "round-robin" for an active socket */ 38590792Sgshapiro if ((idx = olddaemon + 1) >= NDaemons) 38664562Sgshapiro idx = 0; 38790792Sgshapiro for (i = 0; i < NDaemons; i++) 38842575Speter { 38964562Sgshapiro if (Daemons[idx].d_socket >= 0 && 39090792Sgshapiro SM_FD_ISSET(Daemons[idx].d_socket, 39190792Sgshapiro &readfds)) 39264562Sgshapiro { 39364562Sgshapiro lotherend = Daemons[idx].d_socksize; 39473188Sgshapiro memset(&RealHostAddr, '\0', 395168515Sgshapiro sizeof(RealHostAddr)); 39664562Sgshapiro t = accept(Daemons[idx].d_socket, 39764562Sgshapiro (struct sockaddr *)&RealHostAddr, 39864562Sgshapiro &lotherend); 39973188Sgshapiro 40073188Sgshapiro /* 40173188Sgshapiro ** If remote side closes before 40273188Sgshapiro ** accept() finishes, sockaddr 40373188Sgshapiro ** might not be fully filled in. 40473188Sgshapiro */ 40573188Sgshapiro 40673188Sgshapiro if (t >= 0 && 40773188Sgshapiro (lotherend == 0 || 40873188Sgshapiro# ifdef BSD4_4_SOCKADDR 40973188Sgshapiro RealHostAddr.sa.sa_len == 0 || 41073188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 41173188Sgshapiro RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family)) 41273188Sgshapiro { 41373188Sgshapiro (void) close(t); 41473188Sgshapiro t = -1; 41573188Sgshapiro errno = EINVAL; 41673188Sgshapiro } 41764562Sgshapiro olddaemon = curdaemon = idx; 41864562Sgshapiro break; 41964562Sgshapiro } 42090792Sgshapiro if (++idx >= NDaemons) 42164562Sgshapiro idx = 0; 42242575Speter } 42390792Sgshapiro#if NETUNIX 42464562Sgshapiro if (curdaemon == -1 && ControlSocket >= 0 && 42590792Sgshapiro SM_FD_ISSET(ControlSocket, &readfds)) 42642575Speter { 42742575Speter struct sockaddr_un sa_un; 42842575Speter 429168515Sgshapiro lotherend = sizeof(sa_un); 430168515Sgshapiro memset(&sa_un, '\0', sizeof(sa_un)); 43142575Speter t = accept(ControlSocket, 43242575Speter (struct sockaddr *)&sa_un, 43342575Speter &lotherend); 43473188Sgshapiro 43573188Sgshapiro /* 43673188Sgshapiro ** If remote side closes before 43773188Sgshapiro ** accept() finishes, sockaddr 43873188Sgshapiro ** might not be fully filled in. 43973188Sgshapiro */ 44073188Sgshapiro 44173188Sgshapiro if (t >= 0 && 44273188Sgshapiro (lotherend == 0 || 44373188Sgshapiro# ifdef BSD4_4_SOCKADDR 44473188Sgshapiro sa_un.sun_len == 0 || 44573188Sgshapiro# endif /* BSD4_4_SOCKADDR */ 44673188Sgshapiro sa_un.sun_family != AF_UNIX)) 44773188Sgshapiro { 44873188Sgshapiro (void) close(t); 44973188Sgshapiro t = -1; 45073188Sgshapiro errno = EINVAL; 45173188Sgshapiro } 45273188Sgshapiro if (t >= 0) 45390792Sgshapiro control = true; 45442575Speter } 45590792Sgshapiro#else /* NETUNIX */ 45671345Sgshapiro if (curdaemon == -1) 45771345Sgshapiro { 45871345Sgshapiro /* No daemon to service */ 45971345Sgshapiro continue; 46071345Sgshapiro } 46190792Sgshapiro#endif /* NETUNIX */ 46238032Speter if (t >= 0 || errno != EINTR) 46338032Speter break; 46438032Speter } 46542575Speter if (timedout) 46642575Speter { 46790792Sgshapiro timedout = false; 46842575Speter continue; 46942575Speter } 47064562Sgshapiro save_errno = errno; 47190792Sgshapiro (void) sm_blocksignal(SIGALRM); 47238032Speter if (t < 0) 47338032Speter { 47464562Sgshapiro errno = save_errno; 475132943Sgshapiro 476132943Sgshapiro /* let's ignore these temporary errors */ 477132943Sgshapiro if (save_errno == EINTR 478132943Sgshapiro#ifdef EAGAIN 479132943Sgshapiro || save_errno == EAGAIN 480132943Sgshapiro#endif /* EAGAIN */ 481132943Sgshapiro#ifdef ECONNABORTED 482132943Sgshapiro || save_errno == ECONNABORTED 483132943Sgshapiro#endif /* ECONNABORTED */ 484132943Sgshapiro#ifdef EWOULDBLOCK 485132943Sgshapiro || save_errno == EWOULDBLOCK 486132943Sgshapiro#endif /* EWOULDBLOCK */ 487132943Sgshapiro ) 488132943Sgshapiro continue; 489132943Sgshapiro 49038032Speter syserr("getrequests: accept"); 49138032Speter 492159609Sgshapiro if (curdaemon >= 0) 493159609Sgshapiro { 494159609Sgshapiro /* arrange to re-open socket next time around */ 495159609Sgshapiro (void) close(Daemons[curdaemon].d_socket); 496159609Sgshapiro Daemons[curdaemon].d_socket = -1; 49790792Sgshapiro#if SO_REUSEADDR_IS_BROKEN 498159609Sgshapiro /* 499159609Sgshapiro ** Give time for bound socket to be released. 500159609Sgshapiro ** This creates a denial-of-service if you can 501159609Sgshapiro ** force accept() to fail on affected systems. 502159609Sgshapiro */ 50364562Sgshapiro 504159609Sgshapiro Daemons[curdaemon].d_refuse_connections_until = 505159609Sgshapiro curtime() + 15; 50690792Sgshapiro#endif /* SO_REUSEADDR_IS_BROKEN */ 507159609Sgshapiro } 50838032Speter continue; 50938032Speter } 51038032Speter 51164562Sgshapiro if (!control) 51264562Sgshapiro { 51364562Sgshapiro /* set some daemon related macros */ 51464562Sgshapiro switch (Daemons[curdaemon].d_addr.sa.sa_family) 51564562Sgshapiro { 51664562Sgshapiro case AF_UNSPEC: 51790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 51890792Sgshapiro macid("{daemon_family}"), "unspec"); 51964562Sgshapiro break; 520285303Sgshapiro#if NETUNIX 52190792Sgshapiro case AF_UNIX: 52290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 52390792Sgshapiro macid("{daemon_family}"), "local"); 52490792Sgshapiro break; 525285303Sgshapiro#endif /* NETUNIX */ 52690792Sgshapiro#if NETINET 52764562Sgshapiro case AF_INET: 52890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 52990792Sgshapiro macid("{daemon_family}"), "inet"); 53064562Sgshapiro break; 53190792Sgshapiro#endif /* NETINET */ 53290792Sgshapiro#if NETINET6 53364562Sgshapiro case AF_INET6: 53490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 53590792Sgshapiro macid("{daemon_family}"), "inet6"); 53664562Sgshapiro break; 53790792Sgshapiro#endif /* NETINET6 */ 53890792Sgshapiro#if NETISO 53964562Sgshapiro case AF_ISO: 54090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54190792Sgshapiro macid("{daemon_family}"), "iso"); 54264562Sgshapiro break; 54390792Sgshapiro#endif /* NETISO */ 54490792Sgshapiro#if NETNS 54564562Sgshapiro case AF_NS: 54690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 54790792Sgshapiro macid("{daemon_family}"), "ns"); 54864562Sgshapiro break; 54990792Sgshapiro#endif /* NETNS */ 55090792Sgshapiro#if NETX25 55164562Sgshapiro case AF_CCITT: 55290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55390792Sgshapiro macid("{daemon_family}"), "x.25"); 55464562Sgshapiro break; 55590792Sgshapiro#endif /* NETX25 */ 55664562Sgshapiro } 55790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 55890792Sgshapiro macid("{daemon_name}"), 55990792Sgshapiro Daemons[curdaemon].d_name); 56064562Sgshapiro if (Daemons[curdaemon].d_mflags != NULL) 56190792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56290792Sgshapiro macid("{daemon_flags}"), 56390792Sgshapiro Daemons[curdaemon].d_mflags); 56464562Sgshapiro else 56590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 56690792Sgshapiro macid("{daemon_flags}"), ""); 56764562Sgshapiro } 56864562Sgshapiro 56938032Speter /* 570132943Sgshapiro ** If connection rate is exceeded here, connection shall be 571132943Sgshapiro ** refused later by a new call after fork() by the 572132943Sgshapiro ** validate_connection() function. Closing the connection 573132943Sgshapiro ** at this point violates RFC 2821. 574132943Sgshapiro ** Do NOT remove this call, its side effects are needed. 575132943Sgshapiro */ 576132943Sgshapiro 577132943Sgshapiro connection_rate_check(&RealHostAddr, NULL); 578132943Sgshapiro 579132943Sgshapiro /* 58038032Speter ** Create a subprocess to process the mail. 58138032Speter */ 58238032Speter 58338032Speter if (tTd(15, 2)) 58490792Sgshapiro sm_dprintf("getrequests: forking (fd = %d)\n", t); 58538032Speter 58638032Speter /* 58790792Sgshapiro ** Advance state of PRNG. 58890792Sgshapiro ** This is necessary because otherwise all child processes 58964562Sgshapiro ** will produce the same PRN sequence and hence the selection 59064562Sgshapiro ** of a queue directory (and other things, e.g., MX selection) 59164562Sgshapiro ** are not "really" random. 59264562Sgshapiro */ 59390792Sgshapiro#if STARTTLS 59490792Sgshapiro /* XXX get some better "random" data? */ 59566494Sgshapiro seed = get_random(); 59690792Sgshapiro RAND_seed((void *) &NextDiskSpaceCheck, 597168515Sgshapiro sizeof(NextDiskSpaceCheck)); 598168515Sgshapiro RAND_seed((void *) &now, sizeof(now)); 599168515Sgshapiro RAND_seed((void *) &seed, sizeof(seed)); 60090792Sgshapiro#else /* STARTTLS */ 60164562Sgshapiro (void) get_random(); 60290792Sgshapiro#endif /* STARTTLS */ 60364562Sgshapiro 60490792Sgshapiro#if NAMED_BIND 60564562Sgshapiro /* 606132943Sgshapiro ** Update MX records for FallbackMX. 60790792Sgshapiro ** Let's hope this is fast otherwise we screw up the 60890792Sgshapiro ** response time. 60990792Sgshapiro */ 61090792Sgshapiro 611132943Sgshapiro if (FallbackMX != NULL) 612132943Sgshapiro (void) getfallbackmxrr(FallbackMX); 61390792Sgshapiro#endif /* NAMED_BIND */ 61490792Sgshapiro 615110560Sgshapiro if (tTd(93, 100)) 616110560Sgshapiro { 617110560Sgshapiro /* don't fork, handle connection in this process */ 618110560Sgshapiro pid = 0; 61938032Speter pipefd[0] = pipefd[1] = -1; 620110560Sgshapiro } 621110560Sgshapiro else 622110560Sgshapiro { 623110560Sgshapiro /* 624110560Sgshapiro ** Create a pipe to keep the child from writing to 625110560Sgshapiro ** the socket until after the parent has closed 626110560Sgshapiro ** it. Otherwise the parent may hang if the child 627110560Sgshapiro ** has closed it first. 628110560Sgshapiro */ 62938032Speter 630110560Sgshapiro if (pipe(pipefd) < 0) 631110560Sgshapiro pipefd[0] = pipefd[1] = -1; 632110560Sgshapiro 633110560Sgshapiro (void) sm_blocksignal(SIGCHLD); 634110560Sgshapiro pid = fork(); 635110560Sgshapiro if (pid < 0) 63638032Speter { 637110560Sgshapiro syserr("daemon: cannot fork"); 638110560Sgshapiro if (pipefd[0] != -1) 639110560Sgshapiro { 640110560Sgshapiro (void) close(pipefd[0]); 641110560Sgshapiro (void) close(pipefd[1]); 642110560Sgshapiro } 643110560Sgshapiro (void) sm_releasesignal(SIGCHLD); 644110560Sgshapiro (void) sleep(10); 645110560Sgshapiro (void) close(t); 646110560Sgshapiro continue; 64738032Speter } 64838032Speter } 64990792Sgshapiro 65038032Speter if (pid == 0) 65138032Speter { 65238032Speter char *p; 65390792Sgshapiro SM_FILE_T *inchannel, *outchannel = NULL; 65438032Speter 65538032Speter /* 65638032Speter ** CHILD -- return to caller. 65738032Speter ** Collect verified idea of sending host. 65838032Speter ** Verify calling user id if possible here. 65938032Speter */ 66038032Speter 66177349Sgshapiro /* Reset global flags */ 66277349Sgshapiro RestartRequest = NULL; 66390792Sgshapiro RestartWorkGroup = false; 66477349Sgshapiro ShutdownRequest = NULL; 66577349Sgshapiro PendingSignal = 0; 66690792Sgshapiro CurrentPid = getpid(); 667132943Sgshapiro close_sendmail_pid(); 66877349Sgshapiro 66990792Sgshapiro (void) sm_releasesignal(SIGALRM); 67090792Sgshapiro (void) sm_releasesignal(SIGCHLD); 67190792Sgshapiro (void) sm_signal(SIGCHLD, SIG_DFL); 67290792Sgshapiro (void) sm_signal(SIGHUP, SIG_DFL); 67390792Sgshapiro (void) sm_signal(SIGTERM, intsig); 67477349Sgshapiro 67590792Sgshapiro /* turn on profiling */ 67690792Sgshapiro /* SM_PROF(0); */ 67790792Sgshapiro 67890792Sgshapiro /* 67990792Sgshapiro ** Initialize exception stack and default exception 68090792Sgshapiro ** handler for child process. 68190792Sgshapiro */ 68290792Sgshapiro 68390792Sgshapiro sm_exc_newthread(fatal_error); 68490792Sgshapiro 68564562Sgshapiro if (!control) 68664562Sgshapiro { 68790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 68890792Sgshapiro macid("{daemon_addr}"), 68990792Sgshapiro anynet_ntoa(&Daemons[curdaemon].d_addr)); 690168515Sgshapiro (void) sm_snprintf(status, sizeof(status), "%d", 69164562Sgshapiro ntohs(Daemons[curdaemon].d_port)); 69290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 69390792Sgshapiro macid("{daemon_port}"), status); 69464562Sgshapiro } 69564562Sgshapiro 69690792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 69764562Sgshapiro { 69864562Sgshapiro if (Daemons[idx].d_socket >= 0) 69964562Sgshapiro (void) close(Daemons[idx].d_socket); 70080785Sgshapiro Daemons[idx].d_socket = -1; 70164562Sgshapiro } 70242575Speter clrcontrol(); 70338032Speter 70464562Sgshapiro /* Avoid SMTP daemon actions if control command */ 70564562Sgshapiro if (control) 70664562Sgshapiro { 70764562Sgshapiro /* Add control socket process */ 70890792Sgshapiro proc_list_add(CurrentPid, 70990792Sgshapiro "console socket child", 710132943Sgshapiro PROC_CONTROL_CHILD, 0, -1, NULL); 71164562Sgshapiro } 71264562Sgshapiro else 71364562Sgshapiro { 71464562Sgshapiro proc_list_clear(); 71542575Speter 71690792Sgshapiro /* clean up background delivery children */ 71790792Sgshapiro (void) sm_signal(SIGCHLD, reapchild); 71890792Sgshapiro 71964562Sgshapiro /* Add parent process as first child item */ 72090792Sgshapiro proc_list_add(CurrentPid, "daemon child", 721132943Sgshapiro PROC_DAEMON_CHILD, 0, -1, NULL); 72264562Sgshapiro /* don't schedule queue runs if ETRN */ 72364562Sgshapiro QueueIntvl = 0; 724168515Sgshapiro 725168515Sgshapiro /* 726168515Sgshapiro ** Hack: override global variables if 727168515Sgshapiro ** the corresponding DaemonPortOption 728168515Sgshapiro ** is set. 729168515Sgshapiro */ 730147078Sgshapiro#if _FFR_SS_PER_DAEMON 731147078Sgshapiro if (Daemons[curdaemon].d_supersafe != 732168515Sgshapiro DPO_NOTSET) 733168515Sgshapiro SuperSafe = Daemons[curdaemon]. 734168515Sgshapiro d_supersafe; 735147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 736147078Sgshapiro if (Daemons[curdaemon].d_dm != DM_NOTSET) 737147078Sgshapiro set_delivery_mode( 738147078Sgshapiro Daemons[curdaemon].d_dm, e); 73938032Speter 740168515Sgshapiro if (Daemons[curdaemon].d_refuseLA != 741168515Sgshapiro DPO_NOTSET) 742168515Sgshapiro RefuseLA = Daemons[curdaemon]. 743168515Sgshapiro d_refuseLA; 744168515Sgshapiro if (Daemons[curdaemon].d_queueLA != DPO_NOTSET) 745168515Sgshapiro QueueLA = Daemons[curdaemon].d_queueLA; 746168515Sgshapiro if (Daemons[curdaemon].d_delayLA != DPO_NOTSET) 747168515Sgshapiro DelayLA = Daemons[curdaemon].d_delayLA; 748168515Sgshapiro if (Daemons[curdaemon].d_maxchildren != 749168515Sgshapiro DPO_NOTSET) 750168515Sgshapiro MaxChildren = Daemons[curdaemon]. 751168515Sgshapiro d_maxchildren; 752168515Sgshapiro 75390792Sgshapiro sm_setproctitle(true, e, "startup with %s", 75464562Sgshapiro anynet_ntoa(&RealHostAddr)); 75564562Sgshapiro } 75664562Sgshapiro 75738032Speter if (pipefd[0] != -1) 75838032Speter { 75938032Speter auto char c; 76038032Speter 76138032Speter /* 76238032Speter ** Wait for the parent to close the write end 76338032Speter ** of the pipe, which we will see as an EOF. 76438032Speter ** This guarantees that we won't write to the 76538032Speter ** socket until after the parent has closed 76638032Speter ** the pipe. 76738032Speter */ 76838032Speter 76938032Speter /* close the write end of the pipe */ 77038032Speter (void) close(pipefd[1]); 77138032Speter 77238032Speter /* we shouldn't be interrupted, but ... */ 77338032Speter while (read(pipefd[0], &c, 1) < 0 && 77438032Speter errno == EINTR) 77538032Speter continue; 77638032Speter (void) close(pipefd[0]); 77738032Speter } 77838032Speter 77964562Sgshapiro /* control socket processing */ 78064562Sgshapiro if (control) 78164562Sgshapiro { 78264562Sgshapiro control_command(t, e); 78364562Sgshapiro /* NOTREACHED */ 78464562Sgshapiro exit(EX_SOFTWARE); 78564562Sgshapiro } 78664562Sgshapiro 78738032Speter /* determine host name */ 78838032Speter p = hostnamebyanyaddr(&RealHostAddr); 78990792Sgshapiro if (strlen(p) > MAXNAME) /* XXX - 1 ? */ 79038032Speter p[MAXNAME] = '\0'; 79138032Speter RealHostName = newstr(p); 79264562Sgshapiro if (RealHostName[0] == '[') 79364562Sgshapiro { 79490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 79590792Sgshapiro macid("{client_resolve}"), 79690792Sgshapiro h_errno == TRY_AGAIN ? "TEMP" : "FAIL"); 79764562Sgshapiro } 79864562Sgshapiro else 799132943Sgshapiro { 80090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 801132943Sgshapiro macid("{client_resolve}"), "OK"); 802132943Sgshapiro } 80390792Sgshapiro sm_setproctitle(true, e, "startup with %s", p); 80494334Sgshapiro markstats(e, NULL, STATS_CONNECT); 80538032Speter 80690792Sgshapiro if ((inchannel = sm_io_open(SmFtStdiofd, 80790792Sgshapiro SM_TIME_DEFAULT, 80890792Sgshapiro (void *) &t, 809132943Sgshapiro SM_IO_RDONLY_B, 81090792Sgshapiro NULL)) == NULL || 81138032Speter (t = dup(t)) < 0 || 81290792Sgshapiro (outchannel = sm_io_open(SmFtStdiofd, 81390792Sgshapiro SM_TIME_DEFAULT, 81490792Sgshapiro (void *) &t, 815132943Sgshapiro SM_IO_WRONLY_B, 81690792Sgshapiro NULL)) == NULL) 81738032Speter { 81890792Sgshapiro syserr("cannot open SMTP server channel, fd=%d", 81990792Sgshapiro t); 82090792Sgshapiro finis(false, true, EX_OK); 82138032Speter } 82290792Sgshapiro sm_io_automode(inchannel, outchannel); 82338032Speter 82438032Speter InChannel = inchannel; 82538032Speter OutChannel = outchannel; 82690792Sgshapiro DisConnected = false; 82738032Speter 828285303Sgshapiro#if _FFR_XCNCT 829285303Sgshapiro t = xconnect(inchannel); 830285303Sgshapiro if (t <= 0) 831285303Sgshapiro { 832285303Sgshapiro clrbitn(D_XCNCT, Daemons[curdaemon].d_flags); 833285303Sgshapiro clrbitn(D_XCNCT_M, Daemons[curdaemon].d_flags); 834285303Sgshapiro } 835285303Sgshapiro else 836285303Sgshapiro setbitn(t, Daemons[curdaemon].d_flags); 837244833Sgshapiro 838285303Sgshapiro#endif /* _FFR_XCNCT */ 839285303Sgshapiro 84090792Sgshapiro#if XLA 84138032Speter if (!xla_host_ok(RealHostName)) 84238032Speter { 84364562Sgshapiro message("421 4.4.5 Too many SMTP sessions for this host"); 84490792Sgshapiro finis(false, true, EX_OK); 84538032Speter } 84690792Sgshapiro#endif /* XLA */ 84764562Sgshapiro /* find out name for interface of connection */ 84890792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 84990792Sgshapiro NULL), &sa.sa, &len) == 0) 85064562Sgshapiro { 85164562Sgshapiro p = hostnamebyanyaddr(&sa); 85264562Sgshapiro if (tTd(15, 9)) 85390792Sgshapiro sm_dprintf("getreq: got name %s\n", p); 85490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 85590792Sgshapiro macid("{if_name}"), p); 85664562Sgshapiro 85790792Sgshapiro /* 85890792Sgshapiro ** Do this only if it is not the loopback 85990792Sgshapiro ** interface. 86090792Sgshapiro */ 86190792Sgshapiro 86264562Sgshapiro if (!isloopback(sa)) 86364562Sgshapiro { 86490792Sgshapiro char *addr; 86590792Sgshapiro char family[5]; 86690792Sgshapiro 86790792Sgshapiro addr = anynet_ntoa(&sa); 86890792Sgshapiro (void) sm_snprintf(family, 86990792Sgshapiro sizeof(family), 87090792Sgshapiro "%d", sa.sa.sa_family); 87190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 87290792Sgshapiro A_TEMP, 87390792Sgshapiro macid("{if_addr}"), addr); 87490792Sgshapiro macdefine(&BlankEnvelope.e_macro, 87590792Sgshapiro A_TEMP, 87690792Sgshapiro macid("{if_family}"), family); 87764562Sgshapiro if (tTd(15, 7)) 87890792Sgshapiro sm_dprintf("getreq: got addr %s and family %s\n", 87990792Sgshapiro addr, family); 88064562Sgshapiro } 88164562Sgshapiro else 88264562Sgshapiro { 88390792Sgshapiro macdefine(&BlankEnvelope.e_macro, 88490792Sgshapiro A_PERM, 88590792Sgshapiro macid("{if_addr}"), NULL); 88690792Sgshapiro macdefine(&BlankEnvelope.e_macro, 88790792Sgshapiro A_PERM, 88890792Sgshapiro macid("{if_family}"), NULL); 88964562Sgshapiro } 89064562Sgshapiro } 89164562Sgshapiro else 89264562Sgshapiro { 89364562Sgshapiro if (tTd(15, 7)) 89490792Sgshapiro sm_dprintf("getreq: getsockname failed\n"); 89590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 89690792Sgshapiro macid("{if_name}"), NULL); 89790792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 89890792Sgshapiro macid("{if_addr}"), NULL); 89990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 90090792Sgshapiro macid("{if_family}"), NULL); 90164562Sgshapiro } 90238032Speter break; 90338032Speter } 90438032Speter 90538032Speter /* parent -- keep track of children */ 90664562Sgshapiro if (control) 90764562Sgshapiro { 908168515Sgshapiro (void) sm_snprintf(status, sizeof(status), 90990792Sgshapiro "control socket server child"); 910132943Sgshapiro proc_list_add(pid, status, PROC_CONTROL, 0, -1, NULL); 91164562Sgshapiro } 91264562Sgshapiro else 91364562Sgshapiro { 914168515Sgshapiro (void) sm_snprintf(status, sizeof(status), 91590792Sgshapiro "SMTP server child for %s", 91690792Sgshapiro anynet_ntoa(&RealHostAddr)); 917132943Sgshapiro proc_list_add(pid, status, PROC_DAEMON, 0, -1, 918132943Sgshapiro &RealHostAddr); 91964562Sgshapiro } 92090792Sgshapiro (void) sm_releasesignal(SIGCHLD); 92138032Speter 92238032Speter /* close the read end of the synchronization pipe */ 92338032Speter if (pipefd[0] != -1) 92464562Sgshapiro { 92538032Speter (void) close(pipefd[0]); 92664562Sgshapiro pipefd[0] = -1; 92764562Sgshapiro } 92838032Speter 92938032Speter /* close the port so that others will hang (for a while) */ 93038032Speter (void) close(t); 93138032Speter 93238032Speter /* release the child by closing the read end of the sync pipe */ 93338032Speter if (pipefd[1] != -1) 93464562Sgshapiro { 93538032Speter (void) close(pipefd[1]); 93664562Sgshapiro pipefd[1] = -1; 93764562Sgshapiro } 93838032Speter } 93990792Sgshapiro if (tTd(15, 2)) 94090792Sgshapiro sm_dprintf("getreq: returning\n"); 94164562Sgshapiro 94290792Sgshapiro#if MILTER 94390792Sgshapiro /* set the filters for this daemon */ 94490792Sgshapiro if (Daemons[curdaemon].d_inputfilterlist != NULL) 94590792Sgshapiro { 94690792Sgshapiro for (i = 0; 947110560Sgshapiro (i < MAXFILTERS && 948110560Sgshapiro Daemons[curdaemon].d_inputfilters[i] != NULL); 94990792Sgshapiro i++) 95090792Sgshapiro { 95190792Sgshapiro InputFilters[i] = Daemons[curdaemon].d_inputfilters[i]; 95290792Sgshapiro } 95390792Sgshapiro if (i < MAXFILTERS) 95490792Sgshapiro InputFilters[i] = NULL; 95590792Sgshapiro } 95690792Sgshapiro#endif /* MILTER */ 95764562Sgshapiro return &Daemons[curdaemon].d_flags; 95838032Speter} 95990792Sgshapiro 96090792Sgshapiro/* 96190792Sgshapiro** GETREQUESTS_CHECKDISKSPACE -- check available diskspace. 96290792Sgshapiro** 96390792Sgshapiro** Parameters: 96490792Sgshapiro** e -- envelope. 96590792Sgshapiro** 96690792Sgshapiro** Returns: 96790792Sgshapiro** none. 96890792Sgshapiro** 96990792Sgshapiro** Side Effects: 97090792Sgshapiro** Modifies Daemon flags (D_ETRNONLY) if not enough disk space. 97190792Sgshapiro*/ 97290792Sgshapiro 97390792Sgshapirostatic void 97490792Sgshapirogetrequests_checkdiskspace(e) 97590792Sgshapiro ENVELOPE *e; 97690792Sgshapiro{ 97790792Sgshapiro bool logged = false; 97890792Sgshapiro int idx; 97990792Sgshapiro time_t now; 98090792Sgshapiro 98190792Sgshapiro now = curtime(); 98290792Sgshapiro if (now < NextDiskSpaceCheck) 98390792Sgshapiro return; 98490792Sgshapiro 98590792Sgshapiro /* Check if there is available disk space in all queue groups. */ 98690792Sgshapiro if (!enoughdiskspace(0, NULL)) 98790792Sgshapiro { 98890792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 98990792Sgshapiro { 99090792Sgshapiro if (bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 99190792Sgshapiro continue; 99290792Sgshapiro 99390792Sgshapiro /* log only if not logged before */ 99490792Sgshapiro if (!logged) 99590792Sgshapiro { 99690792Sgshapiro if (LogLevel > 8) 99790792Sgshapiro sm_syslog(LOG_INFO, NOQID, 99890792Sgshapiro "rejecting new messages: min free: %ld", 99990792Sgshapiro MinBlocksFree); 100090792Sgshapiro sm_setproctitle(true, e, 100190792Sgshapiro "rejecting new messages: min free: %ld", 100290792Sgshapiro MinBlocksFree); 100390792Sgshapiro logged = true; 100490792Sgshapiro } 100590792Sgshapiro setbitn(D_ETRNONLY, Daemons[idx].d_flags); 100690792Sgshapiro } 100790792Sgshapiro } 100890792Sgshapiro else 100990792Sgshapiro { 101090792Sgshapiro for (idx = 0; idx < NDaemons; ++idx) 101190792Sgshapiro { 101290792Sgshapiro if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags)) 101390792Sgshapiro continue; 101490792Sgshapiro 101590792Sgshapiro /* log only if not logged before */ 101690792Sgshapiro if (!logged) 101790792Sgshapiro { 101890792Sgshapiro if (LogLevel > 8) 101990792Sgshapiro sm_syslog(LOG_INFO, NOQID, 102090792Sgshapiro "accepting new messages (again)"); 102190792Sgshapiro logged = true; 102290792Sgshapiro } 102390792Sgshapiro 102490792Sgshapiro /* title will be set later */ 102590792Sgshapiro clrbitn(D_ETRNONLY, Daemons[idx].d_flags); 102690792Sgshapiro } 102790792Sgshapiro } 102890792Sgshapiro 102990792Sgshapiro /* only check disk space once a minute */ 103090792Sgshapiro NextDiskSpaceCheck = now + 60; 103190792Sgshapiro} 103290792Sgshapiro 103390792Sgshapiro/* 103464562Sgshapiro** OPENDAEMONSOCKET -- open SMTP socket 103538032Speter** 103664562Sgshapiro** Deals with setting all appropriate options. 103738032Speter** 103838032Speter** Parameters: 103964562Sgshapiro** d -- the structure for the daemon to open. 104038032Speter** firsttime -- set if this is the initial open. 104138032Speter** 104238032Speter** Returns: 104338032Speter** Size in bytes of the daemon socket addr. 104438032Speter** 104538032Speter** Side Effects: 104638032Speter** Leaves DaemonSocket set to the open socket. 104738032Speter** Exits if the socket cannot be created. 104838032Speter*/ 104938032Speter 105090792Sgshapiro#define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 105138032Speter 105264562Sgshapirostatic int 105364562Sgshapiroopendaemonsocket(d, firsttime) 105490792Sgshapiro DAEMON_T *d; 105538032Speter bool firsttime; 105638032Speter{ 105738032Speter int on = 1; 105864562Sgshapiro int fdflags; 105964562Sgshapiro SOCKADDR_LEN_T socksize = 0; 106038032Speter int ntries = 0; 106164562Sgshapiro int save_errno; 106238032Speter 106338032Speter if (tTd(15, 2)) 106490792Sgshapiro sm_dprintf("opendaemonsocket(%s)\n", d->d_name); 106538032Speter 106638032Speter do 106738032Speter { 106838032Speter if (ntries > 0) 106964562Sgshapiro (void) sleep(5); 107064562Sgshapiro if (firsttime || d->d_socket < 0) 107138032Speter { 1072285303Sgshapiro#if NETUNIX 107390792Sgshapiro if (d->d_addr.sa.sa_family == AF_UNIX) 107490792Sgshapiro { 107590792Sgshapiro int rval; 107690792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT; 107790792Sgshapiro 107890792Sgshapiro /* if not safe, don't use it */ 107990792Sgshapiro rval = safefile(d->d_addr.sunix.sun_path, 108090792Sgshapiro RunAsUid, RunAsGid, 108190792Sgshapiro RunAsUserName, sff, 108290792Sgshapiro S_IRUSR|S_IWUSR, NULL); 108390792Sgshapiro if (rval != 0) 108490792Sgshapiro { 108590792Sgshapiro save_errno = errno; 108690792Sgshapiro syserr("opendaemonsocket: daemon %s: unsafe domain socket %s", 108790792Sgshapiro d->d_name, 108890792Sgshapiro d->d_addr.sunix.sun_path); 108990792Sgshapiro goto fail; 109090792Sgshapiro } 109190792Sgshapiro 109290792Sgshapiro /* Don't try to overtake an existing socket */ 109390792Sgshapiro (void) unlink(d->d_addr.sunix.sun_path); 109490792Sgshapiro } 1095285303Sgshapiro#endif /* NETUNIX */ 109664562Sgshapiro d->d_socket = socket(d->d_addr.sa.sa_family, 109764562Sgshapiro SOCK_STREAM, 0); 109864562Sgshapiro if (d->d_socket < 0) 109938032Speter { 110064562Sgshapiro save_errno = errno; 110190792Sgshapiro syserr("opendaemonsocket: daemon %s: can't create server SMTP socket", 110290792Sgshapiro d->d_name); 110390792Sgshapiro fail: 110490792Sgshapiro if (bitnset(D_OPTIONAL, d->d_flags) && 110590792Sgshapiro (!transienterror(save_errno) || 110690792Sgshapiro ntries >= MAXOPENTRIES - 1)) 110790792Sgshapiro { 110890792Sgshapiro syserr("opendaemonsocket: daemon %s: optional socket disabled", 110990792Sgshapiro d->d_name); 111090792Sgshapiro setbitn(D_DISABLE, d->d_flags); 111190792Sgshapiro d->d_socket = -1; 111290792Sgshapiro return -1; 111390792Sgshapiro } 111438032Speter severe: 111538032Speter if (LogLevel > 0) 111638032Speter sm_syslog(LOG_ALERT, NOQID, 111790792Sgshapiro "daemon %s: problem creating SMTP socket", 111890792Sgshapiro d->d_name); 111964562Sgshapiro d->d_socket = -1; 112038032Speter continue; 112138032Speter } 112238032Speter 1123285303Sgshapiro if (!SM_FD_OK_SELECT(d->d_socket)) 1124110560Sgshapiro { 1125110560Sgshapiro save_errno = EINVAL; 1126110560Sgshapiro syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large", 1127110560Sgshapiro d->d_name, d->d_socket); 1128110560Sgshapiro goto fail; 1129110560Sgshapiro } 1130110560Sgshapiro 113138032Speter /* turn on network debugging? */ 113238032Speter if (tTd(15, 101)) 113364562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 113438032Speter SO_DEBUG, (char *)&on, 1135168515Sgshapiro sizeof(on)); 113638032Speter 113764562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 1138168515Sgshapiro SO_REUSEADDR, (char *)&on, sizeof(on)); 113964562Sgshapiro (void) setsockopt(d->d_socket, SOL_SOCKET, 1140168515Sgshapiro SO_KEEPALIVE, (char *)&on, sizeof(on)); 114138032Speter 114290792Sgshapiro#ifdef SO_RCVBUF 114364562Sgshapiro if (d->d_tcprcvbufsize > 0) 114438032Speter { 114564562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 114638032Speter SO_RCVBUF, 114764562Sgshapiro (char *) &d->d_tcprcvbufsize, 114864562Sgshapiro sizeof(d->d_tcprcvbufsize)) < 0) 114964562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name); 115038032Speter } 115190792Sgshapiro#endif /* SO_RCVBUF */ 115290792Sgshapiro#ifdef SO_SNDBUF 115364562Sgshapiro if (d->d_tcpsndbufsize > 0) 115464562Sgshapiro { 115564562Sgshapiro if (setsockopt(d->d_socket, SOL_SOCKET, 115664562Sgshapiro SO_SNDBUF, 115764562Sgshapiro (char *) &d->d_tcpsndbufsize, 115864562Sgshapiro sizeof(d->d_tcpsndbufsize)) < 0) 115964562Sgshapiro syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name); 116064562Sgshapiro } 116190792Sgshapiro#endif /* SO_SNDBUF */ 116238032Speter 116364562Sgshapiro if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 || 116464562Sgshapiro fcntl(d->d_socket, F_SETFD, 116564562Sgshapiro fdflags | FD_CLOEXEC) == -1) 116638032Speter { 116764562Sgshapiro save_errno = errno; 116864562Sgshapiro syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s", 116964562Sgshapiro d->d_name, 117064562Sgshapiro fdflags == -1 ? "get" : "set", 117190792Sgshapiro sm_errstring(save_errno)); 117264562Sgshapiro (void) close(d->d_socket); 117364562Sgshapiro goto severe; 117464562Sgshapiro } 117564562Sgshapiro 117664562Sgshapiro switch (d->d_addr.sa.sa_family) 117764562Sgshapiro { 1178285303Sgshapiro#ifdef NETUNIX 117990792Sgshapiro case AF_UNIX: 1180168515Sgshapiro socksize = sizeof(d->d_addr.sunix); 118190792Sgshapiro break; 1182285303Sgshapiro#endif /* NETUNIX */ 118390792Sgshapiro#if NETINET 118438032Speter case AF_INET: 1185168515Sgshapiro socksize = sizeof(d->d_addr.sin); 118638032Speter break; 118790792Sgshapiro#endif /* NETINET */ 118838032Speter 118990792Sgshapiro#if NETINET6 119064562Sgshapiro case AF_INET6: 1191168515Sgshapiro socksize = sizeof(d->d_addr.sin6); 119264562Sgshapiro break; 119390792Sgshapiro#endif /* NETINET6 */ 119464562Sgshapiro 119590792Sgshapiro#if NETISO 119638032Speter case AF_ISO: 1197168515Sgshapiro socksize = sizeof(d->d_addr.siso); 119838032Speter break; 119990792Sgshapiro#endif /* NETISO */ 120038032Speter 120138032Speter default: 1202168515Sgshapiro socksize = sizeof(d->d_addr); 120338032Speter break; 120438032Speter } 120538032Speter 120664562Sgshapiro if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0) 120738032Speter { 120838032Speter /* probably another daemon already */ 120964562Sgshapiro save_errno = errno; 121064562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot bind", 121164562Sgshapiro d->d_name); 121264562Sgshapiro (void) close(d->d_socket); 121390792Sgshapiro goto fail; 121438032Speter } 121538032Speter } 121664562Sgshapiro if (!firsttime && 121764562Sgshapiro listen(d->d_socket, d->d_listenqueue) < 0) 121838032Speter { 121964562Sgshapiro save_errno = errno; 122064562Sgshapiro syserr("opendaemonsocket: daemon %s: cannot listen", 122164562Sgshapiro d->d_name); 122264562Sgshapiro (void) close(d->d_socket); 122338032Speter goto severe; 122438032Speter } 122538032Speter return socksize; 122664562Sgshapiro } while (ntries++ < MAXOPENTRIES && transienterror(save_errno)); 122764562Sgshapiro syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting", 122864562Sgshapiro d->d_name); 122964562Sgshapiro /* NOTREACHED */ 123038032Speter return -1; /* avoid compiler warning on IRIX */ 123138032Speter} 123290792Sgshapiro/* 123364562Sgshapiro** SETUPDAEMON -- setup socket for daemon 123464562Sgshapiro** 123564562Sgshapiro** Parameters: 123664562Sgshapiro** daemonaddr -- socket for daemon 123764562Sgshapiro** 123864562Sgshapiro** Returns: 123964562Sgshapiro** port number on which daemon should run 124064562Sgshapiro** 124164562Sgshapiro*/ 124290792Sgshapiro 124390792Sgshapirostatic unsigned short 124464562Sgshapirosetupdaemon(daemonaddr) 124564562Sgshapiro SOCKADDR *daemonaddr; 124664562Sgshapiro{ 124790792Sgshapiro unsigned short port; 124864562Sgshapiro 124964562Sgshapiro /* 125064562Sgshapiro ** Set up the address for the mailer. 125164562Sgshapiro */ 125264562Sgshapiro 125364562Sgshapiro if (daemonaddr->sa.sa_family == AF_UNSPEC) 125464562Sgshapiro { 1255168515Sgshapiro memset(daemonaddr, '\0', sizeof(*daemonaddr)); 125690792Sgshapiro#if NETINET 125764562Sgshapiro daemonaddr->sa.sa_family = AF_INET; 125890792Sgshapiro#endif /* NETINET */ 125964562Sgshapiro } 126064562Sgshapiro 126164562Sgshapiro switch (daemonaddr->sa.sa_family) 126264562Sgshapiro { 126390792Sgshapiro#if NETINET 126464562Sgshapiro case AF_INET: 126564562Sgshapiro if (daemonaddr->sin.sin_addr.s_addr == 0) 1266182352Sgshapiro daemonaddr->sin.sin_addr.s_addr = 1267182352Sgshapiro LocalDaemon ? htonl(INADDR_LOOPBACK) : INADDR_ANY; 126864562Sgshapiro port = daemonaddr->sin.sin_port; 126964562Sgshapiro break; 127090792Sgshapiro#endif /* NETINET */ 127164562Sgshapiro 127290792Sgshapiro#if NETINET6 127364562Sgshapiro case AF_INET6: 127464562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr)) 1275182352Sgshapiro daemonaddr->sin6.sin6_addr = 1276223067Sgshapiro (LocalDaemon && V6LoopbackAddrFound) ? 1277223067Sgshapiro in6addr_loopback : in6addr_any; 127864562Sgshapiro port = daemonaddr->sin6.sin6_port; 127964562Sgshapiro break; 128090792Sgshapiro#endif /* NETINET6 */ 128164562Sgshapiro 128264562Sgshapiro default: 128364562Sgshapiro /* unknown protocol */ 128464562Sgshapiro port = 0; 128564562Sgshapiro break; 128664562Sgshapiro } 128764562Sgshapiro if (port == 0) 128864562Sgshapiro { 128990792Sgshapiro#ifdef NO_GETSERVBYNAME 129064562Sgshapiro port = htons(25); 129190792Sgshapiro#else /* NO_GETSERVBYNAME */ 129264562Sgshapiro { 129364562Sgshapiro register struct servent *sp; 129464562Sgshapiro 129564562Sgshapiro sp = getservbyname("smtp", "tcp"); 129664562Sgshapiro if (sp == NULL) 129764562Sgshapiro { 129864562Sgshapiro syserr("554 5.3.5 service \"smtp\" unknown"); 129964562Sgshapiro port = htons(25); 130064562Sgshapiro } 130164562Sgshapiro else 130264562Sgshapiro port = sp->s_port; 130364562Sgshapiro } 130490792Sgshapiro#endif /* NO_GETSERVBYNAME */ 130564562Sgshapiro } 130664562Sgshapiro 130764562Sgshapiro switch (daemonaddr->sa.sa_family) 130864562Sgshapiro { 130990792Sgshapiro#if NETINET 131064562Sgshapiro case AF_INET: 131164562Sgshapiro daemonaddr->sin.sin_port = port; 131264562Sgshapiro break; 131390792Sgshapiro#endif /* NETINET */ 131464562Sgshapiro 131590792Sgshapiro#if NETINET6 131664562Sgshapiro case AF_INET6: 131764562Sgshapiro daemonaddr->sin6.sin6_port = port; 131864562Sgshapiro break; 131990792Sgshapiro#endif /* NETINET6 */ 132064562Sgshapiro 132164562Sgshapiro default: 132264562Sgshapiro /* unknown protocol */ 132364562Sgshapiro break; 132464562Sgshapiro } 132590792Sgshapiro return port; 132664562Sgshapiro} 132790792Sgshapiro/* 132838032Speter** CLRDAEMON -- reset the daemon connection 132938032Speter** 133038032Speter** Parameters: 133138032Speter** none. 133238032Speter** 133338032Speter** Returns: 133438032Speter** none. 133538032Speter** 133638032Speter** Side Effects: 133738032Speter** releases any resources used by the passive daemon. 133838032Speter*/ 133938032Speter 134038032Spetervoid 134138032Speterclrdaemon() 134238032Speter{ 134364562Sgshapiro int i; 134464562Sgshapiro 134590792Sgshapiro for (i = 0; i < NDaemons; i++) 134664562Sgshapiro { 134764562Sgshapiro if (Daemons[i].d_socket >= 0) 134864562Sgshapiro (void) close(Daemons[i].d_socket); 134964562Sgshapiro Daemons[i].d_socket = -1; 135064562Sgshapiro } 135138032Speter} 135290792Sgshapiro 135390792Sgshapiro/* 135490792Sgshapiro** GETMODIFIERS -- get modifier flags 135590792Sgshapiro** 135690792Sgshapiro** Parameters: 135790792Sgshapiro** v -- the modifiers (input text line). 135890792Sgshapiro** modifiers -- pointer to flag field to represent modifiers. 135990792Sgshapiro** 136090792Sgshapiro** Returns: 136190792Sgshapiro** (xallocat()ed) string representation of modifiers. 136290792Sgshapiro** 136390792Sgshapiro** Side Effects: 136490792Sgshapiro** fills in modifiers. 136590792Sgshapiro*/ 136690792Sgshapiro 136790792Sgshapirochar * 136890792Sgshapirogetmodifiers(v, modifiers) 136990792Sgshapiro char *v; 137090792Sgshapiro BITMAP256 modifiers; 137190792Sgshapiro{ 137290792Sgshapiro int l; 137390792Sgshapiro char *h, *f, *flags; 137490792Sgshapiro 137590792Sgshapiro /* maximum length of flags: upper case Option -> "OO " */ 137690792Sgshapiro l = 3 * strlen(v) + 3; 137790792Sgshapiro 137890792Sgshapiro /* is someone joking? */ 137990792Sgshapiro if (l < 0 || l > 256) 138090792Sgshapiro { 138190792Sgshapiro if (LogLevel > 2) 138290792Sgshapiro sm_syslog(LOG_ERR, NOQID, 138390792Sgshapiro "getmodifiers too long, ignored"); 138490792Sgshapiro return NULL; 138590792Sgshapiro } 138690792Sgshapiro flags = xalloc(l); 138790792Sgshapiro f = flags; 138890792Sgshapiro clrbitmap(modifiers); 138990792Sgshapiro for (h = v; *h != '\0'; h++) 139090792Sgshapiro { 139190792Sgshapiro if (isascii(*h) && !isspace(*h) && isprint(*h)) 139290792Sgshapiro { 139390792Sgshapiro setbitn(*h, modifiers); 139490792Sgshapiro if (flags != f) 139590792Sgshapiro *flags++ = ' '; 139690792Sgshapiro *flags++ = *h; 139790792Sgshapiro if (isupper(*h)) 139890792Sgshapiro *flags++ = *h; 139990792Sgshapiro } 140090792Sgshapiro } 140190792Sgshapiro *flags++ = '\0'; 140290792Sgshapiro return f; 140390792Sgshapiro} 140490792Sgshapiro 140590792Sgshapiro/* 140690792Sgshapiro** CHKDAEMONMODIFIERS -- check whether all daemons have set a flag. 140790792Sgshapiro** 140890792Sgshapiro** Parameters: 140990792Sgshapiro** flag -- the flag to test. 141090792Sgshapiro** 141190792Sgshapiro** Returns: 141290792Sgshapiro** true iff all daemons have set flag. 141390792Sgshapiro*/ 141490792Sgshapiro 141590792Sgshapirobool 141690792Sgshapirochkdaemonmodifiers(flag) 141790792Sgshapiro int flag; 141890792Sgshapiro{ 141990792Sgshapiro int i; 142090792Sgshapiro 142190792Sgshapiro for (i = 0; i < NDaemons; i++) 142290792Sgshapiro if (!bitnset((char) flag, Daemons[i].d_flags)) 142390792Sgshapiro return false; 142490792Sgshapiro return true; 142590792Sgshapiro} 142690792Sgshapiro 142790792Sgshapiro/* 142864562Sgshapiro** SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client) 142938032Speter** 143038032Speter** Parameters: 143138032Speter** p -- the options line. 143264562Sgshapiro** d -- the daemon structure to fill in. 143338032Speter** 143438032Speter** Returns: 143538032Speter** none. 143638032Speter*/ 143738032Speter 143864562Sgshapirostatic void 143964562Sgshapirosetsockaddroptions(p, d) 1440141858Sgshapiro char *p; 144190792Sgshapiro DAEMON_T *d; 144238032Speter{ 144390792Sgshapiro#if NETISO 144471345Sgshapiro short portno; 144590792Sgshapiro#endif /* NETISO */ 144671345Sgshapiro char *port = NULL; 144771345Sgshapiro char *addr = NULL; 144838032Speter 144990792Sgshapiro#if NETINET 145064562Sgshapiro if (d->d_addr.sa.sa_family == AF_UNSPEC) 145164562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 145290792Sgshapiro#endif /* NETINET */ 1453157001Sgshapiro#if _FFR_SS_PER_DAEMON 1454168515Sgshapiro d->d_supersafe = DPO_NOTSET; 1455157001Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1456157001Sgshapiro d->d_dm = DM_NOTSET; 1457168515Sgshapiro d->d_refuseLA = DPO_NOTSET; 1458168515Sgshapiro d->d_queueLA = DPO_NOTSET; 1459168515Sgshapiro d->d_delayLA = DPO_NOTSET; 1460168515Sgshapiro d->d_maxchildren = DPO_NOTSET; 146164562Sgshapiro 146238032Speter while (p != NULL) 146338032Speter { 146438032Speter register char *f; 146538032Speter register char *v; 146638032Speter 146738032Speter while (isascii(*p) && isspace(*p)) 146838032Speter p++; 146938032Speter if (*p == '\0') 147038032Speter break; 147138032Speter f = p; 147238032Speter p = strchr(p, ','); 147338032Speter if (p != NULL) 147438032Speter *p++ = '\0'; 147538032Speter v = strchr(f, '='); 147638032Speter if (v == NULL) 147738032Speter continue; 147838032Speter while (isascii(*++v) && isspace(*v)) 147938032Speter continue; 148038032Speter 148138032Speter switch (*f) 148238032Speter { 1483147078Sgshapiro case 'A': /* address */ 1484168515Sgshapiro#if !_FFR_DPO_CS 1485168515Sgshapiro case 'a': 1486168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1487147078Sgshapiro addr = v; 1488147078Sgshapiro break; 1489147078Sgshapiro 1490168515Sgshapiro case 'c': 1491168515Sgshapiro d->d_maxchildren = atoi(v); 1492168515Sgshapiro break; 1493168515Sgshapiro 1494147078Sgshapiro case 'D': /* DeliveryMode */ 1495147078Sgshapiro switch (*v) 1496147078Sgshapiro { 1497147078Sgshapiro case SM_QUEUE: 1498147078Sgshapiro case SM_DEFER: 1499147078Sgshapiro case SM_DELIVER: 1500157001Sgshapiro case SM_FORK: 1501285303Sgshapiro#if _FFR_PROXY 1502285303Sgshapiro case SM_PROXY_REQ: 1503285303Sgshapiro#endif /* _FFR_PROXY */ 1504147078Sgshapiro d->d_dm = *v; 1505147078Sgshapiro break; 1506147078Sgshapiro default: 1507147078Sgshapiro syserr("554 5.3.5 Unknown delivery mode %c", 1508147078Sgshapiro *v); 1509147078Sgshapiro break; 1510147078Sgshapiro } 1511147078Sgshapiro break; 1512147078Sgshapiro 1513168515Sgshapiro case 'd': /* delayLA */ 1514168515Sgshapiro d->d_delayLA = atoi(v); 1515168515Sgshapiro break; 1516168515Sgshapiro 151738032Speter case 'F': /* address family */ 1518168515Sgshapiro#if !_FFR_DPO_CS 1519168515Sgshapiro case 'f': 1520168515Sgshapiro#endif /* !_FFR_DPO_CS */ 152138032Speter if (isascii(*v) && isdigit(*v)) 152264562Sgshapiro d->d_addr.sa.sa_family = atoi(v); 1523285303Sgshapiro#ifdef NETUNIX 152490792Sgshapiro else if (sm_strcasecmp(v, "unix") == 0 || 152590792Sgshapiro sm_strcasecmp(v, "local") == 0) 152690792Sgshapiro d->d_addr.sa.sa_family = AF_UNIX; 1527285303Sgshapiro#endif /* NETUNIX */ 152890792Sgshapiro#if NETINET 152990792Sgshapiro else if (sm_strcasecmp(v, "inet") == 0) 153064562Sgshapiro d->d_addr.sa.sa_family = AF_INET; 153190792Sgshapiro#endif /* NETINET */ 153290792Sgshapiro#if NETINET6 153390792Sgshapiro else if (sm_strcasecmp(v, "inet6") == 0) 153464562Sgshapiro d->d_addr.sa.sa_family = AF_INET6; 153590792Sgshapiro#endif /* NETINET6 */ 153690792Sgshapiro#if NETISO 153790792Sgshapiro else if (sm_strcasecmp(v, "iso") == 0) 153864562Sgshapiro d->d_addr.sa.sa_family = AF_ISO; 153990792Sgshapiro#endif /* NETISO */ 154090792Sgshapiro#if NETNS 154190792Sgshapiro else if (sm_strcasecmp(v, "ns") == 0) 154264562Sgshapiro d->d_addr.sa.sa_family = AF_NS; 154390792Sgshapiro#endif /* NETNS */ 154490792Sgshapiro#if NETX25 154590792Sgshapiro else if (sm_strcasecmp(v, "x.25") == 0) 154664562Sgshapiro d->d_addr.sa.sa_family = AF_CCITT; 154790792Sgshapiro#endif /* NETX25 */ 154838032Speter else 154964562Sgshapiro syserr("554 5.3.5 Unknown address family %s in Family=option", 155064562Sgshapiro v); 155138032Speter break; 155238032Speter 155390792Sgshapiro#if MILTER 155490792Sgshapiro case 'I': 1555168515Sgshapiro# if !_FFR_DPO_CS 1556168515Sgshapiro case 'i': 1557168515Sgshapiro# endif /* !_FFR_DPO_CS */ 155890792Sgshapiro d->d_inputfilterlist = v; 155990792Sgshapiro break; 156090792Sgshapiro#endif /* MILTER */ 156190792Sgshapiro 156238032Speter case 'L': /* listen queue size */ 1563168515Sgshapiro#if !_FFR_DPO_CS 1564168515Sgshapiro case 'l': 1565168515Sgshapiro#endif /* !_FFR_DPO_CS */ 156664562Sgshapiro d->d_listenqueue = atoi(v); 156738032Speter break; 156838032Speter 156964562Sgshapiro case 'M': /* modifiers (flags) */ 1570168515Sgshapiro#if !_FFR_DPO_CS 1571168515Sgshapiro case 'm': 1572168515Sgshapiro#endif /* !_FFR_DPO_CS */ 157390792Sgshapiro d->d_mflags = getmodifiers(v, d->d_flags); 157464562Sgshapiro break; 157564562Sgshapiro 1576147078Sgshapiro case 'N': /* name */ 1577168515Sgshapiro#if !_FFR_DPO_CS 1578168515Sgshapiro case 'n': 1579168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1580147078Sgshapiro d->d_name = v; 158138032Speter break; 158238032Speter 1583147078Sgshapiro case 'P': /* port */ 1584168515Sgshapiro#if !_FFR_DPO_CS 1585168515Sgshapiro case 'p': 1586168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1587147078Sgshapiro port = v; 1588147078Sgshapiro break; 1589147078Sgshapiro 1590168515Sgshapiro case 'q': 1591168515Sgshapiro d->d_queueLA = atoi(v); 1592168515Sgshapiro break; 1593168515Sgshapiro 159438032Speter case 'R': /* receive buffer size */ 159564562Sgshapiro d->d_tcprcvbufsize = atoi(v); 159638032Speter break; 159738032Speter 1598168515Sgshapiro case 'r': 1599168515Sgshapiro d->d_refuseLA = atoi(v); 1600168515Sgshapiro break; 1601168515Sgshapiro 1602147078Sgshapiro case 'S': /* send buffer size */ 1603168515Sgshapiro#if !_FFR_DPO_CS 1604168515Sgshapiro case 's': 1605168515Sgshapiro#endif /* !_FFR_DPO_CS */ 1606147078Sgshapiro d->d_tcpsndbufsize = atoi(v); 160764562Sgshapiro break; 160864562Sgshapiro 1609147078Sgshapiro#if _FFR_SS_PER_DAEMON 1610147078Sgshapiro case 'T': /* SuperSafe */ 1611147078Sgshapiro if (tolower(*v) == 'i') 1612147078Sgshapiro d->d_supersafe = SAFE_INTERACTIVE; 1613147078Sgshapiro else if (tolower(*v) == 'p') 1614147078Sgshapiro# if MILTER 1615147078Sgshapiro d->d_supersafe = SAFE_REALLY_POSTMILTER; 1616147078Sgshapiro# else /* MILTER */ 1617147078Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1618147078Sgshapiro "Warning: SuperSafe=PostMilter requires Milter support (-DMILTER)\n"); 1619147078Sgshapiro# endif /* MILTER */ 1620147078Sgshapiro else 1621147078Sgshapiro d->d_supersafe = atobool(v) ? SAFE_REALLY 1622147078Sgshapiro : SAFE_NO; 1623147078Sgshapiro break; 1624147078Sgshapiro#endif /* _FFR_SS_PER_DAEMON */ 1625147078Sgshapiro 162638032Speter default: 162764562Sgshapiro syserr("554 5.3.5 PortOptions parameter \"%s\" unknown", 162864562Sgshapiro f); 162938032Speter } 163038032Speter } 163171345Sgshapiro 163271345Sgshapiro /* Check addr and port after finding family */ 163371345Sgshapiro if (addr != NULL) 163471345Sgshapiro { 163571345Sgshapiro switch (d->d_addr.sa.sa_family) 163671345Sgshapiro { 1637285303Sgshapiro#if NETUNIX 163890792Sgshapiro case AF_UNIX: 163990792Sgshapiro if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path)) 164090792Sgshapiro { 164190792Sgshapiro errno = ENAMETOOLONG; 1642285303Sgshapiro syserr("setsockaddroptions: domain socket name too long: %s > %ld", 1643285303Sgshapiro addr, 1644285303Sgshapiro (long) sizeof(d->d_addr.sunix.sun_path)); 164590792Sgshapiro break; 164690792Sgshapiro } 164790792Sgshapiro 164890792Sgshapiro /* file safety check done in opendaemonsocket() */ 164990792Sgshapiro (void) memset(&d->d_addr.sunix.sun_path, '\0', 165090792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 165190792Sgshapiro (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path, 165290792Sgshapiro addr, 165390792Sgshapiro sizeof(d->d_addr.sunix.sun_path)); 165490792Sgshapiro break; 1655285303Sgshapiro#endif /* NETUNIX */ 165690792Sgshapiro#if NETINET 165771345Sgshapiro case AF_INET: 165871345Sgshapiro if (!isascii(*addr) || !isdigit(*addr) || 165990792Sgshapiro ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr)) 166090792Sgshapiro == INADDR_NONE)) 166171345Sgshapiro { 166271345Sgshapiro register struct hostent *hp; 166371345Sgshapiro 166471345Sgshapiro hp = sm_gethostbyname(addr, AF_INET); 166571345Sgshapiro if (hp == NULL) 166671345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 166771345Sgshapiro addr); 166871345Sgshapiro else 166971345Sgshapiro { 167071345Sgshapiro while (*(hp->h_addr_list) != NULL && 167171345Sgshapiro hp->h_addrtype != AF_INET) 167271345Sgshapiro hp->h_addr_list++; 167371345Sgshapiro if (*(hp->h_addr_list) == NULL) 167471345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 167571345Sgshapiro addr); 167671345Sgshapiro else 167771345Sgshapiro memmove(&d->d_addr.sin.sin_addr, 167871345Sgshapiro *(hp->h_addr_list), 167971345Sgshapiro INADDRSZ); 168090792Sgshapiro# if NETINET6 168171345Sgshapiro freehostent(hp); 168271345Sgshapiro hp = NULL; 168390792Sgshapiro# endif /* NETINET6 */ 168471345Sgshapiro } 168571345Sgshapiro } 168671345Sgshapiro break; 168790792Sgshapiro#endif /* NETINET */ 168871345Sgshapiro 168990792Sgshapiro#if NETINET6 169071345Sgshapiro case AF_INET6: 169190792Sgshapiro if (anynet_pton(AF_INET6, addr, 169290792Sgshapiro &d->d_addr.sin6.sin6_addr) != 1) 169371345Sgshapiro { 169471345Sgshapiro register struct hostent *hp; 169571345Sgshapiro 169671345Sgshapiro hp = sm_gethostbyname(addr, AF_INET6); 169771345Sgshapiro if (hp == NULL) 169871345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 169971345Sgshapiro addr); 170071345Sgshapiro else 170171345Sgshapiro { 170271345Sgshapiro while (*(hp->h_addr_list) != NULL && 170371345Sgshapiro hp->h_addrtype != AF_INET6) 170471345Sgshapiro hp->h_addr_list++; 170571345Sgshapiro if (*(hp->h_addr_list) == NULL) 170671345Sgshapiro syserr("554 5.3.0 host \"%s\" unknown", 170771345Sgshapiro addr); 170871345Sgshapiro else 170971345Sgshapiro memmove(&d->d_addr.sin6.sin6_addr, 171071345Sgshapiro *(hp->h_addr_list), 171171345Sgshapiro IN6ADDRSZ); 171271345Sgshapiro freehostent(hp); 171371345Sgshapiro hp = NULL; 171471345Sgshapiro } 171571345Sgshapiro } 171671345Sgshapiro break; 171790792Sgshapiro#endif /* NETINET6 */ 171871345Sgshapiro 171971345Sgshapiro default: 172071345Sgshapiro syserr("554 5.3.5 address= option unsupported for family %d", 172171345Sgshapiro d->d_addr.sa.sa_family); 172271345Sgshapiro break; 172371345Sgshapiro } 172471345Sgshapiro } 172571345Sgshapiro 172671345Sgshapiro if (port != NULL) 172771345Sgshapiro { 172871345Sgshapiro switch (d->d_addr.sa.sa_family) 172971345Sgshapiro { 173090792Sgshapiro#if NETINET 173171345Sgshapiro case AF_INET: 173271345Sgshapiro if (isascii(*port) && isdigit(*port)) 173390792Sgshapiro d->d_addr.sin.sin_port = htons((unsigned short) 173490792Sgshapiro atoi((const char *) port)); 173571345Sgshapiro else 173671345Sgshapiro { 173790792Sgshapiro# ifdef NO_GETSERVBYNAME 173871345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 173971345Sgshapiro port); 174090792Sgshapiro# else /* NO_GETSERVBYNAME */ 174171345Sgshapiro register struct servent *sp; 174271345Sgshapiro 174371345Sgshapiro sp = getservbyname(port, "tcp"); 174471345Sgshapiro if (sp == NULL) 174571345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 174671345Sgshapiro port); 174771345Sgshapiro else 174871345Sgshapiro d->d_addr.sin.sin_port = sp->s_port; 174990792Sgshapiro# endif /* NO_GETSERVBYNAME */ 175071345Sgshapiro } 175171345Sgshapiro break; 175290792Sgshapiro#endif /* NETINET */ 175371345Sgshapiro 175490792Sgshapiro#if NETINET6 175571345Sgshapiro case AF_INET6: 175671345Sgshapiro if (isascii(*port) && isdigit(*port)) 175790792Sgshapiro d->d_addr.sin6.sin6_port = htons((unsigned short) 175890792Sgshapiro atoi(port)); 175971345Sgshapiro else 176071345Sgshapiro { 176190792Sgshapiro# ifdef NO_GETSERVBYNAME 176271345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 176371345Sgshapiro port); 176490792Sgshapiro# else /* NO_GETSERVBYNAME */ 176571345Sgshapiro register struct servent *sp; 176671345Sgshapiro 176771345Sgshapiro sp = getservbyname(port, "tcp"); 176871345Sgshapiro if (sp == NULL) 176971345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 177071345Sgshapiro port); 177171345Sgshapiro else 177271345Sgshapiro d->d_addr.sin6.sin6_port = sp->s_port; 177390792Sgshapiro# endif /* NO_GETSERVBYNAME */ 177471345Sgshapiro } 177571345Sgshapiro break; 177690792Sgshapiro#endif /* NETINET6 */ 177771345Sgshapiro 177890792Sgshapiro#if NETISO 177971345Sgshapiro case AF_ISO: 178071345Sgshapiro /* assume two byte transport selector */ 178171345Sgshapiro if (isascii(*port) && isdigit(*port)) 178290792Sgshapiro portno = htons((unsigned short) atoi(port)); 178371345Sgshapiro else 178471345Sgshapiro { 178590792Sgshapiro# ifdef NO_GETSERVBYNAME 178671345Sgshapiro syserr("554 5.3.5 invalid port number: %s", 178771345Sgshapiro port); 178890792Sgshapiro# else /* NO_GETSERVBYNAME */ 178971345Sgshapiro register struct servent *sp; 179071345Sgshapiro 179171345Sgshapiro sp = getservbyname(port, "tcp"); 179271345Sgshapiro if (sp == NULL) 179371345Sgshapiro syserr("554 5.3.5 service \"%s\" unknown", 179471345Sgshapiro port); 179571345Sgshapiro else 179671345Sgshapiro portno = sp->s_port; 179790792Sgshapiro# endif /* NO_GETSERVBYNAME */ 179871345Sgshapiro } 179971345Sgshapiro memmove(TSEL(&d->d_addr.siso), 180071345Sgshapiro (char *) &portno, 2); 180171345Sgshapiro break; 180290792Sgshapiro#endif /* NETISO */ 180371345Sgshapiro 180471345Sgshapiro default: 180571345Sgshapiro syserr("554 5.3.5 Port= option unsupported for family %d", 180671345Sgshapiro d->d_addr.sa.sa_family); 180771345Sgshapiro break; 180871345Sgshapiro } 180971345Sgshapiro } 181038032Speter} 181190792Sgshapiro/* 181264562Sgshapiro** SETDAEMONOPTIONS -- set options for running the MTA daemon 181338032Speter** 181438032Speter** Parameters: 181564562Sgshapiro** p -- the options line. 181664562Sgshapiro** 181764562Sgshapiro** Returns: 181890792Sgshapiro** true if successful, false otherwise. 181990792Sgshapiro** 182090792Sgshapiro** Side Effects: 182190792Sgshapiro** increments number of daemons. 182264562Sgshapiro*/ 182364562Sgshapiro 182490792Sgshapiro#define DEF_LISTENQUEUE 10 182590792Sgshapiro 182698841Sgshapirostruct dflags 182798841Sgshapiro{ 182898841Sgshapiro char *d_name; 182998841Sgshapiro int d_flag; 183098841Sgshapiro}; 183198841Sgshapiro 183298841Sgshapirostatic struct dflags DaemonFlags[] = 183398841Sgshapiro{ 183498841Sgshapiro { "AUTHREQ", D_AUTHREQ }, 183598841Sgshapiro { "BINDIF", D_BINDIF }, 183698841Sgshapiro { "CANONREQ", D_CANONREQ }, 183798841Sgshapiro { "IFNHELO", D_IFNHELO }, 183898841Sgshapiro { "FQMAIL", D_FQMAIL }, 183998841Sgshapiro { "FQRCPT", D_FQRCPT }, 184098841Sgshapiro { "SMTPS", D_SMTPS }, 184198841Sgshapiro { "UNQUALOK", D_UNQUALOK }, 184298841Sgshapiro { "NOAUTH", D_NOAUTH }, 184398841Sgshapiro { "NOCANON", D_NOCANON }, 184498841Sgshapiro { "NOETRN", D_NOETRN }, 184598841Sgshapiro { "NOTLS", D_NOTLS }, 184698841Sgshapiro { "ETRNONLY", D_ETRNONLY }, 184798841Sgshapiro { "OPTIONAL", D_OPTIONAL }, 184898841Sgshapiro { "DISABLE", D_DISABLE }, 184998841Sgshapiro { "ISSET", D_ISSET }, 185098841Sgshapiro { NULL, 0 } 185198841Sgshapiro}; 185298841Sgshapiro 185398841Sgshapirostatic void 185498841Sgshapiroprintdaemonflags(d) 185598841Sgshapiro DAEMON_T *d; 185698841Sgshapiro{ 185798841Sgshapiro register struct dflags *df; 185898841Sgshapiro bool first = true; 185998841Sgshapiro 186098841Sgshapiro for (df = DaemonFlags; df->d_name != NULL; df++) 186198841Sgshapiro { 186298841Sgshapiro if (!bitnset(df->d_flag, d->d_flags)) 186398841Sgshapiro continue; 186498841Sgshapiro if (first) 1865132943Sgshapiro sm_dprintf("<%s", df->d_name); 186698841Sgshapiro else 1867132943Sgshapiro sm_dprintf(",%s", df->d_name); 186898841Sgshapiro first = false; 186998841Sgshapiro } 187098841Sgshapiro if (!first) 1871132943Sgshapiro sm_dprintf(">"); 187298841Sgshapiro} 187398841Sgshapiro 187464562Sgshapirobool 187564562Sgshapirosetdaemonoptions(p) 187664562Sgshapiro register char *p; 187764562Sgshapiro{ 187890792Sgshapiro if (NDaemons >= MAXDAEMONS) 187990792Sgshapiro return false; 188090792Sgshapiro Daemons[NDaemons].d_socket = -1; 188190792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 188290792Sgshapiro clrbitmap(Daemons[NDaemons].d_flags); 188390792Sgshapiro setsockaddroptions(p, &Daemons[NDaemons]); 188464562Sgshapiro 188590792Sgshapiro#if MILTER 188690792Sgshapiro if (Daemons[NDaemons].d_inputfilterlist != NULL) 188790792Sgshapiro Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist); 188890792Sgshapiro#endif /* MILTER */ 188990792Sgshapiro 189090792Sgshapiro if (Daemons[NDaemons].d_name != NULL) 189190792Sgshapiro Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name); 189264562Sgshapiro else 189364562Sgshapiro { 189464562Sgshapiro char num[30]; 189564562Sgshapiro 1896168515Sgshapiro (void) sm_snprintf(num, sizeof(num), "Daemon%d", NDaemons); 189790792Sgshapiro Daemons[NDaemons].d_name = newstr(num); 189864562Sgshapiro } 189964562Sgshapiro 190064562Sgshapiro if (tTd(37, 1)) 190164562Sgshapiro { 190290792Sgshapiro sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name); 190398841Sgshapiro printdaemonflags(&Daemons[NDaemons]); 190490792Sgshapiro sm_dprintf("\n"); 190564562Sgshapiro } 190690792Sgshapiro ++NDaemons; 190790792Sgshapiro return true; 190864562Sgshapiro} 190990792Sgshapiro/* 191064562Sgshapiro** INITDAEMON -- initialize daemon if not yet done. 191164562Sgshapiro** 191264562Sgshapiro** Parameters: 191364562Sgshapiro** none 191464562Sgshapiro** 191564562Sgshapiro** Returns: 191664562Sgshapiro** none 191764562Sgshapiro** 191864562Sgshapiro** Side Effects: 191964562Sgshapiro** initializes structure for one daemon. 192064562Sgshapiro*/ 192190792Sgshapiro 192264562Sgshapirovoid 192364562Sgshapiroinitdaemon() 192464562Sgshapiro{ 192590792Sgshapiro if (NDaemons == 0) 192664562Sgshapiro { 192790792Sgshapiro Daemons[NDaemons].d_socket = -1; 192890792Sgshapiro Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE; 192990792Sgshapiro Daemons[NDaemons].d_name = "Daemon0"; 193090792Sgshapiro NDaemons = 1; 193164562Sgshapiro } 193264562Sgshapiro} 193390792Sgshapiro/* 193464562Sgshapiro** SETCLIENTOPTIONS -- set options for running the client 193564562Sgshapiro** 193664562Sgshapiro** Parameters: 193764562Sgshapiro** p -- the options line. 193864562Sgshapiro** 193964562Sgshapiro** Returns: 194064562Sgshapiro** none. 194164562Sgshapiro*/ 194264562Sgshapiro 194390792Sgshapirostatic DAEMON_T ClientSettings[AF_MAX + 1]; 194464562Sgshapiro 194564562Sgshapirovoid 194664562Sgshapirosetclientoptions(p) 194764562Sgshapiro register char *p; 194864562Sgshapiro{ 194990792Sgshapiro int family; 195090792Sgshapiro DAEMON_T d; 195164562Sgshapiro 1952168515Sgshapiro memset(&d, '\0', sizeof(d)); 195364562Sgshapiro setsockaddroptions(p, &d); 195464562Sgshapiro 195564562Sgshapiro /* grab what we need */ 195690792Sgshapiro family = d.d_addr.sa.sa_family; 195790792Sgshapiro STRUCTCOPY(d, ClientSettings[family]); 195890792Sgshapiro setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */ 195990792Sgshapiro if (d.d_name != NULL) 196090792Sgshapiro ClientSettings[family].d_name = newstr(d.d_name); 196164562Sgshapiro else 196290792Sgshapiro { 196390792Sgshapiro char num[30]; 196490792Sgshapiro 1965168515Sgshapiro (void) sm_snprintf(num, sizeof(num), "Client%d", family); 196690792Sgshapiro ClientSettings[family].d_name = newstr(num); 196790792Sgshapiro } 196864562Sgshapiro} 196990792Sgshapiro/* 197064562Sgshapiro** ADDR_FAMILY -- determine address family from address 197164562Sgshapiro** 197264562Sgshapiro** Parameters: 197364562Sgshapiro** addr -- the string representation of the address 197464562Sgshapiro** 197564562Sgshapiro** Returns: 197664562Sgshapiro** AF_INET, AF_INET6 or AF_UNSPEC 197764562Sgshapiro** 197864562Sgshapiro** Side Effects: 197964562Sgshapiro** none. 198064562Sgshapiro*/ 198164562Sgshapiro 198264562Sgshapirostatic int 198364562Sgshapiroaddr_family(addr) 198464562Sgshapiro char *addr; 198564562Sgshapiro{ 198690792Sgshapiro#if NETINET6 198764562Sgshapiro SOCKADDR clt_addr; 198890792Sgshapiro#endif /* NETINET6 */ 198964562Sgshapiro 199090792Sgshapiro#if NETINET 199164562Sgshapiro if (inet_addr(addr) != INADDR_NONE) 199264562Sgshapiro { 199364562Sgshapiro if (tTd(16, 9)) 199490792Sgshapiro sm_dprintf("addr_family(%s): INET\n", addr); 199564562Sgshapiro return AF_INET; 199664562Sgshapiro } 199790792Sgshapiro#endif /* NETINET */ 199890792Sgshapiro#if NETINET6 199990792Sgshapiro if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1) 200064562Sgshapiro { 200164562Sgshapiro if (tTd(16, 9)) 200290792Sgshapiro sm_dprintf("addr_family(%s): INET6\n", addr); 200364562Sgshapiro return AF_INET6; 200464562Sgshapiro } 200590792Sgshapiro#endif /* NETINET6 */ 2006285303Sgshapiro#if NETUNIX 200790792Sgshapiro if (*addr == '/') 200890792Sgshapiro { 200990792Sgshapiro if (tTd(16, 9)) 201090792Sgshapiro sm_dprintf("addr_family(%s): LOCAL\n", addr); 201190792Sgshapiro return AF_UNIX; 201290792Sgshapiro } 2013285303Sgshapiro#endif /* NETUNIX */ 201464562Sgshapiro if (tTd(16, 9)) 201590792Sgshapiro sm_dprintf("addr_family(%s): UNSPEC\n", addr); 201664562Sgshapiro return AF_UNSPEC; 201764562Sgshapiro} 201890792Sgshapiro 201990792Sgshapiro/* 202090792Sgshapiro** CHKCLIENTMODIFIERS -- check whether all clients have set a flag. 202190792Sgshapiro** 202290792Sgshapiro** Parameters: 202390792Sgshapiro** flag -- the flag to test. 202490792Sgshapiro** 202590792Sgshapiro** Returns: 202690792Sgshapiro** true iff all configured clients have set the flag. 202790792Sgshapiro*/ 202890792Sgshapiro 202990792Sgshapirobool 203090792Sgshapirochkclientmodifiers(flag) 203190792Sgshapiro int flag; 203290792Sgshapiro{ 203390792Sgshapiro int i; 203490792Sgshapiro bool flagisset; 203590792Sgshapiro 203690792Sgshapiro flagisset = false; 203790792Sgshapiro for (i = 0; i < AF_MAX; i++) 203890792Sgshapiro { 203990792Sgshapiro if (bitnset(D_ISSET, ClientSettings[i].d_flags)) 204090792Sgshapiro { 204190792Sgshapiro if (!bitnset((char) flag, ClientSettings[i].d_flags)) 204290792Sgshapiro return false; 204390792Sgshapiro flagisset = true; 204490792Sgshapiro } 204590792Sgshapiro } 204690792Sgshapiro return flagisset; 204790792Sgshapiro} 204890792Sgshapiro 204990792Sgshapiro#if MILTER 205090792Sgshapiro/* 2051285303Sgshapiro** SETUP_DAEMON_MILTERS -- Parse per-socket filters 205290792Sgshapiro** 205390792Sgshapiro** Parameters: 205490792Sgshapiro** none 205590792Sgshapiro** 205690792Sgshapiro** Returns: 205790792Sgshapiro** none 205890792Sgshapiro*/ 205990792Sgshapiro 206090792Sgshapirovoid 206190792Sgshapirosetup_daemon_milters() 206290792Sgshapiro{ 206390792Sgshapiro int idx; 206490792Sgshapiro 206590792Sgshapiro if (OpMode == MD_SMTP) 206690792Sgshapiro { 206790792Sgshapiro /* no need to configure the daemons */ 206890792Sgshapiro return; 206990792Sgshapiro } 207090792Sgshapiro 207190792Sgshapiro for (idx = 0; idx < NDaemons; idx++) 207290792Sgshapiro { 207390792Sgshapiro if (Daemons[idx].d_inputfilterlist != NULL) 207490792Sgshapiro { 207590792Sgshapiro milter_config(Daemons[idx].d_inputfilterlist, 207690792Sgshapiro Daemons[idx].d_inputfilters, 207790792Sgshapiro MAXFILTERS); 207890792Sgshapiro } 207990792Sgshapiro } 208090792Sgshapiro} 208190792Sgshapiro#endif /* MILTER */ 208290792Sgshapiro/* 208364562Sgshapiro** MAKECONNECTION -- make a connection to an SMTP socket on a machine. 208464562Sgshapiro** 208564562Sgshapiro** Parameters: 208638032Speter** host -- the name of the host. 208738032Speter** port -- the port number to connect to. 208838032Speter** mci -- a pointer to the mail connection information 208938032Speter** structure to be filled in. 209038032Speter** e -- the current envelope. 209190792Sgshapiro** enough -- time at which to stop further connection attempts. 209290792Sgshapiro** (0 means no limit) 209338032Speter** 209438032Speter** Returns: 209538032Speter** An exit code telling whether the connection could be 209638032Speter** made and if not why not. 209738032Speter** 209838032Speter** Side Effects: 209938032Speter** none. 210038032Speter*/ 210138032Speter 210238032Speterstatic jmp_buf CtxConnectTimeout; 210338032Speter 210438032SpeterSOCKADDR CurHostAddr; /* address of current host */ 210538032Speter 210638032Speterint 210790792Sgshapiromakeconnection(host, port, mci, e, enough) 210838032Speter char *host; 210990792Sgshapiro volatile unsigned int port; 211038032Speter register MCI *mci; 211138032Speter ENVELOPE *e; 211290792Sgshapiro time_t enough; 211338032Speter{ 211438032Speter register volatile int addrno = 0; 211590792Sgshapiro volatile int s; 211690792Sgshapiro register struct hostent *volatile hp = (struct hostent *) NULL; 211738032Speter SOCKADDR addr; 211864562Sgshapiro SOCKADDR clt_addr; 211964562Sgshapiro int save_errno = 0; 212064562Sgshapiro volatile SOCKADDR_LEN_T addrlen; 2121159609Sgshapiro volatile bool firstconnect = true; 212290792Sgshapiro SM_EVENT *volatile ev = NULL; 212390792Sgshapiro#if NETINET6 212490792Sgshapiro volatile bool v6found = false; 212590792Sgshapiro#endif /* NETINET6 */ 212664562Sgshapiro volatile int family = InetMode; 212764562Sgshapiro SOCKADDR_LEN_T len; 212864562Sgshapiro volatile SOCKADDR_LEN_T socksize = 0; 212964562Sgshapiro volatile bool clt_bind; 213064562Sgshapiro BITMAP256 d_flags; 213164562Sgshapiro char *p; 213264562Sgshapiro extern ENVELOPE BlankEnvelope; 213338032Speter 213490792Sgshapiro /* retranslate {daemon_flags} into bitmap */ 213564562Sgshapiro clrbitmap(d_flags); 213690792Sgshapiro if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL) 213764562Sgshapiro { 213864562Sgshapiro for (; *p != '\0'; p++) 213964562Sgshapiro { 214064562Sgshapiro if (!(isascii(*p) && isspace(*p))) 214171345Sgshapiro setbitn(bitidx(*p), d_flags); 214264562Sgshapiro } 214364562Sgshapiro } 214464562Sgshapiro 214590792Sgshapiro#if NETINET6 214664562Sgshapiro v4retry: 214790792Sgshapiro#endif /* NETINET6 */ 214890792Sgshapiro clt_bind = false; 214964562Sgshapiro 215064562Sgshapiro /* Set up the address for outgoing connection. */ 215164562Sgshapiro if (bitnset(D_BINDIF, d_flags) && 215290792Sgshapiro (p = macvalue(macid("{if_addr}"), e)) != NULL && 215373188Sgshapiro *p != '\0') 215464562Sgshapiro { 215590792Sgshapiro#if NETINET6 215664562Sgshapiro char p6[INET6_ADDRSTRLEN]; 215790792Sgshapiro#endif /* NETINET6 */ 215864562Sgshapiro 2159168515Sgshapiro memset(&clt_addr, '\0', sizeof(clt_addr)); 216064562Sgshapiro 216164562Sgshapiro /* infer the address family from the address itself */ 216264562Sgshapiro clt_addr.sa.sa_family = addr_family(p); 216364562Sgshapiro switch (clt_addr.sa.sa_family) 216464562Sgshapiro { 216590792Sgshapiro#if NETINET 216664562Sgshapiro case AF_INET: 216773188Sgshapiro clt_addr.sin.sin_addr.s_addr = inet_addr(p); 216873188Sgshapiro if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE && 2169203004Sgshapiro clt_addr.sin.sin_addr.s_addr != 2170203004Sgshapiro htonl(INADDR_LOOPBACK)) 217164562Sgshapiro { 217290792Sgshapiro clt_bind = true; 2173168515Sgshapiro socksize = sizeof(struct sockaddr_in); 217464562Sgshapiro } 217564562Sgshapiro break; 217690792Sgshapiro#endif /* NETINET */ 217764562Sgshapiro 217890792Sgshapiro#if NETINET6 217964562Sgshapiro case AF_INET6: 218064562Sgshapiro if (inet_addr(p) != INADDR_NONE) 2181168515Sgshapiro (void) sm_snprintf(p6, sizeof(p6), 218290792Sgshapiro "IPv6:::ffff:%s", p); 218364562Sgshapiro else 2184168515Sgshapiro (void) sm_strlcpy(p6, p, sizeof(p6)); 218590792Sgshapiro if (anynet_pton(AF_INET6, p6, 218690792Sgshapiro &clt_addr.sin6.sin6_addr) == 1 && 218773188Sgshapiro !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr)) 218864562Sgshapiro { 218990792Sgshapiro clt_bind = true; 2190168515Sgshapiro socksize = sizeof(struct sockaddr_in6); 219164562Sgshapiro } 219264562Sgshapiro break; 219390792Sgshapiro#endif /* NETINET6 */ 219464562Sgshapiro 219590792Sgshapiro#if 0 219664562Sgshapiro default: 219764562Sgshapiro syserr("554 5.3.5 Address= option unsupported for family %d", 219864562Sgshapiro clt_addr.sa.sa_family); 219964562Sgshapiro break; 220090792Sgshapiro#endif /* 0 */ 220164562Sgshapiro } 220264562Sgshapiro if (clt_bind) 220364562Sgshapiro family = clt_addr.sa.sa_family; 220464562Sgshapiro } 220590792Sgshapiro 220690792Sgshapiro /* D_BINDIF not set or not available, fallback to ClientPortOptions */ 220790792Sgshapiro if (!clt_bind) 220864562Sgshapiro { 220990792Sgshapiro STRUCTCOPY(ClientSettings[family].d_addr, clt_addr); 221064562Sgshapiro switch (clt_addr.sa.sa_family) 221164562Sgshapiro { 221290792Sgshapiro#if NETINET 221364562Sgshapiro case AF_INET: 221464562Sgshapiro if (clt_addr.sin.sin_addr.s_addr == 0) 2215182352Sgshapiro clt_addr.sin.sin_addr.s_addr = LocalDaemon ? 2216182352Sgshapiro htonl(INADDR_LOOPBACK) : INADDR_ANY; 221764562Sgshapiro else 221890792Sgshapiro clt_bind = true; 221964562Sgshapiro if (clt_addr.sin.sin_port != 0) 222090792Sgshapiro clt_bind = true; 2221168515Sgshapiro socksize = sizeof(struct sockaddr_in); 222264562Sgshapiro break; 222390792Sgshapiro#endif /* NETINET */ 222490792Sgshapiro#if NETINET6 222564562Sgshapiro case AF_INET6: 222664562Sgshapiro if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr)) 2227223067Sgshapiro clt_addr.sin6.sin6_addr = 2228223067Sgshapiro (LocalDaemon && V6LoopbackAddrFound) ? 2229182352Sgshapiro in6addr_loopback : in6addr_any; 223064562Sgshapiro else 223190792Sgshapiro clt_bind = true; 2232168515Sgshapiro socksize = sizeof(struct sockaddr_in6); 223364562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 223490792Sgshapiro clt_bind = true; 223564562Sgshapiro break; 223690792Sgshapiro#endif /* NETINET6 */ 223790792Sgshapiro#if NETISO 223864562Sgshapiro case AF_ISO: 2239168515Sgshapiro socksize = sizeof(clt_addr.siso); 224090792Sgshapiro clt_bind = true; 224164562Sgshapiro break; 224290792Sgshapiro#endif /* NETISO */ 224364562Sgshapiro default: 224464562Sgshapiro break; 224564562Sgshapiro } 224664562Sgshapiro } 224764562Sgshapiro 224838032Speter /* 224938032Speter ** Set up the address for the mailer. 225038032Speter ** Accept "[a.b.c.d]" syntax for host name. 225138032Speter */ 225238032Speter 225373188Sgshapiro SM_SET_H_ERRNO(0); 225438032Speter errno = 0; 2255168515Sgshapiro memset(&CurHostAddr, '\0', sizeof(CurHostAddr)); 2256168515Sgshapiro memset(&addr, '\0', sizeof(addr)); 225738032Speter SmtpPhase = mci->mci_phase = "initial connection"; 225838032Speter CurHostName = host; 225938032Speter 226038032Speter if (host[0] == '[') 226138032Speter { 226264562Sgshapiro p = strchr(host, ']'); 226338032Speter if (p != NULL) 226438032Speter { 226590792Sgshapiro#if NETINET 226664562Sgshapiro unsigned long hid = INADDR_NONE; 226790792Sgshapiro#endif /* NETINET */ 226890792Sgshapiro#if NETINET6 226964562Sgshapiro struct sockaddr_in6 hid6; 227090792Sgshapiro#endif /* NETINET6 */ 227164562Sgshapiro 227238032Speter *p = '\0'; 227390792Sgshapiro#if NETINET6 2274168515Sgshapiro memset(&hid6, '\0', sizeof(hid6)); 227590792Sgshapiro#endif /* NETINET6 */ 227690792Sgshapiro#if NETINET 227764562Sgshapiro if (family == AF_INET && 227864562Sgshapiro (hid = inet_addr(&host[1])) != INADDR_NONE) 227938032Speter { 228064562Sgshapiro addr.sin.sin_family = AF_INET; 228164562Sgshapiro addr.sin.sin_addr.s_addr = hid; 228264562Sgshapiro } 228364562Sgshapiro else 228490792Sgshapiro#endif /* NETINET */ 228590792Sgshapiro#if NETINET6 228664562Sgshapiro if (family == AF_INET6 && 228790792Sgshapiro anynet_pton(AF_INET6, &host[1], 228890792Sgshapiro &hid6.sin6_addr) == 1) 228964562Sgshapiro { 229064562Sgshapiro addr.sin6.sin6_family = AF_INET6; 229164562Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 229264562Sgshapiro } 229364562Sgshapiro else 229490792Sgshapiro#endif /* NETINET6 */ 229564562Sgshapiro { 229638032Speter /* try it as a host name (avoid MX lookup) */ 229764562Sgshapiro hp = sm_gethostbyname(&host[1], family); 229838032Speter if (hp == NULL && p[-1] == '.') 229938032Speter { 230090792Sgshapiro#if NAMED_BIND 230138032Speter int oldopts = _res.options; 230238032Speter 230338032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 230490792Sgshapiro#endif /* NAMED_BIND */ 230538032Speter p[-1] = '\0'; 230664562Sgshapiro hp = sm_gethostbyname(&host[1], 230764562Sgshapiro family); 230838032Speter p[-1] = '.'; 230990792Sgshapiro#if NAMED_BIND 231038032Speter _res.options = oldopts; 231190792Sgshapiro#endif /* NAMED_BIND */ 231238032Speter } 231338032Speter *p = ']'; 231438032Speter goto gothostent; 231538032Speter } 231638032Speter *p = ']'; 231738032Speter } 231838032Speter if (p == NULL) 231938032Speter { 232038032Speter extern char MsgBuf[]; 232138032Speter 232264562Sgshapiro usrerrenh("5.1.2", 232364562Sgshapiro "553 Invalid numeric domain spec \"%s\"", 232464562Sgshapiro host); 232538032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf); 232664562Sgshapiro errno = EINVAL; 232738032Speter return EX_NOHOST; 232838032Speter } 232938032Speter } 233038032Speter else 233138032Speter { 233238032Speter /* contortion to get around SGI cc complaints */ 233338032Speter { 233464562Sgshapiro p = &host[strlen(host) - 1]; 233564562Sgshapiro hp = sm_gethostbyname(host, family); 233638032Speter if (hp == NULL && *p == '.') 233738032Speter { 233890792Sgshapiro#if NAMED_BIND 233938032Speter int oldopts = _res.options; 234038032Speter 234138032Speter _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 234290792Sgshapiro#endif /* NAMED_BIND */ 234338032Speter *p = '\0'; 234464562Sgshapiro hp = sm_gethostbyname(host, family); 234538032Speter *p = '.'; 234690792Sgshapiro#if NAMED_BIND 234738032Speter _res.options = oldopts; 234890792Sgshapiro#endif /* NAMED_BIND */ 234938032Speter } 235038032Speter } 235138032Spetergothostent: 2352203004Sgshapiro if (hp == NULL || hp->h_addr == NULL) 235338032Speter { 235490792Sgshapiro#if NAMED_BIND 235538032Speter /* check for name server timeouts */ 235690792Sgshapiro# if NETINET6 235790792Sgshapiro if (WorkAroundBrokenAAAA && family == AF_INET6 && 2358261363Sgshapiro (h_errno == TRY_AGAIN || errno == ETIMEDOUT)) 235938032Speter { 236090792Sgshapiro /* 236190792Sgshapiro ** An attempt with family AF_INET may 2362261363Sgshapiro ** succeed. By skipping the next section 236390792Sgshapiro ** of code, we will try AF_INET before 236490792Sgshapiro ** failing. 236590792Sgshapiro */ 236690792Sgshapiro 236790792Sgshapiro if (tTd(16, 10)) 236890792Sgshapiro sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n"); 236938032Speter } 237090792Sgshapiro else 237190792Sgshapiro# endif /* NETINET6 */ 237290792Sgshapiro { 237390792Sgshapiro if (errno == ETIMEDOUT || 2374168515Sgshapiro# if _FFR_GETHBN_ExFILE 2375168515Sgshapiro# ifdef EMFILE 2376168515Sgshapiro errno == EMFILE || 2377168515Sgshapiro# endif /* EMFILE */ 2378168515Sgshapiro# ifdef ENFILE 2379168515Sgshapiro errno == ENFILE || 2380168515Sgshapiro# endif /* ENFILE */ 2381168515Sgshapiro# endif /* _FFR_GETHBN_ExFILE */ 238290792Sgshapiro h_errno == TRY_AGAIN || 238390792Sgshapiro (errno == ECONNREFUSED && UseNameServer)) 238490792Sgshapiro { 238590792Sgshapiro save_errno = errno; 238690792Sgshapiro mci_setstat(mci, EX_TEMPFAIL, 238790792Sgshapiro "4.4.3", NULL); 238890792Sgshapiro errno = save_errno; 238990792Sgshapiro return EX_TEMPFAIL; 239090792Sgshapiro } 239190792Sgshapiro } 239290792Sgshapiro#endif /* NAMED_BIND */ 239390792Sgshapiro#if NETINET6 239464562Sgshapiro /* 239564562Sgshapiro ** Try v6 first, then fall back to v4. 239664562Sgshapiro ** If we found a v6 address, but no v4 239764562Sgshapiro ** addresses, then TEMPFAIL. 239864562Sgshapiro */ 239964562Sgshapiro 240064562Sgshapiro if (family == AF_INET6) 240164562Sgshapiro { 240264562Sgshapiro family = AF_INET; 240364562Sgshapiro goto v4retry; 240464562Sgshapiro } 240564562Sgshapiro if (v6found) 240664562Sgshapiro goto v6tempfail; 240790792Sgshapiro#endif /* NETINET6 */ 240864562Sgshapiro save_errno = errno; 240938032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 241064562Sgshapiro errno = save_errno; 241164562Sgshapiro return EX_NOHOST; 241238032Speter } 241338032Speter addr.sa.sa_family = hp->h_addrtype; 241438032Speter switch (hp->h_addrtype) 241538032Speter { 241690792Sgshapiro#if NETINET 241738032Speter case AF_INET: 241864562Sgshapiro memmove(&addr.sin.sin_addr, 241964562Sgshapiro hp->h_addr, 242038032Speter INADDRSZ); 242138032Speter break; 242290792Sgshapiro#endif /* NETINET */ 242338032Speter 242490792Sgshapiro#if NETINET6 242564562Sgshapiro case AF_INET6: 242664562Sgshapiro memmove(&addr.sin6.sin6_addr, 242764562Sgshapiro hp->h_addr, 242864562Sgshapiro IN6ADDRSZ); 242964562Sgshapiro break; 243090792Sgshapiro#endif /* NETINET6 */ 243164562Sgshapiro 243238032Speter default: 2433168515Sgshapiro if (hp->h_length > sizeof(addr.sa.sa_data)) 243438032Speter { 243538032Speter syserr("makeconnection: long sa_data: family %d len %d", 243638032Speter hp->h_addrtype, hp->h_length); 243738032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 243864562Sgshapiro errno = EINVAL; 243938032Speter return EX_NOHOST; 244038032Speter } 244190792Sgshapiro memmove(addr.sa.sa_data, hp->h_addr, hp->h_length); 244238032Speter break; 244338032Speter } 244438032Speter addrno = 1; 244538032Speter } 244638032Speter 244738032Speter /* 244838032Speter ** Determine the port number. 244938032Speter */ 245038032Speter 245138032Speter if (port == 0) 245238032Speter { 245390792Sgshapiro#ifdef NO_GETSERVBYNAME 245464562Sgshapiro port = htons(25); 245590792Sgshapiro#else /* NO_GETSERVBYNAME */ 245638032Speter register struct servent *sp = getservbyname("smtp", "tcp"); 245738032Speter 245838032Speter if (sp == NULL) 245938032Speter { 246038032Speter if (LogLevel > 2) 246138032Speter sm_syslog(LOG_ERR, NOQID, 246264562Sgshapiro "makeconnection: service \"smtp\" unknown"); 246338032Speter port = htons(25); 246438032Speter } 246538032Speter else 246638032Speter port = sp->s_port; 246790792Sgshapiro#endif /* NO_GETSERVBYNAME */ 246838032Speter } 246938032Speter 247090792Sgshapiro#if NETINET6 247190792Sgshapiro if (addr.sa.sa_family == AF_INET6 && 247290792Sgshapiro IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) && 247390792Sgshapiro ClientSettings[AF_INET].d_addr.sa.sa_family != 0) 247490792Sgshapiro { 247590792Sgshapiro /* 247690792Sgshapiro ** Ignore mapped IPv4 address since 247790792Sgshapiro ** there is a ClientPortOptions setting 247890792Sgshapiro ** for IPv4. 247990792Sgshapiro */ 248090792Sgshapiro 248190792Sgshapiro goto nextaddr; 248290792Sgshapiro } 248390792Sgshapiro#endif /* NETINET6 */ 248490792Sgshapiro 248538032Speter switch (addr.sa.sa_family) 248638032Speter { 248790792Sgshapiro#if NETINET 248838032Speter case AF_INET: 248938032Speter addr.sin.sin_port = port; 2490168515Sgshapiro addrlen = sizeof(struct sockaddr_in); 249138032Speter break; 249290792Sgshapiro#endif /* NETINET */ 249338032Speter 249490792Sgshapiro#if NETINET6 249564562Sgshapiro case AF_INET6: 249664562Sgshapiro addr.sin6.sin6_port = port; 2497168515Sgshapiro addrlen = sizeof(struct sockaddr_in6); 249864562Sgshapiro break; 249990792Sgshapiro#endif /* NETINET6 */ 250064562Sgshapiro 250190792Sgshapiro#if NETISO 250238032Speter case AF_ISO: 250338032Speter /* assume two byte transport selector */ 250464562Sgshapiro memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2); 2505168515Sgshapiro addrlen = sizeof(struct sockaddr_iso); 250638032Speter break; 250790792Sgshapiro#endif /* NETISO */ 250838032Speter 250938032Speter default: 251038032Speter syserr("Can't connect to address family %d", addr.sa.sa_family); 251138032Speter mci_setstat(mci, EX_NOHOST, "5.1.2", NULL); 251264562Sgshapiro errno = EINVAL; 251390792Sgshapiro#if NETINET6 251471345Sgshapiro if (hp != NULL) 251571345Sgshapiro freehostent(hp); 251690792Sgshapiro#endif /* NETINET6 */ 251764562Sgshapiro return EX_NOHOST; 251838032Speter } 251938032Speter 252038032Speter /* 252138032Speter ** Try to actually open the connection. 252238032Speter */ 252338032Speter 252490792Sgshapiro#if XLA 252538032Speter /* if too many connections, don't bother trying */ 252638032Speter if (!xla_noqueue_ok(host)) 252771345Sgshapiro { 252890792Sgshapiro# if NETINET6 252971345Sgshapiro if (hp != NULL) 253071345Sgshapiro freehostent(hp); 253190792Sgshapiro# endif /* NETINET6 */ 253238032Speter return EX_TEMPFAIL; 253371345Sgshapiro } 253490792Sgshapiro#endif /* XLA */ 253538032Speter 253638032Speter for (;;) 253738032Speter { 253838032Speter if (tTd(16, 1)) 253990792Sgshapiro sm_dprintf("makeconnection (%s [%s].%d (%d))\n", 254090792Sgshapiro host, anynet_ntoa(&addr), ntohs(port), 254190792Sgshapiro (int) addr.sa.sa_family); 254238032Speter 254338032Speter /* save for logging */ 254438032Speter CurHostAddr = addr; 254538032Speter 254690792Sgshapiro#if HASRRESVPORT 254738032Speter if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) 254838032Speter { 254938032Speter int rport = IPPORT_RESERVED - 1; 255038032Speter 255138032Speter s = rresvport(&rport); 255238032Speter } 255338032Speter else 255490792Sgshapiro#endif /* HASRRESVPORT */ 255538032Speter { 255690792Sgshapiro s = socket(addr.sa.sa_family, SOCK_STREAM, 0); 255738032Speter } 255838032Speter if (s < 0) 255938032Speter { 256064562Sgshapiro save_errno = errno; 256138032Speter syserr("makeconnection: cannot create socket"); 256290792Sgshapiro#if XLA 256338032Speter xla_host_end(host); 256490792Sgshapiro#endif /* XLA */ 256538032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 256690792Sgshapiro#if NETINET6 256771345Sgshapiro if (hp != NULL) 256871345Sgshapiro freehostent(hp); 256990792Sgshapiro#endif /* NETINET6 */ 257064562Sgshapiro errno = save_errno; 257138032Speter return EX_TEMPFAIL; 257238032Speter } 257338032Speter 257490792Sgshapiro#ifdef SO_SNDBUF 257590792Sgshapiro if (ClientSettings[family].d_tcpsndbufsize > 0) 257638032Speter { 257738032Speter if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 257890792Sgshapiro (char *) &ClientSettings[family].d_tcpsndbufsize, 257990792Sgshapiro sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0) 258038032Speter syserr("makeconnection: setsockopt(SO_SNDBUF)"); 258138032Speter } 258290792Sgshapiro#endif /* SO_SNDBUF */ 258390792Sgshapiro#ifdef SO_RCVBUF 258490792Sgshapiro if (ClientSettings[family].d_tcprcvbufsize > 0) 258564562Sgshapiro { 258664562Sgshapiro if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 258790792Sgshapiro (char *) &ClientSettings[family].d_tcprcvbufsize, 258890792Sgshapiro sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0) 258964562Sgshapiro syserr("makeconnection: setsockopt(SO_RCVBUF)"); 259064562Sgshapiro } 259190792Sgshapiro#endif /* SO_RCVBUF */ 259238032Speter 259338032Speter if (tTd(16, 1)) 259490792Sgshapiro sm_dprintf("makeconnection: fd=%d\n", s); 259538032Speter 259638032Speter /* turn on network debugging? */ 259738032Speter if (tTd(16, 101)) 259838032Speter { 259938032Speter int on = 1; 260064562Sgshapiro 260138032Speter (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 2602168515Sgshapiro (char *)&on, sizeof(on)); 260338032Speter } 260490792Sgshapiro if (e->e_xfp != NULL) /* for debugging */ 260590792Sgshapiro (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT); 260690792Sgshapiro errno = 0; /* for debugging */ 260738032Speter 260864562Sgshapiro if (clt_bind) 260964562Sgshapiro { 261064562Sgshapiro int on = 1; 261164562Sgshapiro 261264562Sgshapiro switch (clt_addr.sa.sa_family) 261364562Sgshapiro { 261490792Sgshapiro#if NETINET 261564562Sgshapiro case AF_INET: 261664562Sgshapiro if (clt_addr.sin.sin_port != 0) 261764562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 261864562Sgshapiro SO_REUSEADDR, 261964562Sgshapiro (char *) &on, 2620168515Sgshapiro sizeof(on)); 262164562Sgshapiro break; 262290792Sgshapiro#endif /* NETINET */ 262364562Sgshapiro 262490792Sgshapiro#if NETINET6 262564562Sgshapiro case AF_INET6: 262664562Sgshapiro if (clt_addr.sin6.sin6_port != 0) 262764562Sgshapiro (void) setsockopt(s, SOL_SOCKET, 262864562Sgshapiro SO_REUSEADDR, 262964562Sgshapiro (char *) &on, 2630168515Sgshapiro sizeof(on)); 263164562Sgshapiro break; 263290792Sgshapiro#endif /* NETINET6 */ 263364562Sgshapiro } 263464562Sgshapiro 263564562Sgshapiro if (bind(s, &clt_addr.sa, socksize) < 0) 263664562Sgshapiro { 263764562Sgshapiro save_errno = errno; 263864562Sgshapiro (void) close(s); 263964562Sgshapiro errno = save_errno; 264064562Sgshapiro syserr("makeconnection: cannot bind socket [%s]", 264164562Sgshapiro anynet_ntoa(&clt_addr)); 264290792Sgshapiro#if NETINET6 264371345Sgshapiro if (hp != NULL) 264471345Sgshapiro freehostent(hp); 264590792Sgshapiro#endif /* NETINET6 */ 264664562Sgshapiro errno = save_errno; 264764562Sgshapiro return EX_TEMPFAIL; 264864562Sgshapiro } 264964562Sgshapiro } 265064562Sgshapiro 265138032Speter /* 265238032Speter ** Linux seems to hang in connect for 90 minutes (!!!). 265338032Speter ** Time out the connect to avoid this problem. 265438032Speter */ 265538032Speter 265638032Speter if (setjmp(CtxConnectTimeout) == 0) 265738032Speter { 265838032Speter int i; 265938032Speter 266038032Speter if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) 266190792Sgshapiro ev = sm_setevent(TimeOuts.to_iconnect, 266290792Sgshapiro connecttimeout, 0); 266338032Speter else if (TimeOuts.to_connect != 0) 266490792Sgshapiro ev = sm_setevent(TimeOuts.to_connect, 266590792Sgshapiro connecttimeout, 0); 266638032Speter else 266738032Speter ev = NULL; 266838032Speter 266964562Sgshapiro switch (ConnectOnlyTo.sa.sa_family) 267064562Sgshapiro { 267190792Sgshapiro#if NETINET 267264562Sgshapiro case AF_INET: 267364562Sgshapiro addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr; 2674223067Sgshapiro addr.sa.sa_family = ConnectOnlyTo.sa.sa_family; 267564562Sgshapiro break; 267690792Sgshapiro#endif /* NETINET */ 267764562Sgshapiro 267890792Sgshapiro#if NETINET6 267964562Sgshapiro case AF_INET6: 268064562Sgshapiro memmove(&addr.sin6.sin6_addr, 268164562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr, 268264562Sgshapiro IN6ADDRSZ); 268364562Sgshapiro break; 268490792Sgshapiro#endif /* NETINET6 */ 268564562Sgshapiro } 2686141858Sgshapiro if (tTd(16, 1)) 2687141858Sgshapiro sm_dprintf("Connecting to [%s]...\n", anynet_ntoa(&addr)); 268838032Speter i = connect(s, (struct sockaddr *) &addr, addrlen); 268964562Sgshapiro save_errno = errno; 269038032Speter if (ev != NULL) 269190792Sgshapiro sm_clrevent(ev); 269238032Speter if (i >= 0) 269338032Speter break; 269438032Speter } 269538032Speter else 269664562Sgshapiro save_errno = errno; 269738032Speter 269894334Sgshapiro /* couldn't connect.... figure out why */ 269994334Sgshapiro (void) close(s); 270094334Sgshapiro 270138032Speter /* if running demand-dialed connection, try again */ 270290792Sgshapiro if (DialDelay > 0 && firstconnect && 270390792Sgshapiro bitnset(M_DIALDELAY, mci->mci_mailer->m_flags)) 270438032Speter { 270538032Speter if (tTd(16, 1)) 270690792Sgshapiro sm_dprintf("Connect failed (%s); trying again...\n", 270790792Sgshapiro sm_errstring(save_errno)); 270890792Sgshapiro firstconnect = false; 270964562Sgshapiro (void) sleep(DialDelay); 271038032Speter continue; 271138032Speter } 271238032Speter 271390792Sgshapiro if (LogLevel > 13) 271438032Speter sm_syslog(LOG_INFO, e->e_id, 271538032Speter "makeconnection (%s [%s]) failed: %s", 271638032Speter host, anynet_ntoa(&addr), 271790792Sgshapiro sm_errstring(save_errno)); 271838032Speter 271990792Sgshapiro#if NETINET6 272090792Sgshapironextaddr: 272190792Sgshapiro#endif /* NETINET6 */ 272290792Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL && 272390792Sgshapiro (enough == 0 || curtime() < enough)) 272438032Speter { 272538032Speter if (tTd(16, 1)) 272690792Sgshapiro sm_dprintf("Connect failed (%s); trying new address....\n", 272790792Sgshapiro sm_errstring(save_errno)); 272838032Speter switch (addr.sa.sa_family) 272938032Speter { 273090792Sgshapiro#if NETINET 273138032Speter case AF_INET: 273264562Sgshapiro memmove(&addr.sin.sin_addr, 273364562Sgshapiro hp->h_addr_list[addrno++], 273464562Sgshapiro INADDRSZ); 273538032Speter break; 273690792Sgshapiro#endif /* NETINET */ 273738032Speter 273890792Sgshapiro#if NETINET6 273964562Sgshapiro case AF_INET6: 274064562Sgshapiro memmove(&addr.sin6.sin6_addr, 274164562Sgshapiro hp->h_addr_list[addrno++], 274264562Sgshapiro IN6ADDRSZ); 274364562Sgshapiro break; 274490792Sgshapiro#endif /* NETINET6 */ 274564562Sgshapiro 274638032Speter default: 274764562Sgshapiro memmove(addr.sa.sa_data, 274864562Sgshapiro hp->h_addr_list[addrno++], 274938032Speter hp->h_length); 275038032Speter break; 275138032Speter } 275238032Speter continue; 275338032Speter } 275464562Sgshapiro errno = save_errno; 275538032Speter 275690792Sgshapiro#if NETINET6 275764562Sgshapiro if (family == AF_INET6) 275864562Sgshapiro { 275964562Sgshapiro if (tTd(16, 1)) 276090792Sgshapiro sm_dprintf("Connect failed (%s); retrying with AF_INET....\n", 276190792Sgshapiro sm_errstring(save_errno)); 276290792Sgshapiro v6found = true; 276364562Sgshapiro family = AF_INET; 276471345Sgshapiro if (hp != NULL) 276571345Sgshapiro { 276671345Sgshapiro freehostent(hp); 276771345Sgshapiro hp = NULL; 276871345Sgshapiro } 276964562Sgshapiro goto v4retry; 277064562Sgshapiro } 277164562Sgshapiro v6tempfail: 277290792Sgshapiro#endif /* NETINET6 */ 277338032Speter /* couldn't open connection */ 277490792Sgshapiro#if NETINET6 277564562Sgshapiro /* Don't clobber an already saved errno from v4retry */ 277664562Sgshapiro if (errno > 0) 277790792Sgshapiro#endif /* NETINET6 */ 277864562Sgshapiro save_errno = errno; 277964562Sgshapiro if (tTd(16, 1)) 278090792Sgshapiro sm_dprintf("Connect failed (%s)\n", 278190792Sgshapiro sm_errstring(save_errno)); 278290792Sgshapiro#if XLA 278338032Speter xla_host_end(host); 278490792Sgshapiro#endif /* XLA */ 278538032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 278690792Sgshapiro#if NETINET6 278771345Sgshapiro if (hp != NULL) 278871345Sgshapiro freehostent(hp); 278990792Sgshapiro#endif /* NETINET6 */ 279064562Sgshapiro errno = save_errno; 279138032Speter return EX_TEMPFAIL; 279238032Speter } 279338032Speter 279490792Sgshapiro#if NETINET6 279571345Sgshapiro if (hp != NULL) 279671345Sgshapiro { 279771345Sgshapiro freehostent(hp); 279871345Sgshapiro hp = NULL; 279971345Sgshapiro } 280090792Sgshapiro#endif /* NETINET6 */ 280171345Sgshapiro 280238032Speter /* connection ok, put it into canonical form */ 280364562Sgshapiro mci->mci_out = NULL; 280490792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 280590792Sgshapiro (void *) &s, 2806132943Sgshapiro SM_IO_WRONLY_B, NULL)) == NULL || 280738032Speter (s = dup(s)) < 0 || 280890792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 280990792Sgshapiro (void *) &s, 2810132943Sgshapiro SM_IO_RDONLY_B, NULL)) == NULL) 281138032Speter { 281264562Sgshapiro save_errno = errno; 281338032Speter syserr("cannot open SMTP client channel, fd=%d", s); 281438032Speter mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 281564562Sgshapiro if (mci->mci_out != NULL) 281690792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 281764562Sgshapiro (void) close(s); 281864562Sgshapiro errno = save_errno; 281938032Speter return EX_TEMPFAIL; 282038032Speter } 282190792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 282238032Speter 282390792Sgshapiro /* set {client_flags} */ 282490792Sgshapiro if (ClientSettings[addr.sa.sa_family].d_mflags != NULL) 282590792Sgshapiro { 282690792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 282790792Sgshapiro macid("{client_flags}"), 282890792Sgshapiro ClientSettings[addr.sa.sa_family].d_mflags); 282990792Sgshapiro } 283090792Sgshapiro else 283190792Sgshapiro macdefine(&mci->mci_macro, A_PERM, 283290792Sgshapiro macid("{client_flags}"), ""); 283390792Sgshapiro 283490792Sgshapiro /* "add" {client_flags} to bitmap */ 283590792Sgshapiro if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags)) 283690792Sgshapiro { 283790792Sgshapiro /* look for just this one flag */ 283890792Sgshapiro setbitn(D_IFNHELO, d_flags); 283990792Sgshapiro } 284090792Sgshapiro 284164562Sgshapiro /* find out name for Interface through which we connect */ 2842168515Sgshapiro len = sizeof(addr); 284364562Sgshapiro if (getsockname(s, &addr.sa, &len) == 0) 284464562Sgshapiro { 284564562Sgshapiro char *name; 284690792Sgshapiro char family[5]; 284764562Sgshapiro 284890792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 284990792Sgshapiro macid("{if_addr_out}"), anynet_ntoa(&addr)); 285090792Sgshapiro (void) sm_snprintf(family, sizeof(family), "%d", 285190792Sgshapiro addr.sa.sa_family); 285290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 285390792Sgshapiro macid("{if_family_out}"), family); 285464562Sgshapiro 285564562Sgshapiro name = hostnamebyanyaddr(&addr); 285690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 285790792Sgshapiro macid("{if_name_out}"), name); 285864562Sgshapiro if (LogLevel > 11) 285964562Sgshapiro { 286064562Sgshapiro /* log connection information */ 286164562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 286264562Sgshapiro "SMTP outgoing connect on %.40s", name); 286364562Sgshapiro } 286464562Sgshapiro if (bitnset(D_IFNHELO, d_flags)) 286564562Sgshapiro { 286664562Sgshapiro if (name[0] != '[' && strchr(name, '.') != NULL) 286764562Sgshapiro mci->mci_heloname = newstr(name); 286864562Sgshapiro } 286964562Sgshapiro } 287064562Sgshapiro else 287164562Sgshapiro { 287290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 287390792Sgshapiro macid("{if_name_out}"), NULL); 287490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 287590792Sgshapiro macid("{if_addr_out}"), NULL); 287690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 287790792Sgshapiro macid("{if_family_out}"), NULL); 287864562Sgshapiro } 2879132943Sgshapiro 2880132943Sgshapiro /* Use the configured HeloName as appropriate */ 2881132943Sgshapiro if (HeloName != NULL && HeloName[0] != '\0') 2882223067Sgshapiro { 2883223067Sgshapiro SM_FREE_CLR(mci->mci_heloname); 2884132943Sgshapiro mci->mci_heloname = newstr(HeloName); 2885223067Sgshapiro } 2886132943Sgshapiro 288738032Speter mci_setstat(mci, EX_OK, NULL, NULL); 288864562Sgshapiro return EX_OK; 288938032Speter} 289064562Sgshapiro 289164562Sgshapirostatic void 2892141858Sgshapiroconnecttimeout(ignore) 2893141858Sgshapiro int ignore; 289464562Sgshapiro{ 289577349Sgshapiro /* 289677349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 289777349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 289877349Sgshapiro ** DOING. 289977349Sgshapiro */ 290077349Sgshapiro 290164562Sgshapiro errno = ETIMEDOUT; 290264562Sgshapiro longjmp(CtxConnectTimeout, 1); 290364562Sgshapiro} 290490792Sgshapiro/* 290564562Sgshapiro** MAKECONNECTION_DS -- make a connection to a domain socket. 290664562Sgshapiro** 290764562Sgshapiro** Parameters: 290864562Sgshapiro** mux_path -- the path of the socket to connect to. 290964562Sgshapiro** mci -- a pointer to the mail connection information 291064562Sgshapiro** structure to be filled in. 291164562Sgshapiro** 291264562Sgshapiro** Returns: 291364562Sgshapiro** An exit code telling whether the connection could be 291464562Sgshapiro** made and if not why not. 291564562Sgshapiro** 291664562Sgshapiro** Side Effects: 291764562Sgshapiro** none. 291864562Sgshapiro*/ 291964562Sgshapiro 292090792Sgshapiro#if NETUNIX 292190792Sgshapiroint 292290792Sgshapiromakeconnection_ds(mux_path, mci) 292364562Sgshapiro char *mux_path; 292464562Sgshapiro register MCI *mci; 292564562Sgshapiro{ 292664562Sgshapiro int sock; 292764562Sgshapiro int rval, save_errno; 292864562Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK; 292964562Sgshapiro struct sockaddr_un unix_addr; 293064562Sgshapiro 293164562Sgshapiro /* if not safe, don't connect */ 293264562Sgshapiro rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName, 293364562Sgshapiro sff, S_IRUSR|S_IWUSR, NULL); 293464562Sgshapiro 293564562Sgshapiro if (rval != 0) 293664562Sgshapiro { 2937132943Sgshapiro syserr("makeconnection_ds: unsafe domain socket %s", 2938132943Sgshapiro mux_path); 293964562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL); 294064562Sgshapiro errno = rval; 294164562Sgshapiro return EX_TEMPFAIL; 294264562Sgshapiro } 294364562Sgshapiro 294464562Sgshapiro /* prepare address structure */ 2945168515Sgshapiro memset(&unix_addr, '\0', sizeof(unix_addr)); 294664562Sgshapiro unix_addr.sun_family = AF_UNIX; 294764562Sgshapiro 2948168515Sgshapiro if (strlen(mux_path) >= sizeof(unix_addr.sun_path)) 294964562Sgshapiro { 2950132943Sgshapiro syserr("makeconnection_ds: domain socket name %s too long", 2951132943Sgshapiro mux_path); 295290792Sgshapiro 295390792Sgshapiro /* XXX why TEMPFAIL but 5.x.y ? */ 295464562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL); 295564562Sgshapiro errno = ENAMETOOLONG; 295664562Sgshapiro return EX_UNAVAILABLE; 295764562Sgshapiro } 295890792Sgshapiro (void) sm_strlcpy(unix_addr.sun_path, mux_path, 2959168515Sgshapiro sizeof(unix_addr.sun_path)); 296064562Sgshapiro 296164562Sgshapiro /* initialize domain socket */ 296264562Sgshapiro sock = socket(AF_UNIX, SOCK_STREAM, 0); 296364562Sgshapiro if (sock == -1) 296464562Sgshapiro { 296564562Sgshapiro save_errno = errno; 2966132943Sgshapiro syserr("makeconnection_ds: could not create domain socket %s", 2967132943Sgshapiro mux_path); 296864562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 296964562Sgshapiro errno = save_errno; 297064562Sgshapiro return EX_TEMPFAIL; 297164562Sgshapiro } 297264562Sgshapiro 297364562Sgshapiro /* connect to server */ 297464562Sgshapiro if (connect(sock, (struct sockaddr *) &unix_addr, 297564562Sgshapiro sizeof(unix_addr)) == -1) 297664562Sgshapiro { 297764562Sgshapiro save_errno = errno; 297864562Sgshapiro syserr("Could not connect to socket %s", mux_path); 297964562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL); 298064562Sgshapiro (void) close(sock); 298164562Sgshapiro errno = save_errno; 298264562Sgshapiro return EX_TEMPFAIL; 298364562Sgshapiro } 298464562Sgshapiro 298564562Sgshapiro /* connection ok, put it into canonical form */ 298664562Sgshapiro mci->mci_out = NULL; 298790792Sgshapiro if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2988132943Sgshapiro (void *) &sock, SM_IO_WRONLY_B, NULL)) 298990792Sgshapiro == NULL 299090792Sgshapiro || (sock = dup(sock)) < 0 || 299190792Sgshapiro (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 2992132943Sgshapiro (void *) &sock, SM_IO_RDONLY_B, NULL)) 299390792Sgshapiro == NULL) 299464562Sgshapiro { 299564562Sgshapiro save_errno = errno; 299664562Sgshapiro syserr("cannot open SMTP client channel, fd=%d", sock); 299764562Sgshapiro mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL); 299864562Sgshapiro if (mci->mci_out != NULL) 299990792Sgshapiro (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT); 300064562Sgshapiro (void) close(sock); 300164562Sgshapiro errno = save_errno; 300264562Sgshapiro return EX_TEMPFAIL; 300364562Sgshapiro } 300490792Sgshapiro sm_io_automode(mci->mci_out, mci->mci_in); 300564562Sgshapiro 300664562Sgshapiro mci_setstat(mci, EX_OK, NULL, NULL); 300764562Sgshapiro errno = 0; 300864562Sgshapiro return EX_OK; 300964562Sgshapiro} 301090792Sgshapiro#endif /* NETUNIX */ 301190792Sgshapiro/* 301290792Sgshapiro** SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon 301377349Sgshapiro** 301477349Sgshapiro** Parameters: 301590792Sgshapiro** none. 301677349Sgshapiro** 301777349Sgshapiro** Returns: 301877349Sgshapiro** none. 301977349Sgshapiro** 302077349Sgshapiro** Side Effects: 302190792Sgshapiro** closes control socket, exits. 302277349Sgshapiro*/ 302377349Sgshapiro 302490792Sgshapirovoid 302590792Sgshapiroshutdown_daemon() 302677349Sgshapiro{ 302790792Sgshapiro int i; 302890792Sgshapiro char *reason; 302977349Sgshapiro 303090792Sgshapiro sm_allsignals(true); 303190792Sgshapiro 303290792Sgshapiro reason = ShutdownRequest; 303390792Sgshapiro ShutdownRequest = NULL; 303490792Sgshapiro PendingSignal = 0; 303590792Sgshapiro 3036132943Sgshapiro if (LogLevel > 9) 3037132943Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, "stopping daemon, reason=%s", 303890792Sgshapiro reason == NULL ? "implicit call" : reason); 303990792Sgshapiro 304090792Sgshapiro FileName = NULL; 304190792Sgshapiro closecontrolsocket(true); 304290792Sgshapiro#if XLA 304390792Sgshapiro xla_all_end(); 304490792Sgshapiro#endif /* XLA */ 304590792Sgshapiro 304690792Sgshapiro for (i = 0; i < NDaemons; i++) 304790792Sgshapiro { 304890792Sgshapiro if (Daemons[i].d_socket >= 0) 304990792Sgshapiro { 305090792Sgshapiro (void) close(Daemons[i].d_socket); 305190792Sgshapiro Daemons[i].d_socket = -1; 305290792Sgshapiro 3053285303Sgshapiro#if NETUNIX 305490792Sgshapiro /* Remove named sockets */ 305590792Sgshapiro if (Daemons[i].d_addr.sa.sa_family == AF_UNIX) 305690792Sgshapiro { 305790792Sgshapiro int rval; 305890792Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT; 305990792Sgshapiro 306090792Sgshapiro /* if not safe, don't use it */ 306190792Sgshapiro rval = safefile(Daemons[i].d_addr.sunix.sun_path, 306290792Sgshapiro RunAsUid, RunAsGid, 306390792Sgshapiro RunAsUserName, sff, 306490792Sgshapiro S_IRUSR|S_IWUSR, NULL); 306590792Sgshapiro if (rval == 0 && 306690792Sgshapiro unlink(Daemons[i].d_addr.sunix.sun_path) < 0) 306790792Sgshapiro { 306890792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 306990792Sgshapiro "Could not remove daemon %s socket: %s: %s", 307090792Sgshapiro Daemons[i].d_name, 307190792Sgshapiro Daemons[i].d_addr.sunix.sun_path, 307290792Sgshapiro sm_errstring(errno)); 307390792Sgshapiro } 307490792Sgshapiro } 3075285303Sgshapiro#endif /* NETUNIX */ 307690792Sgshapiro } 307790792Sgshapiro } 307890792Sgshapiro 307990792Sgshapiro finis(false, true, EX_OK); 308077349Sgshapiro} 308190792Sgshapiro/* 308277349Sgshapiro** RESTART_DAEMON -- Performs a clean restart of the daemon 308377349Sgshapiro** 308477349Sgshapiro** Parameters: 308577349Sgshapiro** none. 308677349Sgshapiro** 308777349Sgshapiro** Returns: 308877349Sgshapiro** none. 308977349Sgshapiro** 309077349Sgshapiro** Side Effects: 309177349Sgshapiro** restarts the daemon or exits if restart fails. 309277349Sgshapiro*/ 309377349Sgshapiro 309480785Sgshapiro/* Make a non-DFL/IGN signal a noop */ 309580785Sgshapiro#define SM_NOOP_SIGNAL(sig, old) \ 309680785Sgshapirodo \ 309780785Sgshapiro{ \ 309890792Sgshapiro (old) = sm_signal((sig), sm_signal_noop); \ 309980785Sgshapiro if ((old) == SIG_IGN || (old) == SIG_DFL) \ 310090792Sgshapiro (void) sm_signal((sig), (old)); \ 310180785Sgshapiro} while (0) 310280785Sgshapiro 310390792Sgshapirovoid 310477349Sgshapirorestart_daemon() 310577349Sgshapiro{ 310690792Sgshapiro bool drop; 310777349Sgshapiro int save_errno; 310877349Sgshapiro char *reason; 310980785Sgshapiro sigfunc_t ignore, oalrm, ousr1; 311077349Sgshapiro extern int DtableSize; 311177349Sgshapiro 311280785Sgshapiro /* clear the events to turn off SIGALRMs */ 311390792Sgshapiro sm_clear_events(); 311490792Sgshapiro sm_allsignals(true); 311577349Sgshapiro 311677349Sgshapiro reason = RestartRequest; 311777349Sgshapiro RestartRequest = NULL; 311877349Sgshapiro PendingSignal = 0; 311977349Sgshapiro 312077349Sgshapiro if (SaveArgv[0][0] != '/') 312177349Sgshapiro { 312277349Sgshapiro if (LogLevel > 3) 312377349Sgshapiro sm_syslog(LOG_INFO, NOQID, 312477349Sgshapiro "could not restart: need full path"); 312590792Sgshapiro finis(false, true, EX_OSFILE); 312690792Sgshapiro /* NOTREACHED */ 312777349Sgshapiro } 312877349Sgshapiro if (LogLevel > 3) 312977349Sgshapiro sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s", 313077349Sgshapiro SaveArgv[0], 313177349Sgshapiro reason == NULL ? "implicit call" : reason); 313277349Sgshapiro 313390792Sgshapiro closecontrolsocket(true); 313498121Sgshapiro#if SM_CONF_SHM 313598121Sgshapiro cleanup_shm(DaemonPid == getpid()); 313698121Sgshapiro#endif /* SM_CONF_SHM */ 313790792Sgshapiro 3138132943Sgshapiro /* close locked pid file */ 3139132943Sgshapiro close_sendmail_pid(); 3140132943Sgshapiro 314190792Sgshapiro /* 314290792Sgshapiro ** Want to drop to the user who started the process in all cases 314390792Sgshapiro ** *but* when running as "smmsp" for the clientmqueue queue run 314490792Sgshapiro ** daemon. In that case, UseMSP will be true, RunAsUid should not 314590792Sgshapiro ** be root, and RealUid should be either 0 or RunAsUid. 314690792Sgshapiro */ 314790792Sgshapiro 314890792Sgshapiro drop = !(UseMSP && RunAsUid != 0 && 314990792Sgshapiro (RealUid == 0 || RealUid == RunAsUid)); 315090792Sgshapiro 315190792Sgshapiro if (drop_privileges(drop) != EX_OK) 315277349Sgshapiro { 315377349Sgshapiro if (LogLevel > 0) 315477349Sgshapiro sm_syslog(LOG_ALERT, NOQID, 315590792Sgshapiro "could not drop privileges: %s", 315690792Sgshapiro sm_errstring(errno)); 315790792Sgshapiro finis(false, true, EX_OSERR); 315890792Sgshapiro /* NOTREACHED */ 315977349Sgshapiro } 316077349Sgshapiro 3161132943Sgshapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 316277349Sgshapiro 316380785Sgshapiro /* 316480785Sgshapiro ** Need to allow signals before execve() to make them "harmless". 316580785Sgshapiro ** However, the default action can be "terminate", so it isn't 316680785Sgshapiro ** really harmless. Setting signals to IGN will cause them to be 316780785Sgshapiro ** ignored in the new process to, so that isn't a good alternative. 316880785Sgshapiro */ 316980785Sgshapiro 317080785Sgshapiro SM_NOOP_SIGNAL(SIGALRM, oalrm); 317180785Sgshapiro SM_NOOP_SIGNAL(SIGCHLD, ignore); 317280785Sgshapiro SM_NOOP_SIGNAL(SIGHUP, ignore); 317380785Sgshapiro SM_NOOP_SIGNAL(SIGINT, ignore); 317480785Sgshapiro SM_NOOP_SIGNAL(SIGPIPE, ignore); 317580785Sgshapiro SM_NOOP_SIGNAL(SIGTERM, ignore); 317680785Sgshapiro#ifdef SIGUSR1 317780785Sgshapiro SM_NOOP_SIGNAL(SIGUSR1, ousr1); 317880785Sgshapiro#endif /* SIGUSR1 */ 317994334Sgshapiro 318094334Sgshapiro /* Turn back on signals */ 318190792Sgshapiro sm_allsignals(false); 318277349Sgshapiro 318377349Sgshapiro (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron); 318477349Sgshapiro save_errno = errno; 318577349Sgshapiro 318680785Sgshapiro /* block signals again and restore needed signals */ 318790792Sgshapiro sm_allsignals(true); 318880785Sgshapiro 318980785Sgshapiro /* For finis() events */ 319090792Sgshapiro (void) sm_signal(SIGALRM, oalrm); 319180785Sgshapiro 319280785Sgshapiro#ifdef SIGUSR1 319380785Sgshapiro /* For debugging finis() */ 319490792Sgshapiro (void) sm_signal(SIGUSR1, ousr1); 319580785Sgshapiro#endif /* SIGUSR1 */ 319677349Sgshapiro 319777349Sgshapiro errno = save_errno; 319877349Sgshapiro if (LogLevel > 0) 319990792Sgshapiro sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s", 320090792Sgshapiro SaveArgv[0], sm_errstring(errno)); 320190792Sgshapiro finis(false, true, EX_OSFILE); 320290792Sgshapiro /* NOTREACHED */ 320377349Sgshapiro} 320490792Sgshapiro/* 320538032Speter** MYHOSTNAME -- return the name of this host. 320638032Speter** 320738032Speter** Parameters: 320838032Speter** hostbuf -- a place to return the name of this host. 320938032Speter** size -- the size of hostbuf. 321038032Speter** 321138032Speter** Returns: 321238032Speter** A list of aliases for this host. 321338032Speter** 321438032Speter** Side Effects: 321538032Speter** Adds numeric codes to $=w. 321638032Speter*/ 321738032Speter 321838032Speterstruct hostent * 321938032Spetermyhostname(hostbuf, size) 322038032Speter char hostbuf[]; 322138032Speter int size; 322238032Speter{ 322338032Speter register struct hostent *hp; 322438032Speter 322573188Sgshapiro if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0') 322690792Sgshapiro (void) sm_strlcpy(hostbuf, "localhost", size); 322764562Sgshapiro hp = sm_gethostbyname(hostbuf, InetMode); 322890792Sgshapiro#if NETINET && NETINET6 322980785Sgshapiro if (hp == NULL && InetMode == AF_INET6) 323080785Sgshapiro { 323180785Sgshapiro /* 323280785Sgshapiro ** It's possible that this IPv6 enabled machine doesn't 323380785Sgshapiro ** actually have any IPv6 interfaces and, therefore, no 323480785Sgshapiro ** IPv6 addresses. Fall back to AF_INET. 323580785Sgshapiro */ 323680785Sgshapiro 323780785Sgshapiro hp = sm_gethostbyname(hostbuf, AF_INET); 323880785Sgshapiro } 323990792Sgshapiro#endif /* NETINET && NETINET6 */ 324038032Speter if (hp == NULL) 324138032Speter return NULL; 324238032Speter if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 324364562Sgshapiro (void) cleanstrcpy(hostbuf, hp->h_name, size); 324464562Sgshapiro 324590792Sgshapiro#if NETINFO 324664562Sgshapiro if (strchr(hostbuf, '.') == NULL) 324738032Speter { 324864562Sgshapiro char *domainname; 324964562Sgshapiro 325064562Sgshapiro domainname = ni_propval("/locations", NULL, "resolver", 325164562Sgshapiro "domain", '\0'); 325264562Sgshapiro if (domainname != NULL && 325364562Sgshapiro strlen(domainname) + strlen(hostbuf) + 1 < size) 325490792Sgshapiro (void) sm_strlcat2(hostbuf, ".", domainname, size); 325538032Speter } 325690792Sgshapiro#endif /* NETINFO */ 325738032Speter 325838032Speter /* 325938032Speter ** If there is still no dot in the name, try looking for a 326038032Speter ** dotted alias. 326138032Speter */ 326238032Speter 326338032Speter if (strchr(hostbuf, '.') == NULL) 326438032Speter { 326538032Speter char **ha; 326638032Speter 326764562Sgshapiro for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 326838032Speter { 326938032Speter if (strchr(*ha, '.') != NULL) 327038032Speter { 327164562Sgshapiro (void) cleanstrcpy(hostbuf, *ha, size - 1); 327238032Speter hostbuf[size - 1] = '\0'; 327338032Speter break; 327438032Speter } 327538032Speter } 327638032Speter } 327738032Speter 327838032Speter /* 327938032Speter ** If _still_ no dot, wait for a while and try again -- it is 328038032Speter ** possible that some service is starting up. This can result 328138032Speter ** in excessive delays if the system is badly configured, but 328238032Speter ** there really isn't a way around that, particularly given that 328338032Speter ** the config file hasn't been read at this point. 328438032Speter ** All in all, a bit of a mess. 328538032Speter */ 328638032Speter 328738032Speter if (strchr(hostbuf, '.') == NULL && 328890792Sgshapiro !getcanonname(hostbuf, size, true, NULL)) 328938032Speter { 3290182352Sgshapiro sm_syslog(LocalDaemon ? LOG_WARNING : LOG_CRIT, NOQID, 329164562Sgshapiro "My unqualified host name (%s) unknown; sleeping for retry", 329264562Sgshapiro hostbuf); 329338032Speter message("My unqualified host name (%s) unknown; sleeping for retry", 329438032Speter hostbuf); 329564562Sgshapiro (void) sleep(60); 329690792Sgshapiro if (!getcanonname(hostbuf, size, true, NULL)) 329738032Speter { 3298182352Sgshapiro sm_syslog(LocalDaemon ? LOG_WARNING : LOG_ALERT, NOQID, 329964562Sgshapiro "unable to qualify my own domain name (%s) -- using short name", 330064562Sgshapiro hostbuf); 330138032Speter message("WARNING: unable to qualify my own domain name (%s) -- using short name", 330238032Speter hostbuf); 330338032Speter } 330438032Speter } 330564562Sgshapiro return hp; 330638032Speter} 330790792Sgshapiro/* 330838032Speter** ADDRCMP -- compare two host addresses 330938032Speter** 331038032Speter** Parameters: 331138032Speter** hp -- hostent structure for the first address 331238032Speter** ha -- actual first address 331338032Speter** sa -- second address 331438032Speter** 331538032Speter** Returns: 331638032Speter** 0 -- if ha and sa match 331738032Speter** else -- they don't match 331838032Speter*/ 331938032Speter 332064562Sgshapirostatic int 332138032Speteraddrcmp(hp, ha, sa) 332238032Speter struct hostent *hp; 332338032Speter char *ha; 332438032Speter SOCKADDR *sa; 332538032Speter{ 332690792Sgshapiro#if NETINET6 332790792Sgshapiro unsigned char *a; 332890792Sgshapiro#endif /* NETINET6 */ 332964562Sgshapiro 333038032Speter switch (sa->sa.sa_family) 333138032Speter { 333290792Sgshapiro#if NETINET 333338032Speter case AF_INET: 333438032Speter if (hp->h_addrtype == AF_INET) 333564562Sgshapiro return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ); 333638032Speter break; 333790792Sgshapiro#endif /* NETINET */ 333838032Speter 333990792Sgshapiro#if NETINET6 334064562Sgshapiro case AF_INET6: 334190792Sgshapiro a = (unsigned char *) &sa->sin6.sin6_addr; 334264562Sgshapiro 334364562Sgshapiro /* Straight binary comparison */ 334464562Sgshapiro if (hp->h_addrtype == AF_INET6) 334564562Sgshapiro return memcmp(ha, a, IN6ADDRSZ); 334664562Sgshapiro 334764562Sgshapiro /* If IPv4-mapped IPv6 address, compare the IPv4 section */ 334864562Sgshapiro if (hp->h_addrtype == AF_INET && 334964562Sgshapiro IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) 335064562Sgshapiro return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ); 335164562Sgshapiro break; 335290792Sgshapiro#endif /* NETINET6 */ 335338032Speter } 335438032Speter return -1; 335538032Speter} 335690792Sgshapiro/* 335764562Sgshapiro** GETAUTHINFO -- get the real host name associated with a file descriptor 335838032Speter** 335938032Speter** Uses RFC1413 protocol to try to get info from the other end. 336038032Speter** 336138032Speter** Parameters: 336238032Speter** fd -- the descriptor 336390792Sgshapiro** may_be_forged -- an outage that is set to true if the 336438032Speter** forward lookup of RealHostName does not match 336590792Sgshapiro** RealHostAddr; set to false if they do match. 336638032Speter** 336738032Speter** Returns: 336838032Speter** The user@host information associated with this descriptor. 336938032Speter*/ 337038032Speter 337138032Speterstatic jmp_buf CtxAuthTimeout; 337238032Speter 337338032Speterstatic void 3374141858Sgshapiroauthtimeout(ignore) 3375141858Sgshapiro int ignore; 337638032Speter{ 337777349Sgshapiro /* 337877349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 337977349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 338077349Sgshapiro ** DOING. 338177349Sgshapiro */ 338277349Sgshapiro 338377349Sgshapiro errno = ETIMEDOUT; 338438032Speter longjmp(CtxAuthTimeout, 1); 338538032Speter} 338638032Speter 338738032Speterchar * 338838032Spetergetauthinfo(fd, may_be_forged) 338938032Speter int fd; 339038032Speter bool *may_be_forged; 339138032Speter{ 339290792Sgshapiro unsigned short SM_NONVOLATILE port = 0; 339338032Speter SOCKADDR_LEN_T falen; 339438032Speter register char *volatile p = NULL; 339538032Speter SOCKADDR la; 339638032Speter SOCKADDR_LEN_T lalen; 339790792Sgshapiro#ifndef NO_GETSERVBYNAME 339838032Speter register struct servent *sp; 339990792Sgshapiro# if NETINET 340090792Sgshapiro static unsigned short port4 = 0; 340190792Sgshapiro# endif /* NETINET */ 340290792Sgshapiro# if NETINET6 340390792Sgshapiro static unsigned short port6 = 0; 340490792Sgshapiro# endif /* NETINET6 */ 340590792Sgshapiro#endif /* ! NO_GETSERVBYNAME */ 340638032Speter volatile int s; 340738032Speter int i = 0; 340890792Sgshapiro size_t len; 340990792Sgshapiro SM_EVENT *ev; 341038032Speter int nleft; 341138032Speter struct hostent *hp; 341238032Speter char *ostype = NULL; 341338032Speter char **ha; 341438032Speter char ibuf[MAXNAME + 1]; 3415110560Sgshapiro static char hbuf[MAXNAME + MAXAUTHINFO + 11]; 341638032Speter 3417285303Sgshapiro *may_be_forged = true; 3418168515Sgshapiro falen = sizeof(RealHostAddr); 341938032Speter if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 || 342038032Speter falen <= 0 || RealHostAddr.sa.sa_family == 0) 342138032Speter { 342264562Sgshapiro if (i < 0) 342364562Sgshapiro { 342464562Sgshapiro /* 342564562Sgshapiro ** ENOTSOCK is OK: bail on anything else, but reset 342664562Sgshapiro ** errno in this case, so a mis-report doesn't 342764562Sgshapiro ** happen later. 342864562Sgshapiro */ 342990792Sgshapiro 343064562Sgshapiro if (errno != ENOTSOCK) 343164562Sgshapiro return NULL; 343264562Sgshapiro errno = 0; 343364562Sgshapiro } 3434285303Sgshapiro 3435285303Sgshapiro *may_be_forged = false; 3436168515Sgshapiro (void) sm_strlcpyn(hbuf, sizeof(hbuf), 2, RealUserName, 343790792Sgshapiro "@localhost"); 343838032Speter if (tTd(9, 1)) 343990792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 344038032Speter return hbuf; 344138032Speter } 344238032Speter 344338032Speter if (RealHostName == NULL) 344438032Speter { 344538032Speter /* translate that to a host name */ 344638032Speter RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 344738032Speter if (strlen(RealHostName) > MAXNAME) 344890792Sgshapiro RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */ 344938032Speter } 345038032Speter 345138032Speter /* cross check RealHostName with forward DNS lookup */ 3452285303Sgshapiro if (anynet_ntoa(&RealHostAddr)[0] == '[' || 3453285303Sgshapiro RealHostName[0] == '[') 3454285303Sgshapiro *may_be_forged = false; 3455285303Sgshapiro else 345638032Speter { 345780785Sgshapiro int family; 345880785Sgshapiro 345980785Sgshapiro family = RealHostAddr.sa.sa_family; 346090792Sgshapiro#if NETINET6 && NEEDSGETIPNODE 346180785Sgshapiro /* 346280785Sgshapiro ** If RealHostAddr is an IPv6 connection with an 346380785Sgshapiro ** IPv4-mapped address, we need RealHostName's IPv4 346480785Sgshapiro ** address(es) for addrcmp() to compare against 346580785Sgshapiro ** RealHostAddr. 346680785Sgshapiro ** 346780785Sgshapiro ** Actually, we only need to do this for systems 346880785Sgshapiro ** which NEEDSGETIPNODE since the real getipnodebyname() 346980785Sgshapiro ** already does V4MAPPED address via the AI_V4MAPPEDCFG 347080785Sgshapiro ** flag. A better fix to this problem is to add this 347180785Sgshapiro ** functionality to our stub getipnodebyname(). 347280785Sgshapiro */ 347380785Sgshapiro 347480785Sgshapiro if (family == AF_INET6 && 347580785Sgshapiro IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr)) 347680785Sgshapiro family = AF_INET; 347790792Sgshapiro#endif /* NETINET6 && NEEDSGETIPNODE */ 347880785Sgshapiro 347938032Speter /* try to match the reverse against the forward lookup */ 348080785Sgshapiro hp = sm_gethostbyname(RealHostName, family); 3481285303Sgshapiro if (hp != NULL) 3482120256Sgshapiro { 348338032Speter for (ha = hp->h_addr_list; *ha != NULL; ha++) 348490792Sgshapiro { 348538032Speter if (addrcmp(hp, *ha, &RealHostAddr) == 0) 3486285303Sgshapiro { 3487285303Sgshapiro *may_be_forged = false; 348838032Speter break; 3489285303Sgshapiro } 349090792Sgshapiro } 349190792Sgshapiro#if NETINET6 349271345Sgshapiro freehostent(hp); 349371345Sgshapiro hp = NULL; 349490792Sgshapiro#endif /* NETINET6 */ 349538032Speter } 349638032Speter } 349738032Speter 349838032Speter if (TimeOuts.to_ident == 0) 349938032Speter goto noident; 350038032Speter 3501168515Sgshapiro lalen = sizeof(la); 350264562Sgshapiro switch (RealHostAddr.sa.sa_family) 350338032Speter { 350490792Sgshapiro#if NETINET 350564562Sgshapiro case AF_INET: 350664562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 350764562Sgshapiro lalen <= 0 || 350864562Sgshapiro la.sa.sa_family != AF_INET) 350964562Sgshapiro { 351064562Sgshapiro /* no ident info */ 351164562Sgshapiro goto noident; 351264562Sgshapiro } 351364562Sgshapiro port = RealHostAddr.sin.sin_port; 351438032Speter 351564562Sgshapiro /* create ident query */ 3516168515Sgshapiro (void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n", 351764562Sgshapiro ntohs(RealHostAddr.sin.sin_port), 351864562Sgshapiro ntohs(la.sin.sin_port)); 351938032Speter 352064562Sgshapiro /* create local address */ 352164562Sgshapiro la.sin.sin_port = 0; 352238032Speter 352364562Sgshapiro /* create foreign address */ 352490792Sgshapiro# ifdef NO_GETSERVBYNAME 352538032Speter RealHostAddr.sin.sin_port = htons(113); 352690792Sgshapiro# else /* NO_GETSERVBYNAME */ 352790792Sgshapiro 352890792Sgshapiro /* 352990792Sgshapiro ** getservbyname() consumes about 5% of the time 353090792Sgshapiro ** when receiving a small message (almost all of the time 353190792Sgshapiro ** spent in this routine). 353290792Sgshapiro ** Hence we store the port in a static variable 353390792Sgshapiro ** to save this time. 353490792Sgshapiro ** The portnumber shouldn't change very often... 353590792Sgshapiro ** This code makes the assumption that the port number 353690792Sgshapiro ** is not 0. 353790792Sgshapiro */ 353890792Sgshapiro 353990792Sgshapiro if (port4 == 0) 354090792Sgshapiro { 354190792Sgshapiro sp = getservbyname("auth", "tcp"); 354290792Sgshapiro if (sp != NULL) 354390792Sgshapiro port4 = sp->s_port; 354490792Sgshapiro else 354590792Sgshapiro port4 = htons(113); 354690792Sgshapiro } 354790792Sgshapiro RealHostAddr.sin.sin_port = port4; 354864562Sgshapiro break; 354990792Sgshapiro# endif /* NO_GETSERVBYNAME */ 355090792Sgshapiro#endif /* NETINET */ 355138032Speter 355290792Sgshapiro#if NETINET6 355364562Sgshapiro case AF_INET6: 355464562Sgshapiro if (getsockname(fd, &la.sa, &lalen) < 0 || 355564562Sgshapiro lalen <= 0 || 355664562Sgshapiro la.sa.sa_family != AF_INET6) 355764562Sgshapiro { 355864562Sgshapiro /* no ident info */ 355964562Sgshapiro goto noident; 356064562Sgshapiro } 356164562Sgshapiro port = RealHostAddr.sin6.sin6_port; 356264562Sgshapiro 356364562Sgshapiro /* create ident query */ 3564168515Sgshapiro (void) sm_snprintf(ibuf, sizeof(ibuf), "%d,%d\r\n", 356564562Sgshapiro ntohs(RealHostAddr.sin6.sin6_port), 356664562Sgshapiro ntohs(la.sin6.sin6_port)); 356764562Sgshapiro 356864562Sgshapiro /* create local address */ 356964562Sgshapiro la.sin6.sin6_port = 0; 357064562Sgshapiro 357164562Sgshapiro /* create foreign address */ 357290792Sgshapiro# ifdef NO_GETSERVBYNAME 357364562Sgshapiro RealHostAddr.sin6.sin6_port = htons(113); 357490792Sgshapiro# else /* NO_GETSERVBYNAME */ 357590792Sgshapiro if (port6 == 0) 357690792Sgshapiro { 357790792Sgshapiro sp = getservbyname("auth", "tcp"); 357890792Sgshapiro if (sp != NULL) 357990792Sgshapiro port6 = sp->s_port; 358090792Sgshapiro else 358190792Sgshapiro port6 = htons(113); 358290792Sgshapiro } 358390792Sgshapiro RealHostAddr.sin6.sin6_port = port6; 358464562Sgshapiro break; 358590792Sgshapiro# endif /* NO_GETSERVBYNAME */ 358690792Sgshapiro#endif /* NETINET6 */ 358764562Sgshapiro default: 358864562Sgshapiro /* no ident info */ 358964562Sgshapiro goto noident; 359064562Sgshapiro } 359164562Sgshapiro 359238032Speter s = -1; 359338032Speter if (setjmp(CtxAuthTimeout) != 0) 359438032Speter { 359538032Speter if (s >= 0) 359638032Speter (void) close(s); 359738032Speter goto noident; 359838032Speter } 359938032Speter 360038032Speter /* put a timeout around the whole thing */ 360190792Sgshapiro ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0); 360238032Speter 360338032Speter /* connect to foreign IDENT server using same address as SMTP socket */ 360464562Sgshapiro s = socket(la.sa.sa_family, SOCK_STREAM, 0); 360538032Speter if (s < 0) 360638032Speter { 360790792Sgshapiro sm_clrevent(ev); 360838032Speter goto noident; 360938032Speter } 361064562Sgshapiro if (bind(s, &la.sa, lalen) < 0 || 361164562Sgshapiro connect(s, &RealHostAddr.sa, lalen) < 0) 361238032Speter goto closeident; 361338032Speter 361438032Speter if (tTd(9, 10)) 361590792Sgshapiro sm_dprintf("getauthinfo: sent %s", ibuf); 361638032Speter 361738032Speter /* send query */ 361838032Speter if (write(s, ibuf, strlen(ibuf)) < 0) 361938032Speter goto closeident; 362038032Speter 362138032Speter /* get result */ 362238032Speter p = &ibuf[0]; 3623168515Sgshapiro nleft = sizeof(ibuf) - 1; 362438032Speter while ((i = read(s, p, nleft)) > 0) 362538032Speter { 3626125820Sgshapiro char *s; 3627125820Sgshapiro 362838032Speter p += i; 362938032Speter nleft -= i; 363038032Speter *p = '\0'; 3631125820Sgshapiro if ((s = strchr(ibuf, '\n')) != NULL) 3632125820Sgshapiro { 3633125820Sgshapiro if (p > s + 1) 3634125820Sgshapiro { 3635125820Sgshapiro p = s + 1; 3636125820Sgshapiro *p = '\0'; 3637125820Sgshapiro } 363838032Speter break; 3639125820Sgshapiro } 3640125820Sgshapiro if (nleft <= 0) 3641125820Sgshapiro break; 364238032Speter } 364338032Speter (void) close(s); 364490792Sgshapiro sm_clrevent(ev); 364538032Speter if (i < 0 || p == &ibuf[0]) 364638032Speter goto noident; 364738032Speter 3648111823Sgshapiro if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r') 364938032Speter p--; 365038032Speter *++p = '\0'; 365138032Speter 365238032Speter if (tTd(9, 3)) 365390792Sgshapiro sm_dprintf("getauthinfo: got %s\n", ibuf); 365438032Speter 365538032Speter /* parse result */ 365638032Speter p = strchr(ibuf, ':'); 365738032Speter if (p == NULL) 365838032Speter { 365938032Speter /* malformed response */ 366038032Speter goto noident; 366138032Speter } 366238032Speter while (isascii(*++p) && isspace(*p)) 366338032Speter continue; 366490792Sgshapiro if (sm_strncasecmp(p, "userid", 6) != 0) 366538032Speter { 366638032Speter /* presumably an error string */ 366738032Speter goto noident; 366838032Speter } 366938032Speter p += 6; 367038032Speter while (isascii(*p) && isspace(*p)) 367138032Speter p++; 367238032Speter if (*p++ != ':') 367338032Speter { 367438032Speter /* either useridxx or malformed response */ 367538032Speter goto noident; 367638032Speter } 367738032Speter 367838032Speter /* p now points to the OSTYPE field */ 367938032Speter while (isascii(*p) && isspace(*p)) 368038032Speter p++; 368138032Speter ostype = p; 368238032Speter p = strchr(p, ':'); 368338032Speter if (p == NULL) 368438032Speter { 368538032Speter /* malformed response */ 368638032Speter goto noident; 368738032Speter } 368838032Speter else 368938032Speter { 369038032Speter char *charset; 369138032Speter 369238032Speter *p = '\0'; 369338032Speter charset = strchr(ostype, ','); 369438032Speter if (charset != NULL) 369538032Speter *charset = '\0'; 369638032Speter } 369738032Speter 369838032Speter /* 1413 says don't do this -- but it's broken otherwise */ 369938032Speter while (isascii(*++p) && isspace(*p)) 370038032Speter continue; 370138032Speter 370238032Speter /* p now points to the authenticated name -- copy carefully */ 370390792Sgshapiro if (sm_strncasecmp(ostype, "other", 5) == 0 && 370438032Speter (ostype[5] == ' ' || ostype[5] == '\0')) 370538032Speter { 3706168515Sgshapiro (void) sm_strlcpy(hbuf, "IDENT:", sizeof(hbuf)); 3707110560Sgshapiro cleanstrcpy(&hbuf[6], p, MAXAUTHINFO); 370838032Speter } 370938032Speter else 3710110560Sgshapiro cleanstrcpy(hbuf, p, MAXAUTHINFO); 371190792Sgshapiro len = strlen(hbuf); 3712168515Sgshapiro (void) sm_strlcpyn(&hbuf[len], sizeof(hbuf) - len, 2, "@", 371390792Sgshapiro RealHostName == NULL ? "localhost" : RealHostName); 371438032Speter goto postident; 371538032Speter 371638032Spetercloseident: 371738032Speter (void) close(s); 371890792Sgshapiro sm_clrevent(ev); 371938032Speter 372038032Speternoident: 372164562Sgshapiro /* put back the original incoming port */ 372264562Sgshapiro switch (RealHostAddr.sa.sa_family) 372364562Sgshapiro { 372490792Sgshapiro#if NETINET 372564562Sgshapiro case AF_INET: 372664562Sgshapiro if (port > 0) 372764562Sgshapiro RealHostAddr.sin.sin_port = port; 372864562Sgshapiro break; 372990792Sgshapiro#endif /* NETINET */ 373064562Sgshapiro 373190792Sgshapiro#if NETINET6 373264562Sgshapiro case AF_INET6: 373364562Sgshapiro if (port > 0) 373464562Sgshapiro RealHostAddr.sin6.sin6_port = port; 373564562Sgshapiro break; 373690792Sgshapiro#endif /* NETINET6 */ 373764562Sgshapiro } 373864562Sgshapiro 373938032Speter if (RealHostName == NULL) 374038032Speter { 374138032Speter if (tTd(9, 1)) 374290792Sgshapiro sm_dprintf("getauthinfo: NULL\n"); 374338032Speter return NULL; 374438032Speter } 3745168515Sgshapiro (void) sm_strlcpy(hbuf, RealHostName, sizeof(hbuf)); 374638032Speter 374738032Speterpostident: 374890792Sgshapiro#if IP_SRCROUTE 374990792Sgshapiro# ifndef GET_IPOPT_DST 375090792Sgshapiro# define GET_IPOPT_DST(dst) (dst) 375190792Sgshapiro# endif /* ! GET_IPOPT_DST */ 375238032Speter /* 375338032Speter ** Extract IP source routing information. 375438032Speter ** 375538032Speter ** Format of output for a connection from site a through b 375638032Speter ** through c to d: 375738032Speter ** loose: @site-c@site-b:site-a 375838032Speter ** strict: !@site-c@site-b:site-a 375938032Speter ** 376038032Speter ** o - pointer within ipopt_list structure. 376138032Speter ** q - pointer within ls/ss rr route data 376238032Speter ** p - pointer to hbuf 376338032Speter */ 376438032Speter 376538032Speter if (RealHostAddr.sa.sa_family == AF_INET) 376638032Speter { 376738032Speter SOCKOPT_LEN_T ipoptlen; 376838032Speter int j; 376990792Sgshapiro unsigned char *q; 377090792Sgshapiro unsigned char *o; 377138032Speter int l; 377264562Sgshapiro struct IPOPTION ipopt; 377338032Speter 3774168515Sgshapiro ipoptlen = sizeof(ipopt); 377538032Speter if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, 377638032Speter (char *) &ipopt, &ipoptlen) < 0) 377738032Speter goto noipsr; 377838032Speter if (ipoptlen == 0) 377938032Speter goto noipsr; 378090792Sgshapiro o = (unsigned char *) ipopt.IP_LIST; 378190792Sgshapiro while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen) 378238032Speter { 378338032Speter switch (*o) 378438032Speter { 378564562Sgshapiro case IPOPT_EOL: 378638032Speter o = NULL; 378738032Speter break; 378838032Speter 378938032Speter case IPOPT_NOP: 379038032Speter o++; 379138032Speter break; 379238032Speter 379338032Speter case IPOPT_SSRR: 379438032Speter case IPOPT_LSRR: 379538032Speter /* 379638032Speter ** Source routing. 379738032Speter ** o[0] is the option type (loose/strict). 379838032Speter ** o[1] is the length of this option, 379938032Speter ** including option type and 380038032Speter ** length. 380138032Speter ** o[2] is the pointer into the route 380238032Speter ** data. 380338032Speter ** o[3] begins the route data. 380438032Speter */ 380538032Speter 380638032Speter p = &hbuf[strlen(hbuf)]; 3807168515Sgshapiro l = sizeof(hbuf) - (hbuf - p) - 6; 380890792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), 380990792Sgshapiro " [%s@%.*s", 381090792Sgshapiro *o == IPOPT_SSRR ? "!" : "", 381190792Sgshapiro l > 240 ? 120 : l / 2, 381290792Sgshapiro inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST))); 381338032Speter i = strlen(p); 381438032Speter p += i; 381538032Speter l -= strlen(p); 381638032Speter 381738032Speter j = o[1] / sizeof(struct in_addr) - 1; 381838032Speter 381938032Speter /* q skips length and router pointer to data */ 382038032Speter q = &o[3]; 382138032Speter for ( ; j >= 0; j--) 382238032Speter { 382364562Sgshapiro struct in_addr addr; 382464562Sgshapiro 382538032Speter memcpy(&addr, q, sizeof(addr)); 382690792Sgshapiro (void) sm_snprintf(p, 382790792Sgshapiro SPACELEFT(hbuf, p), 382890792Sgshapiro "%c%.*s", 382990792Sgshapiro j != 0 ? '@' : ':', 383090792Sgshapiro l > 240 ? 120 : 383190792Sgshapiro j == 0 ? l : l / 2, 383290792Sgshapiro inet_ntoa(addr)); 383338032Speter i = strlen(p); 383438032Speter p += i; 383538032Speter l -= i + 1; 383664562Sgshapiro q += sizeof(struct in_addr); 383738032Speter } 383838032Speter o += o[1]; 383938032Speter break; 384038032Speter 384138032Speter default: 384238032Speter /* Skip over option */ 384338032Speter o += o[1]; 384438032Speter break; 384538032Speter } 384638032Speter } 384790792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]"); 384838032Speter goto postipsr; 384938032Speter } 385038032Speter 385138032Speternoipsr: 385290792Sgshapiro#endif /* IP_SRCROUTE */ 385338032Speter if (RealHostName != NULL && RealHostName[0] != '[') 385438032Speter { 385538032Speter p = &hbuf[strlen(hbuf)]; 385690792Sgshapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]", 385790792Sgshapiro anynet_ntoa(&RealHostAddr)); 385838032Speter } 385938032Speter if (*may_be_forged) 386038032Speter { 386138032Speter p = &hbuf[strlen(hbuf)]; 386290792Sgshapiro (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p)); 386390792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 386490792Sgshapiro macid("{client_resolve}"), "FORGED"); 386538032Speter } 386638032Speter 386790792Sgshapiro#if IP_SRCROUTE 386838032Speterpostipsr: 386990792Sgshapiro#endif /* IP_SRCROUTE */ 387064562Sgshapiro 387164562Sgshapiro /* put back the original incoming port */ 387264562Sgshapiro switch (RealHostAddr.sa.sa_family) 387364562Sgshapiro { 387490792Sgshapiro#if NETINET 387564562Sgshapiro case AF_INET: 387664562Sgshapiro if (port > 0) 387764562Sgshapiro RealHostAddr.sin.sin_port = port; 387864562Sgshapiro break; 387990792Sgshapiro#endif /* NETINET */ 388064562Sgshapiro 388190792Sgshapiro#if NETINET6 388264562Sgshapiro case AF_INET6: 388364562Sgshapiro if (port > 0) 388464562Sgshapiro RealHostAddr.sin6.sin6_port = port; 388564562Sgshapiro break; 388690792Sgshapiro#endif /* NETINET6 */ 388764562Sgshapiro } 388864562Sgshapiro 388990792Sgshapiro if (tTd(9, 1)) 389090792Sgshapiro sm_dprintf("getauthinfo: %s\n", hbuf); 389138032Speter return hbuf; 389238032Speter} 389390792Sgshapiro/* 389438032Speter** HOST_MAP_LOOKUP -- turn a hostname into canonical form 389538032Speter** 389638032Speter** Parameters: 389738032Speter** map -- a pointer to this map. 389838032Speter** name -- the (presumably unqualified) hostname. 389938032Speter** av -- unused -- for compatibility with other mapping 390038032Speter** functions. 390138032Speter** statp -- an exit status (out parameter) -- set to 390238032Speter** EX_TEMPFAIL if the name server is unavailable. 390338032Speter** 390438032Speter** Returns: 390538032Speter** The mapping, if found. 390638032Speter** NULL if no mapping found. 390738032Speter** 390838032Speter** Side Effects: 390938032Speter** Looks up the host specified in hbuf. If it is not 391038032Speter** the canonical name for that host, return the canonical 391138032Speter** name (unless MF_MATCHONLY is set, which will cause the 391238032Speter** status only to be returned). 391338032Speter*/ 391438032Speter 391538032Speterchar * 391638032Speterhost_map_lookup(map, name, av, statp) 391738032Speter MAP *map; 391838032Speter char *name; 391938032Speter char **av; 392038032Speter int *statp; 392138032Speter{ 392238032Speter register struct hostent *hp; 392390792Sgshapiro#if NETINET 392438032Speter struct in_addr in_addr; 392590792Sgshapiro#endif /* NETINET */ 392690792Sgshapiro#if NETINET6 392764562Sgshapiro struct in6_addr in6_addr; 392890792Sgshapiro#endif /* NETINET6 */ 392964562Sgshapiro char *cp, *ans = NULL; 393038032Speter register STAB *s; 393190792Sgshapiro time_t now; 393290792Sgshapiro#if NAMED_BIND 393390792Sgshapiro time_t SM_NONVOLATILE retrans = 0; 393490792Sgshapiro int SM_NONVOLATILE retry = 0; 393590792Sgshapiro#endif /* NAMED_BIND */ 393638032Speter char hbuf[MAXNAME + 1]; 393738032Speter 393838032Speter /* 393938032Speter ** See if we have already looked up this name. If so, just 394090792Sgshapiro ** return it (unless expired). 394138032Speter */ 394238032Speter 394390792Sgshapiro now = curtime(); 394438032Speter s = stab(name, ST_NAMECANON, ST_ENTER); 394590792Sgshapiro if (bitset(NCF_VALID, s->s_namecanon.nc_flags) && 394690792Sgshapiro s->s_namecanon.nc_exp >= now) 394738032Speter { 394838032Speter if (tTd(9, 1)) 394990792Sgshapiro sm_dprintf("host_map_lookup(%s) => CACHE %s\n", 395090792Sgshapiro name, 395190792Sgshapiro s->s_namecanon.nc_cname == NULL 395238032Speter ? "NULL" 395338032Speter : s->s_namecanon.nc_cname); 395438032Speter errno = s->s_namecanon.nc_errno; 395573188Sgshapiro SM_SET_H_ERRNO(s->s_namecanon.nc_herrno); 395638032Speter *statp = s->s_namecanon.nc_stat; 395738032Speter if (*statp == EX_TEMPFAIL) 395838032Speter { 395938032Speter CurEnv->e_status = "4.4.3"; 396038032Speter message("851 %s: Name server timeout", 396138032Speter shortenstring(name, 33)); 396238032Speter } 396338032Speter if (*statp != EX_OK) 396438032Speter return NULL; 396538032Speter if (s->s_namecanon.nc_cname == NULL) 396638032Speter { 3967132943Sgshapiro syserr("host_map_lookup(%s): bogus NULL cache entry, errno=%d, h_errno=%d", 396864562Sgshapiro name, 396964562Sgshapiro s->s_namecanon.nc_errno, 397064562Sgshapiro s->s_namecanon.nc_herrno); 397138032Speter return NULL; 397238032Speter } 397338032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 397438032Speter cp = map_rewrite(map, name, strlen(name), NULL); 397538032Speter else 397638032Speter cp = map_rewrite(map, 397738032Speter s->s_namecanon.nc_cname, 397838032Speter strlen(s->s_namecanon.nc_cname), 397938032Speter av); 398038032Speter return cp; 398138032Speter } 398238032Speter 398338032Speter /* 398438032Speter ** If we are running without a regular network connection (usually 398538032Speter ** dial-on-demand) and we are just queueing, we want to avoid DNS 398638032Speter ** lookups because those could try to connect to a server. 398738032Speter */ 398838032Speter 398964562Sgshapiro if (CurEnv->e_sendmode == SM_DEFER && 399064562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 399138032Speter { 399238032Speter if (tTd(9, 1)) 399390792Sgshapiro sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name); 399438032Speter *statp = EX_TEMPFAIL; 399538032Speter return NULL; 399638032Speter } 399738032Speter 399838032Speter /* 399938032Speter ** If first character is a bracket, then it is an address 400038032Speter ** lookup. Address is copied into a temporary buffer to 400138032Speter ** strip the brackets and to preserve name if address is 400238032Speter ** unknown. 400338032Speter */ 400438032Speter 400564562Sgshapiro if (tTd(9, 1)) 400690792Sgshapiro sm_dprintf("host_map_lookup(%s) => ", name); 400790792Sgshapiro#if NAMED_BIND 400890792Sgshapiro if (map->map_timeout > 0) 400990792Sgshapiro { 401090792Sgshapiro retrans = _res.retrans; 401190792Sgshapiro _res.retrans = map->map_timeout; 401290792Sgshapiro } 401390792Sgshapiro if (map->map_retry > 0) 401490792Sgshapiro { 401590792Sgshapiro retry = _res.retry; 401690792Sgshapiro _res.retry = map->map_retry; 401790792Sgshapiro } 401890792Sgshapiro#endif /* NAMED_BIND */ 401990792Sgshapiro 402090792Sgshapiro /* set default TTL */ 402190792Sgshapiro s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL; 402238032Speter if (*name != '[') 402338032Speter { 402490792Sgshapiro int ttl; 402590792Sgshapiro 4026168515Sgshapiro (void) sm_strlcpy(hbuf, name, sizeof(hbuf)); 4027168515Sgshapiro if (getcanonname(hbuf, sizeof(hbuf) - 1, !HasWildcardMX, &ttl)) 402890792Sgshapiro { 402964562Sgshapiro ans = hbuf; 403090792Sgshapiro if (ttl > 0) 403190792Sgshapiro s->s_namecanon.nc_exp = now + SM_MIN(ttl, 403290792Sgshapiro SM_DEFAULT_TTL); 403390792Sgshapiro } 403464562Sgshapiro } 403564562Sgshapiro else 403664562Sgshapiro { 403764562Sgshapiro if ((cp = strchr(name, ']')) == NULL) 403871345Sgshapiro { 403971345Sgshapiro if (tTd(9, 1)) 404090792Sgshapiro sm_dprintf("FAILED\n"); 404164562Sgshapiro return NULL; 404271345Sgshapiro } 404364562Sgshapiro *cp = '\0'; 404464562Sgshapiro 404564562Sgshapiro hp = NULL; 404690792Sgshapiro#if NETINET 404764562Sgshapiro if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE) 404864562Sgshapiro hp = sm_gethostbyaddr((char *)&in_addr, 404964562Sgshapiro INADDRSZ, AF_INET); 405090792Sgshapiro#endif /* NETINET */ 405190792Sgshapiro#if NETINET6 405264562Sgshapiro if (hp == NULL && 405390792Sgshapiro anynet_pton(AF_INET6, &name[1], &in6_addr) == 1) 405464562Sgshapiro hp = sm_gethostbyaddr((char *)&in6_addr, 405564562Sgshapiro IN6ADDRSZ, AF_INET6); 405690792Sgshapiro#endif /* NETINET6 */ 405764562Sgshapiro *cp = ']'; 405864562Sgshapiro 405964562Sgshapiro if (hp != NULL) 406038032Speter { 406164562Sgshapiro /* found a match -- copy out */ 406290792Sgshapiro ans = denlstring((char *) hp->h_name, true, true); 406390792Sgshapiro#if NETINET6 406490792Sgshapiro if (ans == hp->h_name) 406590792Sgshapiro { 406690792Sgshapiro static char n[MAXNAME + 1]; 406790792Sgshapiro 406890792Sgshapiro /* hp->h_name is about to disappear */ 4069168515Sgshapiro (void) sm_strlcpy(n, ans, sizeof(n)); 407090792Sgshapiro ans = n; 407190792Sgshapiro } 407271345Sgshapiro freehostent(hp); 407371345Sgshapiro hp = NULL; 407490792Sgshapiro#endif /* NETINET6 */ 407538032Speter } 407664562Sgshapiro } 407790792Sgshapiro#if NAMED_BIND 407890792Sgshapiro if (map->map_timeout > 0) 407990792Sgshapiro _res.retrans = retrans; 408090792Sgshapiro if (map->map_retry > 0) 408190792Sgshapiro _res.retry = retry; 408290792Sgshapiro#endif /* NAMED_BIND */ 408338032Speter 408464562Sgshapiro s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 408538032Speter 408664562Sgshapiro /* Found an answer */ 408764562Sgshapiro if (ans != NULL) 408864562Sgshapiro { 408964562Sgshapiro s->s_namecanon.nc_stat = *statp = EX_OK; 409090792Sgshapiro if (s->s_namecanon.nc_cname != NULL) 409190792Sgshapiro sm_free(s->s_namecanon.nc_cname); 409290792Sgshapiro s->s_namecanon.nc_cname = sm_strdup_x(ans); 409364562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 409464562Sgshapiro cp = map_rewrite(map, name, strlen(name), NULL); 409564562Sgshapiro else 409664562Sgshapiro cp = map_rewrite(map, ans, strlen(ans), av); 409771345Sgshapiro if (tTd(9, 1)) 409890792Sgshapiro sm_dprintf("FOUND %s\n", ans); 409964562Sgshapiro return cp; 410038032Speter } 410138032Speter 410264562Sgshapiro 410364562Sgshapiro /* No match found */ 410438032Speter s->s_namecanon.nc_errno = errno; 410590792Sgshapiro#if NAMED_BIND 410638032Speter s->s_namecanon.nc_herrno = h_errno; 410764562Sgshapiro if (tTd(9, 1)) 410890792Sgshapiro sm_dprintf("FAIL (%d)\n", h_errno); 410964562Sgshapiro switch (h_errno) 411038032Speter { 411164562Sgshapiro case TRY_AGAIN: 411264562Sgshapiro if (UseNameServer) 411364562Sgshapiro { 411464562Sgshapiro CurEnv->e_status = "4.4.3"; 411564562Sgshapiro message("851 %s: Name server timeout", 411664562Sgshapiro shortenstring(name, 33)); 411764562Sgshapiro } 411864562Sgshapiro *statp = EX_TEMPFAIL; 411964562Sgshapiro break; 412064562Sgshapiro 412164562Sgshapiro case HOST_NOT_FOUND: 412264562Sgshapiro case NO_DATA: 412364562Sgshapiro *statp = EX_NOHOST; 412464562Sgshapiro break; 412564562Sgshapiro 412664562Sgshapiro case NO_RECOVERY: 412764562Sgshapiro *statp = EX_SOFTWARE; 412864562Sgshapiro break; 412964562Sgshapiro 413064562Sgshapiro default: 413164562Sgshapiro *statp = EX_UNAVAILABLE; 413264562Sgshapiro break; 413338032Speter } 413490792Sgshapiro#else /* NAMED_BIND */ 413564562Sgshapiro if (tTd(9, 1)) 413690792Sgshapiro sm_dprintf("FAIL\n"); 413764562Sgshapiro *statp = EX_NOHOST; 413890792Sgshapiro#endif /* NAMED_BIND */ 413964562Sgshapiro s->s_namecanon.nc_stat = *statp; 414064562Sgshapiro return NULL; 414138032Speter} 414238032Speter/* 414390792Sgshapiro** HOST_MAP_INIT -- initialize host class structures 414438032Speter** 414538032Speter** Parameters: 414690792Sgshapiro** map -- a pointer to this map. 414790792Sgshapiro** args -- argument string. 414838032Speter** 414938032Speter** Returns: 415090792Sgshapiro** true. 415138032Speter*/ 415238032Speter 415338032Speterbool 415438032Speterhost_map_init(map, args) 415538032Speter MAP *map; 415638032Speter char *args; 415738032Speter{ 415838032Speter register char *p = args; 415938032Speter 416038032Speter for (;;) 416138032Speter { 416238032Speter while (isascii(*p) && isspace(*p)) 416338032Speter p++; 416438032Speter if (*p != '-') 416538032Speter break; 416638032Speter switch (*++p) 416738032Speter { 416838032Speter case 'a': 416938032Speter map->map_app = ++p; 417038032Speter break; 417138032Speter 417238032Speter case 'T': 417338032Speter map->map_tapp = ++p; 417438032Speter break; 417538032Speter 417638032Speter case 'm': 417738032Speter map->map_mflags |= MF_MATCHONLY; 417838032Speter break; 417938032Speter 418038032Speter case 't': 418138032Speter map->map_mflags |= MF_NODEFER; 418238032Speter break; 418364562Sgshapiro 418464562Sgshapiro case 'S': /* only for consistency */ 418564562Sgshapiro map->map_spacesub = *++p; 418664562Sgshapiro break; 418764562Sgshapiro 418864562Sgshapiro case 'D': 418964562Sgshapiro map->map_mflags |= MF_DEFER; 419064562Sgshapiro break; 419190792Sgshapiro 419290792Sgshapiro case 'd': 419390792Sgshapiro { 419490792Sgshapiro char *h; 419590792Sgshapiro 419690792Sgshapiro while (isascii(*++p) && isspace(*p)) 419790792Sgshapiro continue; 419890792Sgshapiro h = strchr(p, ' '); 419990792Sgshapiro if (h != NULL) 420090792Sgshapiro *h = '\0'; 420190792Sgshapiro map->map_timeout = convtime(p, 's'); 420290792Sgshapiro if (h != NULL) 420390792Sgshapiro *h = ' '; 420490792Sgshapiro } 420590792Sgshapiro break; 420690792Sgshapiro 420790792Sgshapiro case 'r': 420890792Sgshapiro while (isascii(*++p) && isspace(*p)) 420990792Sgshapiro continue; 421090792Sgshapiro map->map_retry = atoi(p); 421190792Sgshapiro break; 421238032Speter } 421338032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 421438032Speter p++; 421538032Speter if (*p != '\0') 421638032Speter *p++ = '\0'; 421738032Speter } 421838032Speter if (map->map_app != NULL) 421938032Speter map->map_app = newstr(map->map_app); 422038032Speter if (map->map_tapp != NULL) 422138032Speter map->map_tapp = newstr(map->map_tapp); 422290792Sgshapiro return true; 422338032Speter} 422490792Sgshapiro 422564562Sgshapiro#if NETINET6 422664562Sgshapiro/* 422764562Sgshapiro** ANYNET_NTOP -- convert an IPv6 network address to printable form. 422864562Sgshapiro** 422964562Sgshapiro** Parameters: 423064562Sgshapiro** s6a -- a pointer to an in6_addr structure. 423164562Sgshapiro** dst -- buffer to store result in 423264562Sgshapiro** dst_len -- size of dst buffer 423364562Sgshapiro** 423464562Sgshapiro** Returns: 423564562Sgshapiro** A printable version of that structure. 423664562Sgshapiro*/ 423790792Sgshapiro 423864562Sgshapirochar * 423964562Sgshapiroanynet_ntop(s6a, dst, dst_len) 424064562Sgshapiro struct in6_addr *s6a; 424164562Sgshapiro char *dst; 424264562Sgshapiro size_t dst_len; 424364562Sgshapiro{ 424464562Sgshapiro register char *ap; 424564562Sgshapiro 424664562Sgshapiro if (IN6_IS_ADDR_V4MAPPED(s6a)) 424764562Sgshapiro ap = (char *) inet_ntop(AF_INET, 424864562Sgshapiro &s6a->s6_addr[IN6ADDRSZ - INADDRSZ], 424964562Sgshapiro dst, dst_len); 425064562Sgshapiro else 425190792Sgshapiro { 425290792Sgshapiro char *d; 425390792Sgshapiro size_t sz; 425490792Sgshapiro 425590792Sgshapiro /* Save pointer to beginning of string */ 425690792Sgshapiro d = dst; 425790792Sgshapiro 425890792Sgshapiro /* Add IPv6: protocol tag */ 425990792Sgshapiro sz = sm_strlcpy(dst, "IPv6:", dst_len); 426090792Sgshapiro if (sz >= dst_len) 426190792Sgshapiro return NULL; 426290792Sgshapiro dst += sz; 426390792Sgshapiro dst_len -= sz; 4264285303Sgshapiro if (UseCompressedIPv6Addresses) 4265285303Sgshapiro ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len); 4266285303Sgshapiro else 4267285303Sgshapiro ap = sm_inet6_ntop(s6a, dst, dst_len); 426890792Sgshapiro /* Restore pointer to beginning of string */ 426990792Sgshapiro if (ap != NULL) 427090792Sgshapiro ap = d; 427190792Sgshapiro } 427264562Sgshapiro return ap; 427364562Sgshapiro} 427490792Sgshapiro 427590792Sgshapiro/* 427690792Sgshapiro** ANYNET_PTON -- convert printed form to network address. 427790792Sgshapiro** 427890792Sgshapiro** Wrapper for inet_pton() which handles IPv6: labels. 427990792Sgshapiro** 428090792Sgshapiro** Parameters: 428190792Sgshapiro** family -- address family 428290792Sgshapiro** src -- string 428390792Sgshapiro** dst -- destination address structure 428490792Sgshapiro** 428590792Sgshapiro** Returns: 428690792Sgshapiro** 1 if the address was valid 428790792Sgshapiro** 0 if the address wasn't parseable 428890792Sgshapiro** -1 if error 428990792Sgshapiro*/ 429090792Sgshapiro 429190792Sgshapiroint 429290792Sgshapiroanynet_pton(family, src, dst) 429390792Sgshapiro int family; 429490792Sgshapiro const char *src; 429590792Sgshapiro void *dst; 429690792Sgshapiro{ 429790792Sgshapiro if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0) 429890792Sgshapiro src += 5; 429990792Sgshapiro return inet_pton(family, src, dst); 430090792Sgshapiro} 430164562Sgshapiro#endif /* NETINET6 */ 430290792Sgshapiro/* 430338032Speter** ANYNET_NTOA -- convert a network address to printable form. 430438032Speter** 430538032Speter** Parameters: 430638032Speter** sap -- a pointer to a sockaddr structure. 430738032Speter** 430838032Speter** Returns: 430938032Speter** A printable version of that sockaddr. 431038032Speter*/ 431138032Speter 431238032Speter#ifdef USE_SOCK_STREAM 431338032Speter 431464562Sgshapiro# if NETLINK 431564562Sgshapiro# include <net/if_dl.h> 431664562Sgshapiro# endif /* NETLINK */ 431738032Speter 431838032Speterchar * 431938032Speteranynet_ntoa(sap) 432038032Speter register SOCKADDR *sap; 432138032Speter{ 432238032Speter register char *bp; 432338032Speter register char *ap; 432438032Speter int l; 432538032Speter static char buf[100]; 432638032Speter 432738032Speter /* check for null/zero family */ 432838032Speter if (sap == NULL) 432938032Speter return "NULLADDR"; 433038032Speter if (sap->sa.sa_family == 0) 433138032Speter return "0"; 433238032Speter 433338032Speter switch (sap->sa.sa_family) 433438032Speter { 433564562Sgshapiro# if NETUNIX 433638032Speter case AF_UNIX: 433764562Sgshapiro if (sap->sunix.sun_path[0] != '\0') 4338168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[UNIX: %.64s]", 433990792Sgshapiro sap->sunix.sun_path); 434064562Sgshapiro else 4341168515Sgshapiro (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof(buf)); 434238032Speter return buf; 434364562Sgshapiro# endif /* NETUNIX */ 434438032Speter 434564562Sgshapiro# if NETINET 434638032Speter case AF_INET: 434764562Sgshapiro return (char *) inet_ntoa(sap->sin.sin_addr); 434864562Sgshapiro# endif /* NETINET */ 434938032Speter 435064562Sgshapiro# if NETINET6 435164562Sgshapiro case AF_INET6: 4352168515Sgshapiro ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof(buf)); 435364562Sgshapiro if (ap != NULL) 435464562Sgshapiro return ap; 435564562Sgshapiro break; 435664562Sgshapiro# endif /* NETINET6 */ 435764562Sgshapiro 435864562Sgshapiro# if NETLINK 435938032Speter case AF_LINK: 4360168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[LINK: %s]", 436190792Sgshapiro link_ntoa((struct sockaddr_dl *) &sap->sa)); 436238032Speter return buf; 436364562Sgshapiro# endif /* NETLINK */ 436438032Speter default: 436538032Speter /* this case is needed when nothing is #defined */ 436638032Speter /* in order to keep the switch syntactically correct */ 436738032Speter break; 436838032Speter } 436938032Speter 437038032Speter /* unknown family -- just dump bytes */ 4371168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Family %d: ", sap->sa.sa_family); 437238032Speter bp = &buf[strlen(buf)]; 437338032Speter ap = sap->sa.sa_data; 4374168515Sgshapiro for (l = sizeof(sap->sa.sa_data); --l >= 0; ) 437538032Speter { 437690792Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:", 437790792Sgshapiro *ap++ & 0377); 437838032Speter bp += 3; 437938032Speter } 438038032Speter *--bp = '\0'; 438138032Speter return buf; 438238032Speter} 438390792Sgshapiro/* 438438032Speter** HOSTNAMEBYANYADDR -- return name of host based on address 438538032Speter** 438638032Speter** Parameters: 438738032Speter** sap -- SOCKADDR pointer 438838032Speter** 438938032Speter** Returns: 439038032Speter** text representation of host name. 439138032Speter** 439238032Speter** Side Effects: 439338032Speter** none. 439438032Speter*/ 439538032Speter 439638032Speterchar * 439738032Speterhostnamebyanyaddr(sap) 439838032Speter register SOCKADDR *sap; 439938032Speter{ 440038032Speter register struct hostent *hp; 440164562Sgshapiro# if NAMED_BIND 440238032Speter int saveretry; 440364562Sgshapiro# endif /* NAMED_BIND */ 440464562Sgshapiro# if NETINET6 440564562Sgshapiro struct in6_addr in6_addr; 440664562Sgshapiro# endif /* NETINET6 */ 440738032Speter 440864562Sgshapiro# if NAMED_BIND 440938032Speter /* shorten name server timeout to avoid higher level timeouts */ 441038032Speter saveretry = _res.retry; 441164562Sgshapiro if (_res.retry * _res.retrans > 20) 441264562Sgshapiro _res.retry = 20 / _res.retrans; 4413244833Sgshapiro if (_res.retry == 0) 4414244833Sgshapiro _res.retry = 1; 441564562Sgshapiro# endif /* NAMED_BIND */ 441638032Speter 441738032Speter switch (sap->sa.sa_family) 441838032Speter { 441964562Sgshapiro# if NETINET 442038032Speter case AF_INET: 442138032Speter hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr, 442290792Sgshapiro INADDRSZ, AF_INET); 442338032Speter break; 442464562Sgshapiro# endif /* NETINET */ 442538032Speter 442664562Sgshapiro# if NETINET6 442764562Sgshapiro case AF_INET6: 442864562Sgshapiro hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr, 442990792Sgshapiro IN6ADDRSZ, AF_INET6); 443064562Sgshapiro break; 443164562Sgshapiro# endif /* NETINET6 */ 443264562Sgshapiro 443364562Sgshapiro# if NETISO 443438032Speter case AF_ISO: 443538032Speter hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr, 4436168515Sgshapiro sizeof(sap->siso.siso_addr), AF_ISO); 443738032Speter break; 443864562Sgshapiro# endif /* NETISO */ 443938032Speter 444064562Sgshapiro# if NETUNIX 444138032Speter case AF_UNIX: 444238032Speter hp = NULL; 444338032Speter break; 444464562Sgshapiro# endif /* NETUNIX */ 444538032Speter 444638032Speter default: 4447168515Sgshapiro hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof(sap->sa.sa_data), 444890792Sgshapiro sap->sa.sa_family); 444938032Speter break; 445038032Speter } 445138032Speter 445264562Sgshapiro# if NAMED_BIND 445338032Speter _res.retry = saveretry; 445464562Sgshapiro# endif /* NAMED_BIND */ 445538032Speter 445664562Sgshapiro# if NETINET || NETINET6 445764562Sgshapiro if (hp != NULL && hp->h_name[0] != '[' 445864562Sgshapiro# if NETINET6 445964562Sgshapiro && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1 446064562Sgshapiro# endif /* NETINET6 */ 446164562Sgshapiro# if NETINET 446264562Sgshapiro && inet_addr(hp->h_name) == INADDR_NONE 446364562Sgshapiro# endif /* NETINET */ 446464562Sgshapiro ) 446571345Sgshapiro { 446671345Sgshapiro char *name; 446771345Sgshapiro 446890792Sgshapiro name = denlstring((char *) hp->h_name, true, true); 446990792Sgshapiro# if NETINET6 447071345Sgshapiro if (name == hp->h_name) 447171345Sgshapiro { 447271345Sgshapiro static char n[MAXNAME + 1]; 447371345Sgshapiro 447471345Sgshapiro /* Copy the string, hp->h_name is about to disappear */ 4475168515Sgshapiro (void) sm_strlcpy(n, name, sizeof(n)); 447671345Sgshapiro name = n; 447771345Sgshapiro } 447871345Sgshapiro freehostent(hp); 447990792Sgshapiro# endif /* NETINET6 */ 448071345Sgshapiro return name; 448171345Sgshapiro } 448264562Sgshapiro# endif /* NETINET || NETINET6 */ 448371345Sgshapiro 448490792Sgshapiro# if NETINET6 448571345Sgshapiro if (hp != NULL) 448671345Sgshapiro { 448771345Sgshapiro freehostent(hp); 448871345Sgshapiro hp = NULL; 448971345Sgshapiro } 449090792Sgshapiro# endif /* NETINET6 */ 449171345Sgshapiro 449264562Sgshapiro# if NETUNIX 449364562Sgshapiro if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0') 449438032Speter return "localhost"; 449564562Sgshapiro# endif /* NETUNIX */ 449638032Speter { 449738032Speter static char buf[203]; 449838032Speter 4499168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "[%.200s]", 450090792Sgshapiro anynet_ntoa(sap)); 450138032Speter return buf; 450238032Speter } 450338032Speter} 450464562Sgshapiro#endif /* USE_SOCK_STREAM */ 4505